What happened / 发生了什么
当对话历史中包含 function call(工具调用)时,ContextTruncator.fix_messages() 方法在截断消息时可能破坏 assistant(tool_calls) 和 tool response 的配对关系,导致 Gemini API 返回 400 错误。
根本原因分析:
astrbot/core/agent/context/truncator.py 的 fix_messages() 方法(第7-20行)只进行了单向检查:
- ✅ 检查
tool 消息前面是否有足够的消息
- ❌ 没有检查 包含
tool_calls 的 assistant 消息后面是否紧跟对应的 tool response
根据 OpenAI Chat Completions API 规范(Gemini 也遵循此规范),function call 必须紧跟 tool response。当截断发生在 assistant(tool_calls) 和 tool 之间时,会产生非法的消息序列,导致 API 拒绝请求。
Reproduce / 如何复现?
- 使用 Gemini 作为 LLM 提供者
- 在对话中触发工具调用(如使用 memes 插件、web-searcher 等)
- 继续对话直到触发上下文截断(通过插件裁剪历史记录,或达到 token 限制触发压缩)
- 如果截断后
assistant(含tool_calls) 消息后面不再紧跟 tool response,下次 LLM 请求会返回 400 错误
AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
- AstrBot 版本: v4.18.2
- 部署方式: Docker
- LLM 提供商: Gemini (通过 OpenAI 兼容接口)
- 消息平台: aiocqhttp (OneBot v11)
OS
Linux
Logs / 报错日志
[2026-02-24 23:28:24.678] [Core] [WARN] [v4.18.2] [runners.tool_loop_agent_runner:249]: Chat Model 额度gemini request error: Error code: 400 - {'error': {'message': 'Please ensure that function call turn comes immediately after a user turn or after a function response turn.', 'type': 'upstream_error', 'param': '', 'code': 400}}
Traceback (most recent call last):
File "/AstrBot/astrbot/core/agent/runners/tool_loop_agent_runner.py", line 224, in _iter_llm_responses_with_fallback
async for resp in self._iter_llm_responses(include_model=idx == 0):
File "/AstrBot/astrbot/core/agent/runners/tool_loop_agent_runner.py", line 201, in _iter_llm_responses
yield await self.provider.text_chat(**payload)
...
openai.BadRequestError: Error code: 400 - {'error': {'message': 'Please ensure that function call turn comes immediately after a user turn or after a function response turn.', 'type': 'upstream_error', 'param': '', 'code': 400}}
消息序列日志(可以看到存在 assistant,user 的序列,如果该 assistant 包含 tool_calls 则格式非法):
[AftCompact] RunCtx.messages -> [32] system,user,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user
Are you willing to submit a PR? / 你愿意提交 PR 吗?
Code of Conduct
What happened / 发生了什么
当对话历史中包含 function call(工具调用)时,
ContextTruncator.fix_messages()方法在截断消息时可能破坏assistant(tool_calls)和toolresponse 的配对关系,导致 Gemini API 返回 400 错误。根本原因分析:
astrbot/core/agent/context/truncator.py的fix_messages()方法(第7-20行)只进行了单向检查:tool消息前面是否有足够的消息tool_calls的assistant消息后面是否紧跟对应的toolresponse根据 OpenAI Chat Completions API 规范(Gemini 也遵循此规范),function call 必须紧跟 tool response。当截断发生在
assistant(tool_calls)和tool之间时,会产生非法的消息序列,导致 API 拒绝请求。Reproduce / 如何复现?
assistant(含tool_calls)消息后面不再紧跟toolresponse,下次 LLM 请求会返回 400 错误AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
OS
Linux
Logs / 报错日志
消息序列日志(可以看到存在
assistant,user的序列,如果该assistant包含tool_calls则格式非法):Are you willing to submit a PR? / 你愿意提交 PR 吗?
Code of Conduct