codecamp

Gemini 思考签名丢了怎么办

思考签名是推理过程的加密表示:stateful 模式由服务端自动管理,stateless 必须原样回传全部 thought 块,删改会让后续轮次失去推理连续性。(核验 2026-11-05,F111)

一、Gemini 思考签名丢了怎么办:问题不是怎么补,而是你为什么要删

报错里出现 missing_thought_signature,第一反应通常是「怎么把签名补回来」。补不回来——它是加密的推理过程,不是你能重建的字段。

真正该问的是:它为什么会丢? 在 Interactions API 里,绝大多数情况不是平台弄丢了,而是你的代码在「整理历史」时把它删掉了。

官方对这件事的表述分两种模式,差别很大(F111):

  • stateful 模式(默认):store: true 加上后续轮次传 previous_interaction_id,服务端替你管全部状态,包括所有思考块与签名。这种模式下你什么都不用做。
  • stateless 模式:自己管理对话历史、每轮回传完整输入输出。这时你必须原样回传所有 thought 块,不得删除或修改。

也就是说,签名问题的根因几乎总是同一个:你在 stateless 模式下做了一次「历史清理」,把看起来没用的思考块裁掉了。

二、missing_thought_signature 审计:最小可运行示例

把一段历史摊开,按模式判断哪些块能删——答案通常是「一个都不能删」。

## EXPECT: stateful:无需处理 | stateless:必须回传 3 个签名块(thought 2、tool_result 1) | 可安全删除 0 个
HISTORY = [
    {"type": "thought", "signature": "sig-1"},
    {"type": "model_output", "text": "……"},
    {"type": "thought", "signature": "sig-2"},
    {"type": "tool_result", "signature": "sig-3"},
]

def audit(history, mode):
    if mode == "stateful":
        return "无需处理", 0
    signed = [block for block in history if block.get("signature")]
    thoughts = [block for block in signed if block["type"] == "thought"]
    tools = [block for block in signed if block["type"] != "thought"]
    msg = f"必须回传 {len(signed)} 个签名块(thought {len(thoughts)}、tool_result {len(tools)})"
    return msg, len(signed)

msg_stateful, _ = audit(HISTORY, "stateful")
msg_stateless, signed_count = audit(HISTORY, "stateless")
assert msg_stateful == "无需处理" and signed_count == 3
print(f"stateful:{msg_stateful} | stateless:{msg_stateless} | 可安全删除 0 个")

注意 tool_result 那个块:它不是思考块,但它带着自己的签名。内置工具(比如 Google Search)的调用与结果块可能各自持有一份签名,stateless 模式下同样要回传(F111)。只盯着 thought 类型去清理,会漏掉这一类。

三、解释与边界:四条不能碰的规则

规则一,stateful 下别自己管历史。 用了 previous_interaction_id 就别再手工拼历史;两套机制同时上,等于把服务端维护的状态和你的本地副本混在一起,行为不可预期(两条路径的差异见 4.1)。

规则二,stateless 下不能删也不能改。 官方用的是「必须原样回传」这种措辞(F111)。摘要替代、截断旧轮、重排顺序,都会让签名对不上。如果上下文实在放不下,正确做法是开一个新的会话,而不是把旧历史压缩后硬塞进去。

规则三,切模型也要带旧签名。 官方明确说,同一会话里换模型时仍要回传上一个模型的思考块,后端会处理兼容性(F111)。很多人以为换模型就该「清空重来」,恰好做反了。

规则四,工具结果签名别丢。 前面代码里的第三个签名块就是例子:它的类型不是 thought,却同样带签名(F111)。所以历史清洗要按「有没有签名」筛,不按「是不是 thought」筛——后者会漏。落到代码审查上只需一句话:任何过滤或切片作用在历史之前,先问它会不会丢掉带签名的块。

签名为什么补不回来。 官方把它描述为推理过程的「加密表示」——加密意味着你既解不开、也造不出。所以遇到签名缺失,唯一的修法是回到上一次完好的历史,而不是想办法重建一个。这决定了排障方向:查历史处理代码,不查模型。

stateful 也不是万能的。 它的前提是 store: true 且后续轮次传 previous_interaction_id(F111)。一旦为了隔离或合规把它关掉,行为就退回 stateless,签名得你自己带——这个切换点见 4.1,两种模式的边界是同一条。

一次典型的签名丢失故障长这样。 上线前几轮都正常,某天用户在长会话里追问第五个问题,开始报 missing_thought_signature。查下来是「历史超过若干轮就截断前几轮」的逻辑——它把带签名的思考块一起截了。修法不是把阈值调大,而是改截断策略:要么整段会话重开,要么只截「无签名的输出块」。这个复盘顺序可以直接套用:先定位错误码,再看历史处理,最后确认当前是哪种模式。(这是从同类问题的共同形态归纳出的典型模式,不是某一次具体工单的记录。)

截断策略怎么改才安全。 如果上下文真的放不下,有三条路,代价从低到高。一是只保留最近若干轮,更早的整轮丢弃——签名只要成段保留就仍然自洽,坏的是「每轮抽掉思考块」这种半保留;二是把旧会话总结成一段纯文本,当作新会话的输入,等于主动放弃旧会话的推理连续性,但不会报错;三是每次追问都新开会话,用检索把需要的片段带回来。三条都不完美,但都比「删几个思考块再硬拼」安全。

签名不进日志,但要留指纹。 签名是长串加密数据,整段打日志既没用又占空间。实用做法是记录块序号、类型与签名前几位,配上会话 id:报错时你能一眼看出「缺的是第几轮的第几个块」,又不用把整段密文搬进日志系统。这一步和脱敏规范不冲突,因为签名本身不含明文,但它确实会撑大日志,按指纹记录更划算。

边界。 本节只讲签名怎么不丢。多轮的两种模式(stateful 与 stateless)怎么选,见 4.1;思考档位与输出上限的取舍,见 9.1;共享 1M 窗口下「历史放不下」的预算问题,见 9.3。

四、预期输出与异常分支

真跑输出:

stateful:无需处理 | stateless:必须回传 3 个签名块(thought 2、tool_result 1) | 可安全删除 0 个

六类分支。报 missing_thought_signature:先查历史里少了哪些签名块,别急着重试——重试同样的残缺历史,结果一样。用摘要替代旧轮次:签名对不上,等于人为制造了这个错误。切模型时清空历史:官方要求带旧签名,清空反而破坏了连续性(F111)。只回传 thought 块、漏了工具结果:内置工具的签名在 call/result 块上,同样要带。stateful 与 stateless 混用:一轮传 id、一轮自己拼历史,模型会看到两份来源不同的状态。把签名当成可选字段:它是推理连续性的前提,不是元数据装饰。

五、判据卡:签名丢了能不能直接重试

该这么做 不该这么做
先用 stateful,让服务端管状态 一边传 id 一边自己拼历史
stateless 下原样回传所有签名块 摘要、截断、重排历史
按「有没有签名」筛,不按类型筛 只保留 thought,丢掉工具结果
换模型时仍回传上一模型的思考块 换模型就清空重来

六、来源与核验

  • https://aistudio.google.com/docs/thinking.md(核验 2026-11-05,F111)
  • https://aistudio.google.com/docs/api-errors.md(核验 2026-11-05,F27)

签名机制与两种模式的边界属于「API 结构」档事实,复核周期三个月,见 1.3。若官方在 stateless 下提供「签名重建」能力,本节的结论要重写——目前没有这种能力,所以只有「不删」这一条路。

七、动手试

  1. 从 HISTORY 里删掉第二个 thought 块,重跑。你会先看到断言失败——代码里钉死了 signed_count == 3。把断言里的 3 改成 2 再跑,输出才会变成「必须回传 2 个签名块」。验收标准:能说清「少一个块,为什么服务端会报 missing_thought_signature」,并指出这里少的是推理链条上的哪一环。
  2. 给 audit 加一条输出:列出被删除块的下标。验收标准:在真实历史里跑一次,看被删的是不是都是「看着没用」的思考块。
  3. 打开你项目里的历史处理代码,搜 thought、signature、truncate。验收标准:如果同时命中,说明这里有一次尚未暴露的清洗;把这段代码与报错日志对一遍,能提前找到下一次线上故障。
Gemini thinking_level 怎么取舍
Gemini 1M 上下文怎么算预算
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }