-
Notifications
You must be signed in to change notification settings - Fork 683
Fix duplicate JSON response output when agent invokes tools #2154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix duplicate JSON response output when agent invokes tools #2154
Conversation
## 问题描述
当 agent 调用 workflow tool 后,工具会同时返回 TEXT 和 JSON 两种格式的响应:
- TEXT 类型:将 JSON 结构序列化成字符串
- JSON 类型:保留原本的 JSON 结构
这导致最终的 tool_response 包含重复的 JSON 内容,例如:
`{"test_tool_output": "測試"}{"test_tool_output": "測試"}`
## 解决方案
在 function_calling.py 和 ReAct.py 中实现了智能去重逻辑:
1. 收集所有 tool 响应并检测是否存在 JSON 类型
2. 当同时存在 TEXT 和 JSON 响应且内容相同时,跳过 TEXT 响应
3. 只保留 JSON 响应,避免重复输出
## 修改文件
- agent-strategies/cot_agent/strategies/function_calling.py
- agent-strategies/cot_agent/strategies/ReAct.py
- agent-strategies/cot_agent/manifest.yaml (版本升级至 0.0.26)
- .gitignore (添加 .claude 和 dify-plugin.exe)
## 影响范围
- 只影响 agent 调用工具时的响应处理
- 不改变 workflow tool 的输出格式
- 保持向后兼容性
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## 问题描述
当 agent 调用 workflow tool 后,工具会同时返回 TEXT 和 JSON 两种格式的响应:
- TEXT 类型:将 JSON 结构序列化成字符串
- JSON 类型:保留原本的 JSON 结构
这导致最终的 tool_response 包含重复的 JSON 内容,例如:
`{"test_tool_output": "測試"}tool response: {"test_tool_output": "測試"}.`
## 解决方案
在 function_calling.py 和 ReAct.py 中实现了字符串截取逻辑:
1. 正常收集所有 tool 响应内容
2. 检测 tool_result 中是否包含 "tool response:" 标记
3. 如果包含该标记,截取该位置之前的内容,去掉后面的重复部分
这种方案适用于任何格式差异的情况,即使前后 JSON 不完全相等也能正确处理。
## 修改文件
- agent-strategies/cot_agent/strategies/function_calling.py
- agent-strategies/cot_agent/strategies/ReAct.py
- agent-strategies/cot_agent/manifest.yaml (版本升级至 0.0.26)
- .gitignore (添加 .claude 和 dify-plugin.exe)
## 影响范围
- 只影响 agent 调用工具时的响应处理
- 不改变 workflow tool 的输出格式
- 保持向后兼容性
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
將基於字符串匹配的去重方式改為基於響應類型檢測, 當工具同時返回 TEXT 和 JSON 響應時自動跳過 TEXT 響應, 避免內容重複問題。 影響範圍: - agent-strategies/cot_agent/strategies/ReAct.py - agent-strategies/cot_agent/strategies/function_calling.py
…m/paul0728/dify-official-plugins into fix/agent-tool-response-duplicate
Summary of ChangesHello @paul0728, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves a bug where agents invoking workflow tools would generate redundant JSON output. The core of the solution involves introducing intelligent deduplication within the agent strategies, specifically for Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request aims to fix an issue with duplicate JSON and TEXT responses from tools. The approach taken is to detect when a JSON response is present and skip the corresponding TEXT response. While the intent is correct, the implementation in both ReAct.py and function_calling.py has a critical flaw: it unconditionally skips all TEXT responses, which will break any tool that only returns text. Additionally, there is some unused code related to this change that should be removed. I've provided comments with suggestions to correct the logic to only skip TEXT responses when a JSON response is actually present, and to point out the dead code. The other changes are stylistic and look good.
| if response.type == ToolInvokeMessage.MessageType.TEXT: | ||
| result += cast(ToolInvokeMessage.TextMessage, response.message).text | ||
| # Skip TEXT response as workflow always returns both TEXT and JSON | ||
| continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unconditionally skipping all TEXT type responses will cause problems for tools that only return a text response, as their output would be completely ignored. The logic should be to skip the TEXT response only if a JSON response is also present. When no JSON response exists, the TEXT response should be processed as before.
if response.type == ToolInvokeMessage.MessageType.TEXT:
if has_json_response:
# Skip TEXT response as a JSON response exists (likely duplicate content)
continue
result += cast(ToolInvokeMessage.TextMessage, response.message).text| tool_invoke_response.type | ||
| == ToolInvokeMessage.MessageType.TEXT | ||
| ): | ||
| tool_result += cast( | ||
| ToolInvokeMessage.TextMessage, | ||
| tool_invoke_response.message, | ||
| ).text | ||
| # Skip TEXT response as workflow always returns both TEXT and JSON | ||
| continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unconditionally skipping all TEXT type responses will cause problems for tools that only return a text response, as their output would be completely ignored. The logic should be to skip the TEXT response only if a JSON response is also present. When no JSON response exists, the TEXT response should be processed as before.
if (
tool_invoke_response.type
== ToolInvokeMessage.MessageType.TEXT
):
if has_json_response:
# Skip TEXT response as a JSON response exists (likely duplicate content)
continue
tool_result += cast(
ToolInvokeMessage.TextMessage,
tool_invoke_response.message,
).text| json_content = None | ||
| if has_json_response: | ||
| # Get the JSON content for comparison | ||
| for r in responses_list: | ||
| if r.type == ToolInvokeMessage.MessageType.JSON: | ||
| json_content = json.dumps( | ||
| cast( | ||
| ToolInvokeMessage.JsonMessage, | ||
| r.message, | ||
| ).json_object, | ||
| ensure_ascii=False, | ||
| ) | ||
| break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| json_content = None | ||
| if has_json_response: | ||
| # Get the JSON content for comparison | ||
| for r in responses_list: | ||
| if r.type == ToolInvokeMessage.MessageType.JSON: | ||
| json_content = json.dumps( | ||
| cast( | ||
| ToolInvokeMessage.JsonMessage, | ||
| r.message, | ||
| ).json_object, | ||
| ensure_ascii=False, | ||
| ) | ||
| break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related Issues or Context
This PR fixes an issue where duplicate JSON content appears in tool responses when an agent invokes a workflow tool.
Problem Background:
When an agent calls a workflow tool, the tool returns responses in both TEXT and JSON formats simultaneously. The TEXT type serializes the JSON structure into a string, while the JSON type preserves the original JSON structure. This results in the final
tool_responsecontaining duplicate content, for example:Solution:
Implement smart deduplication logic in
function_calling.pyandReAct.py. When a JSON-type response is detected, the TEXT-type response is skipped, and only the JSON response is retained.Key Changed Files:
agent-strategies/cot_agent/strategies/function_calling.py: Added response deduplication logicagent-strategies/cot_agent/strategies/ReAct.py: Added response deduplication logicagent-strategies/cot_agent/manifest.yaml: Bumped version to 0.0.26.gitignore: Added.claudeanddify-plugin.exeImpact Scope:
This PR contains Changes to Non-Plugin
This PR contains Changes to Non-LLM Models Plugin
This PR contains Changes to LLM Models Plugin
My Changes Affect Message Flow Handling (System Messages and User→Assistant Turn-Taking)
My Changes Affect Tool Interaction Flow (Multi-Round Usage and Output Handling, for both Agent App and Agent Node)
My Changes Affect Multimodal Input Handling (Images, PDFs, Audio, Video, etc.)
My Changes Affect Multimodal Output Generation (Images, Audio, Video, etc.)
My Changes Affect Structured Output Format (JSON, XML, etc.)
My Changes Affect Token Consumption Metrics
My Changes Affect Other LLM Functionalities (Reasoning Process, Grounding, Prompt Caching, etc.)
Other Changes (Add New Models, Fix Model Parameters etc.)
Version Control (Any Changes to the Plugin Will Require Bumping the Version)
Dify Plugin SDK Version
dify_plugin>=0.3.0,<0.6.0is in requirements.txt (Current:dify_plugin>=0.5.0,<0.6.0)Environment Verification (If Any Code Changes)
Local Deployment Environment
SaaS Environment