什么是额外内容
部分提供商会在回复中附带不透明的状态,并期望在下一轮对话中原样传回。Gemini 3 会使用思维签名(thought signature)为其函数调用签名,如果历史记录回放该调用时缺少签名,请求会被拒绝。Anthropic 要求在继续进行的工具调用(tool use)轮次之前,带上助手轮次的思考块(thinking block),包括其签名。 这类状态没有对应的兼容 OpenAI 的字段,因此 GoModel 将其统一放在一个位置:按厂商(vendor)分键的extra_content 对象。
出现位置
状态放在与提供商的单个部分(part)相对应的单元上。一个工具调用对应一个 Gemini
part,因此每个调用的签名位于该工具调用上。思考块属于整个助手轮次,因此位于消息上。
规则
- 每次转换都会原样传递。 Chat、Responses 和 Anthropic Messages 的入口、流式传输以及助手轮次回显都会携带
extra_content,且不会查看其内容。 - 每个提供商只能看到属于自己的厂商对象。 在请求发往提供商之前,GoModel 会删除所有不属于该提供商的厂商对象。Gemini 签名绝不会发送到 Anthropic 或 OpenAI,在提供商之间迁移的历史记录也不会因外来字段而失败。
- 只有所属的适配器会读写其中的内容。 网关的其他部分都不会解析其内容。
- 原样回显。 不要改写、重排或裁剪该成员。
思维签名保留
Gemini 3 会为其发出的函数调用附加加密的thoughtSignature。下一个请求必须在同一调用上携带相同的签名,否则 Gemini 会返回 HTTP 400 “Function call is missing a thought_signature”。下面是一次通过 Chat Completions 进行的工具调用轮次,仅展示相关字段。
1
客户端提出问题,并提供可用工具
2
Gemini 返回函数调用和签名
GoModel 将请求转换为 Gemini 原生的
generateContent 结构。Gemini 返回一个携带签名的 functionCall 部分。3
GoModel 返回该调用,签名位于 extra_content 下
4
客户端执行工具,并发回完整的历史记录
助手消息按收到的原样追加,因此
extra_content 会自动随之传回。5
GoModel 在对应的 Gemini 部分上回放签名
tool_calls 增量、Responses API 的 function_call 项、Anthropic Messages 的 tool_use 块上;对于纯文本轮次,则出现在助手消息本身上。在 Responses API 中,纯文本轮次的签名位于消息之前的一个 reasoning 输出项上,该输出项本身不含推理文本;将该项回显后,签名会落到助手轮次上。在并行调用批次中,只有第一个调用携带签名。工具调用上扁平的 thought_signature 或 thoughtSignature 同样会被接受,因此基于其他网关构建的客户端也能继续工作。
当 Gemini 3 的历史记录中包含没有任何签名的函数调用时(例如对话始于其他提供商,或客户端丢弃了该成员),GoModel 会发送 Google 文档中规定的占位值,而不是直接暴露 400 错误。只要有真实值,请始终回显真实值;使用占位值会让该轮次失去推理连续性。有关提供商的详细信息,请参阅 Gemini 思维签名。
思考块
Anthropic 的扩展思考(extended thinking)会在助手轮次中返回thinking 和 redacted_thinking 内容块。当该轮次以工具调用结束时,后续请求必须在 tool_use 块之前回放这些块(包括签名)。通过 Anthropic Messages API 时,流程如下:
1
客户端发送包含思考块的历史记录
2
GoModel 将这些块保存在 extra_content.anthropic 下
在内部,历史记录采用 Chat 结构。思考块位于助手消息上,
is_error 位于工具结果上。两者都没有对应的兼容 OpenAI 的字段,因此都放在 anthropic 厂商对象下。只有在结果失败时才会写入 is_error。3
Anthropic 原样收到这些块
当路由到 Anthropic 时,思考块会按发送时的原样放回
tool_use 块之前,is_error 也会恢复到 tool_result 上。其他任何提供商只会收到工具调用和结果文本。返回方向
Anthropic 会为其返回的每个思考块签名,如果后续轮次回放某个思考块时缺少签名,请求会被拒绝:signature_delta 的形式在思考块关闭之前于块内发出,与 Anthropic 的行为完全一致。
来自不签名提供商的推理内容
DeepSeek、Fireworks 等提供商返回的推理文本不带任何认证信息。Anthropic Messages API 仍会将其渲染为thinking 块,并带有 signature: "":该 schema 将此成员标记为必填,严格类型化的客户端会拒绝缺少该成员的块;流式传输时,该块以空签名打开,且不会发送 signature_delta,这与 Anthropic 自身在真实签名到达之前流式发送的结构一致。请原样回显该轮次:该块会像其他块一样回放给对应的提供商。
Anthropic 只接受由其自身签发的签名(缺少签名时报错 signature: Field required,其他情况报错 Invalid `signature` in `thinking` block),因此当此类历史记录被路由到 Anthropic 时,未签名的块会被丢弃,该轮次的其余部分照常发送。
其他协议没有思考块,因此它们会在 extra_content.anthropic.thinking_blocks 下携带相同的数据:在 Chat Completions 中位于助手消息上,在 Responses API 中位于 reasoning 输出项上。流式 Chat 增量会在思考块完成后、任何文本之前携带该值,且该值是累积的:最后收到的那个值包含整个轮次的内容。
reasoning_content 的含义保持不变:它是可读文本,不需要回放。redacted_thinking 块完全没有可读文本,因此只有 extra_content 能携带它。
将助手轮次按收到的原样追加到历史记录中,回放就会自动完成。将该历史记录路由到其他提供商时,该成员会像所有外来厂商对象一样被丢弃,对话在没有它的情况下继续。
在提供商之间迁移历史记录
一段对话可能始于某个提供商,再在另一个提供商上继续。规则很简单:在每条路由、每种协议中,所有不属于目标提供商的厂商对象都会在发送前被移除。
客户端自身的历史记录永远不会被修改。过滤只作用于 GoModel 发往上游的副本。