Hermes Agent 使用 Gemini 3 / Gemini preview 模型时,如果一进入工具调用就报:
Function call is missing a thought_signature in functionCall parts.
This is required for tools to work correctly.
很多人第一反应会去换 API Key、换地区、重试 Google endpoint,甚至怀疑 Gemini 服务当天不稳定。但从 Hermes Agent issue #14488 的修复过程看,这类错误更准确的关键词不是“网络问题”,而是:Gemini 工具调用历史里必须保留 thought_signature,客户端在持久化 tool call 时把它丢了。
这篇文章面向正在搜索这些长尾问题的人:
Gemini Function call is missing a thought_signatureHermes Agent Gemini thought_signature HTTP 400gemini-3-flash-preview default_api terminal thought_signaturegemini-3.1-pro-preview missing thought_signatureGemini tools work correctly missing thought_signature
如果你只是在 Hermes Agent 里配置 Gemini 模型,最重要的结论是:先升级到包含修复的版本;如果仍复现,再检查 tool call 的 extra_content / provider_data 是否在历史消息构建时被保留下来。
典型报错长什么样?
issue 中多个用户都给出了类似错误,常见形式如下:
HTTP 400: Gemini HTTP 400 (INVALID_ARGUMENT):
Function call is missing a thought_signature in functionCall parts.
This is required for tools to work correctly, and missing thought_signature may lead to degraded model performance.
Additional data, function call `default_api:terminal`, position 2.
也可能出现在其他工具名上:
function call `default_api:skill_view`, position 5
function call `default_api:search_files`, position 4
这说明问题触发点通常不是某一个具体工具坏了,而是 Gemini 的工具调用消息在后续请求中缺少了模型要求的签名字段。
一句话结论:这不是普通 API Key 错误
missing thought_signature 和下面这些问题不是同一类:
| 现象 | 更可能的原因 |
| 401 / 403 | API Key、权限、项目、账单或区域限制 |
| 404 model not found | 模型名、endpoint 版本或账号权限不匹配 |
| context length exceeded | 上下文长度超限 |
| missing thought_signature | 工具调用历史消息缺少 Gemini 要求的签名字段 |
所以,反复重试、换代理、清空温度参数,通常不会从根上解决这个错误。
为什么 Gemini 工具调用需要 thought_signature?
Gemini 的部分模型在工具调用流程里,会把内部思考/工具调用相关的签名信息附加到响应中。后续轮次如果把历史 functionCall / tool call 重新发回 Gemini,客户端需要保留这些签名。
可以把它理解成:
- 模型第一次决定调用工具时,Gemini 返回了一个带签名的 function call;
- Hermes Agent 把这个 function call 写进 conversation history;
- 下一轮请求时,Hermes Agent 需要把这个带签名的历史片段回传;
- 如果客户端只保存了工具名和参数,却丢掉了
thought_signature,Gemini 就会认为这段 function call 不完整,于是返回 HTTP 400。
这和 DeepSeek thinking mode 要求回传 reasoning_content / content[].thinking 有相似之处:都不是“用户要看到隐藏思考”,而是客户端协议层必须保留供应商要求的隐藏元数据。
区别是:
- DeepSeek 常见关键词是
reasoning_content、content[].thinking; - Gemini 这里的关键词是
thought_signature、extra_content、provider_data。
Hermes Agent #14488 的根因是什么?
#14488 的讨论里,一位用户给出了非常清楚的根因分析:
> commit 43de1ca8 移除了 _nr_to_assistant_message shim,改用 ToolCall / NormalizedResponse dataclass 上的 duck-typed properties。但 ToolCall 定义里漏掉了 extra_content property,而 extra_content 正是承载 Gemini thought_signature 的地方。
结果就是:
1. Gemini transport 正确把 thought_signature 放进了 provider_data["extra_content"]; 2. 但 agent loop 构建 assistant message 时读取 getattr(tc, "extra_content", None); 3. 因为 ToolCall 没有 extra_content property,读取结果变成 None; 4. 历史消息落盘/拼接时静默丢掉签名; 5. 下一轮工具调用或 fallback 请求中,Gemini 看到 functionCall 缺 thought_signature,返回 HTTP 400。
这类 bug 最麻烦的地方是:第一轮响应可能是正常的,真正爆炸发生在后续工具调用或历史 replay。
官方修复思路:给 ToolCall 补回 extra_content property
issue 里最终给出的修复方向很直接:在 ToolCall dataclass 上补一个 extra_content property,让 agent loop 能从 provider_data 里读到 Gemini 的额外签名内容。
简化后的补丁逻辑如下:
@property
def extra_content(self) -> Optional[Dict[str, Any]]:
"""Gemini extra_content (thought_signature) from provider_data."""
return (self.provider_data or {}).get("extra_content")
维护者随后确认修复已进入 commit f5af6520,并提示用户运行:
hermes update
因此,如果你遇到这个错误,第一优先级不是改 prompt,而是确认当前安装版本是否包含 f5af6520 或后续等效修复。
排查清单:遇到 missing thought_signature 该怎么查?
1. 先确认模型和触发路径
这个问题在 issue 中主要出现在 Gemini preview / 新模型路径上,例如:
gemini-3-flash-previewgemini-3.1-pro-preview- 部分 Gemini 3 preview 工具调用场景
如果你只问普通文本问题不报错,一调用 terminal、search_files、skill_view 等工具才报错,就更符合这个问题的特征。
2. 升级 Hermes Agent
先执行:
hermes update
然后重新打开会话测试。不要只重启旧进程,因为旧代码仍可能使用已经丢签名的历史结构。
3. 用新会话复现,不要只在旧会话里重试
如果旧会话历史里已经缺了 thought_signature,升级后也可能继续被坏历史污染。
建议:
- 新开一个 clean session;
- 选择同一个 Gemini 模型;
- 让它执行一个简单工具调用;
- 看是否仍然报
missing thought_signature。
如果新会话正常,旧会话异常,说明你很可能遇到的是历史消息已经损坏,而不是当前版本仍未修好。
4. 检查 provider_data / extra_content 是否被保留
如果你维护的是 fork、插件、adapter 或自定义 transport,要重点检查:
- Gemini response 是否把
thought_signature存入provider_data["extra_content"]; ToolCall对象是否暴露extra_content;_build_assistant_message或类似 history builder 是否把extra_content写回 assistant message;- fallback、retry、compression、cron、tool replay 路径是否都没有丢字段。
很多协议 bug 都不是主路径出错,而是 fallback / retry / 历史压缩路径漏了一个字段。
5. 不要把它误判为“Gemini 今天不稳定”
issue 中确实有人一开始怀疑 Google/Gemini 服务当天异常,因为前一天还能用、当天突然报错。但后续根因说明更像是客户端升级后消息结构变更导致字段丢失。
如果错误稳定包含:
Function call is missing a thought_signature in functionCall parts
那它就是一个很明确的协议字段问题。
临时规避方案
如果你暂时无法升级到修复版本,可以考虑这些临时方案:
1. 切回不触发该问题的 Gemini 2.5 模型 issue 中有人提到切到 2.5 模型暂时可用。但这只是规避,不是修复。
2. 避免使用工具调用密集任务 如果普通对话可用、工具调用报错,可以临时减少 terminal / search_files / skill_view 等调用。
3. 新建会话 对已经污染的历史,新会话比继续在旧会话里 retry 更可靠。
4. 手动打补丁 如果你维护自定义部署,可以把 extra_content property 补到 ToolCall,但生产环境仍建议跟进官方更新。
给开发者的定位关键词
如果你要在日志或源码里快速定位,可以搜索:
thought_signatureextra_contentprovider_dataToolCall_build_assistant_message_nr_to_assistant_messagefunctionCall partsGeminiAPIError [HTTP 400]
重点不是只看 Gemini transport 是否拿到了签名,而是看签名是否完整穿过:
Gemini response → NormalizedResponse / ToolCall → provider_data → extra_content → assistant history → next request
只要其中任何一步把字段扔了,下一轮就可能炸。
和 DeepAI API 中转站有什么关系?
如果你在多工具环境里管理模型,DeepAI API 中转站更适合解决的是这些基础设施问题:
- 统一 OpenAI-compatible Base URL;
- 统一 API Key 管理;
- 在 Cherry Studio、Cline、Dify、Open WebUI 等支持自定义 OpenAI Compatible API 的工具里集中接入模型;
- 降低多供应商模型切换时的配置成本。
但要说清楚边界:DeepAI API 中转站不能替客户端恢复已经丢失的 Gemini thought_signature。
如果 Hermes Agent 或任何客户端在 history replay 时把供应商字段丢了,中转层最多能看到一个已经不完整的请求。真正要修的是客户端消息构建、工具调用历史保存和 provider adapter。
所以正确组合是:
- 用 DeepAI 这类 OpenAI-compatible API 基础设施统一模型接入;
- 同时确保客户端对 Gemini / DeepSeek / OpenAI Responses API 等供应商特有字段有正确适配;
- 不把“中转站”包装成能修复客户端协议字段丢失的万能方案。
FAQ
missing thought_signature 是不是 API Key 错了?
通常不是。API Key 错误更常见是 401 / 403。missing thought_signature 指向的是 Gemini 工具调用历史消息缺少供应商要求的签名字段。
为什么第一轮能跑,第二轮或工具调用才报错?
因为签名是在模型返回 function call 后需要被保存并在后续请求中回传。第一轮拿到签名没问题,但客户端持久化时丢掉了它,下一轮 replay 才暴露。
只要运行 hermes update 就一定好吗?
如果你升级到了包含 f5af6520 或等效修复的版本,新会话通常应解决。但旧会话历史如果已经缺字段,仍建议新开会话验证。
这个问题和 DeepSeek reasoning_content 是同一个 bug 吗?
不是同一个 bug,但属于同一类协议问题:供应商要求客户端在后续请求里保留某些隐藏元数据。DeepSeek 是 reasoning_content / content[].thinking,Gemini 是 thought_signature。
为什么 retry / fallback 没用?
因为请求体本身缺字段。重试只会重复发送不完整历史,fallback 如果复用同一段坏历史,也会继续失败。
总结
Hermes Agent 的 Gemini Function call is missing a thought_signature 错误,本质上是工具调用历史消息丢失 Gemini thought_signature。在 #14488 中,根因被定位到 ToolCall dataclass 缺少 extra_content property,导致 provider_data["extra_content"] 中的签名没有进入 assistant history。
最实用的处理顺序是:
1. 升级 Hermes Agent,确认包含 f5af6520 或后续修复; 2. 用新会话复现,避免旧历史污染; 3. 检查 Gemini tool call 的 extra_content 是否完整穿过 history builder; 4. 不要把它误判为 API Key、网络或简单模型不可用; 5. 使用 DeepAI API 中转站时,也要清楚它解决的是模型接入与配置统一,不是客户端丢字段的问题。