fix: skills_like 模式下保留原始 completion_text,修复上下文分裂问题#8240
Conversation
Only overwrite tool-call-related fields from the re-query response, preserving the original completion_text and reasoning_content that were already sent to the user.
…ext-divergence fix: skills_like 模式下保留原始 completion_text,修复上下文分裂问题
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In the
skills_likebranch, consider extracting the logic that mergesrequery_respintollm_respinto a small helper (e.g.,_merge_tool_calls(original, requery)), so it’s clearer exactly which fields are intentionally preserved vs. overridden and easier to extend if more tool-related fields are added later. - Double-check whether there are any additional tool-related attributes on
llm_resp(such as IDs, metadata, or error fields) that also need to be synchronized fromrequery_respto avoid future divergence similar totools_call_name/args/ids.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the `skills_like` branch, consider extracting the logic that merges `requery_resp` into `llm_resp` into a small helper (e.g., `_merge_tool_calls(original, requery)`), so it’s clearer exactly which fields are intentionally preserved vs. overridden and easier to extend if more tool-related fields are added later.
- Double-check whether there are any additional tool-related attributes on `llm_resp` (such as IDs, metadata, or error fields) that also need to be synchronized from `requery_resp` to avoid future divergence similar to `tools_call_name/args/ids`.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request refactors the tool re-query logic in tool_loop_agent_runner.py for the skills_like mode by introducing a temporary response variable and updating the primary response object's tool call attributes. Feedback highlights a potential issue where error responses from the re-query might be incorrectly handled as successful assistant responses, leading to incorrect state transitions. Additionally, it was noted that token usage from these re-queries is not currently being tracked, and a suggestion was provided to update the session statistics accordingly.
| if not llm_resp.tools_call_name: | ||
| requery_resp, _ = await self._resolve_tool_exec(llm_resp) | ||
| if not requery_resp.tools_call_name: | ||
| llm_resp = requery_resp |
| requery_resp, _ = await self._resolve_tool_exec(llm_resp) | ||
| if not requery_resp.tools_call_name: |
There was a problem hiding this comment.
在 skills_like 模式下,重新查询(re-query)产生的 token 消耗目前没有被计入 self.stats.token_usage。这会导致代理运行的 token 统计不准确。建议在获取 requery_resp 后,如果它是一个新的响应对象,则累加其 usage,并同步更新会话的 token 使用量。
| requery_resp, _ = await self._resolve_tool_exec(llm_resp) | |
| if not requery_resp.tools_call_name: | |
| requery_resp, _ = await self._resolve_tool_exec(llm_resp) | |
| if requery_resp is not llm_resp and requery_resp.usage: | |
| self.stats.token_usage += requery_resp.usage | |
| if self.req.conversation: | |
| self.req.conversation.token_usage = requery_resp.usage.total | |
| if not requery_resp.tools_call_name: |
修复 #8238
skills_like 模式下,
_resolve_tool_exec()的返回值整体覆盖了llm_resp,导致已发送给用户的completion_text被 re-query 生成的不同文本替换,存入 conversation history 的内容与用户实际收到的不一致。Modifications / 改动点
修改文件:
astrbot/core/agent/runners/tool_loop_agent_runner.py将
_resolve_tool_exec返回后对llm_resp的整体覆盖改为仅替换工具调用相关字段(tools_call_name、tools_call_args、tools_call_ids),保留原始的completion_text和reasoning_content。fallback 路径(re-query 未返回工具调用)逻辑不变。Screenshots or Test Results / 运行截图或测试结果
API 调用记录:
skills_like 开启时,每次工具调用产生 3 次 API 请求:
time: input: 12454 output: 66 ← step() 首次 LLM 调用
time: input: 12481 output: 66 ← _resolve_tool_exec re-query(input 增加 27 token,为注入的 requery instruction)
time: input: 12690 output: 478 ← 工具执行后生成最终回复
改为 full 模式后,同样的操作只产生 2 次:
time: input: 14351 output: 481 ← step() LLM 调用(文本 + 工具调用)
time: input: 14854 output: 474 ← 工具执行后生成最终回复
上下文分裂示例:
用户实际收到(NapCat 发送记录可验证):「我在你的服务器里替你跑一下。」
conversation history 中存储的(后续 LLM 调用的上下文可验证):「好的,我curl一下。」
两段文本来自两次独立的 LLM 调用,同一个 prompt,不同输出。
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Bug Fixes: