docs/technical/gemini-tool-call-thought-signatures.md
Last updated: 2026-07
本文记录 Gemini 3 function calling 的 thought signature 规则,以及 Chatbox 在 Agent Mode / Code Execution 场景下的历史序列化要求。背景问题来自 gemini-3.1-pro-preview 在一次响应中并行生成大量 code_execution 调用,达到 25 次工具调用暂停后,点击继续时 Google API 返回:
Function call is missing a thought_signature in functionCall parts.
Gemini 3 的 function calling 对当前 turn 执行严格 signature 校验。当前 turn 指从最近一条普通 user text message 开始,到后续所有 model functionCall 和 user/tool functionResponse steps。
关键规则:
functionCall part 会带 thoughtSignature,下一次请求必须原样带回。functionCall part 带 thoughtSignature,后续并行 functionCall 没有 signature 是正常行为。functionCall 都会带自己的 signature,后续请求必须累计带回所有 step 的 signature。functionCall 确实没有 signature,例如历史由客户端确定性构造或跨模型迁移,可以使用 Google 文档允许的 dummy signature:skip_thought_signature_validator。并行调用的正确回传形态必须保持为一个 model/assistant 消息后接一个 tool 消息:
assistant/model parts:
FC1 + thoughtSignature
FC2
FC3
tool/user parts:
FR1
FR2
FR3
不能交错成:
assistant/model: FC1 + thoughtSignature
tool/user: FR1
assistant/model: FC2
tool/user: FR2
交错后,FC2 会被 Google 视为新的 step 的第一个 function call;由于它没有 signature,请求会 400。
相关文件:
src/renderer/stores/session/stream-chunk-processor.ts
Message.contentParts。chunk.providerMetadata.google.thoughtSignature。stepIndex(generation step 边界,来自 finish-step chunk);同一 stepIndex 的 tool calls 即同一并行批次。tool-error 且没有先前 tool-call part 时,也要先创建并持久化 tool-call part,再抛出暂停错误。src/shared/services/model-message-converter.ts
Message.contentParts 转成 AI SDK ModelMessage[]。stepIndex 的已完成 tool calls 会合并成一个 assistant message,并跟一个包含所有 tool results 的 tool message。skip_thought_signature_validator。src/renderer/stores/session/agent-harness.ts
model.apiStyle === 'google' 时启用 Google signature 兜底(getModel() 会为内置/自定义 Gemini provider 及 ChatboxAI google 路由模型统一打上 apiStyle)。src/renderer/stores/session/orchestration.ts
src/renderer/components/message-parts/ToolCallPartUI.tsx
tool_call_limit 暂停批次只展示一个继续入口。复现 prompt:
我要测试工具调用次数。请严格按下面要求做,不要合并步骤:
对 1 到 30 这 30 个数字,每个数字单独执行一次代码,每次只输出这一个数字。
必须分成 30 次独立的工具调用,绝对不要用循环,也不要一次输出多个数字。
在 Agent Mode on 并注入真实 Code Execution tools 时,gemini-3.1-pro-preview 一次返回 30 个 code_execution tool calls。实测只有第一个 tool call 带 thoughtSignature,后 29 个没有。这符合 Gemini 并行 function calling 规则。
原问题不是“后 29 个缺 signature”,而是 Chatbox 历史序列化把同一批并行调用拆成了多个 assistant/tool 对,形成:
FC1 + signature, FR1, FC2, FR2, ...
当继续暂停后的请求发给 Google 时,后续 unsigned FC2、FC14 等被视为新 step 的第一个 function call,于是触发 400。
thoughtSignature,不要丢失 providerMetadata。stepIndex(provider generation step 边界)表达同一批并行 tool calls;继续生成时 createInitialState 会从历史最大值 +1 起步,避免新旧批次误合并。assistant: [FC...] 然后 tool: [FR...],禁止 interleave。skip_thought_signature_validator。toolChoice 规避问题;复现和修复都应该走真实 Agent Mode tool path。最小有效验证应该覆盖两层:
skip_thought_signature_validator。单元测试应覆盖:
MessageToolCallPart.providerMetadata。stepIndex,且快结果插队不会拆分批次。stepIndex 的 tool calls 序列化为一个 assistant turn 和一个 matching tool-result turn。skip_thought_signature_validator。这次排查中有几个容易再次踩的坑:
position 4 / position 14 不等于那些原始并行 call 应该有 signature;它通常说明我们把并行组拆成了多个 step。toolChoice、provider 底层参数或模型调用策略。这个问题属于 message history shape 和 provider metadata preservation。