Skip to content

fix: skills_like 模式下保留原始 completion_text,修复上下文分裂问题#8240

Open
EmilyCheoh wants to merge 2 commits into
AstrBotDevs:masterfrom
EmilyCheoh:master
Open

fix: skills_like 模式下保留原始 completion_text,修复上下文分裂问题#8240
EmilyCheoh wants to merge 2 commits into
AstrBotDevs:masterfrom
EmilyCheoh:master

Conversation

@EmilyCheoh
Copy link
Copy Markdown

@EmilyCheoh EmilyCheoh commented May 19, 2026

修复 #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_nametools_call_argstools_call_ids),保留原始的 completion_textreasoning_content。fallback 路径(re-query 未返回工具调用)逻辑不变。

  • This is NOT a breaking change. / 这不是一个破坏性变更。

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.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Bug Fixes:

  • Fix skills_like mode overwriting the original assistant completion with the re-query response, which caused mismatches between sent messages and conversation history.

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,修复上下文分裂问题
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. labels May 19, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • 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.
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`.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a 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 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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

如果 re-query 返回了错误响应(role == "err"),当前逻辑在 fallback 路径下会将其直接赋值给 llm_resp 并继续执行,最终会调用 _complete_with_assistant_response 将代理状态设置为 DONE。这会导致错误被当作正常的助手回复处理,建议在此处增加对 requery_resp.role == "err" 的判断,并按照标准的错误流程处理(例如跳转到错误状态并返回错误响应)。

Comment on lines +819 to +820
requery_resp, _ = await self._resolve_tool_exec(llm_resp)
if not requery_resp.tools_call_name:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

skills_like 模式下,重新查询(re-query)产生的 token 消耗目前没有被计入 self.stats.token_usage。这会导致代理运行的 token 统计不准确。建议在获取 requery_resp 后,如果它是一个新的响应对象,则累加其 usage,并同步更新会话的 token 使用量。

Suggested change
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:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant