Claude Platform Docs
Messages保留思考

思考块的前缀检查

前缀检查比较什么、哪些模型会运行它、请求未通过前缀检查时会发生什么,以及如何处理 400 错误和不返回错误的情况。

每个将思考块发送回具有保留思考的模型的请求都会经过一次 “prefix check”(前缀检查)。如果在 Claude 生成某个块之后,system、tools 或更早的消息发生了更改,前缀检查就会失败。如果位于其他思考块之间的某个思考块被省略或移动,前缀检查也会失败。

未通过前缀检查可能会也可能不会导致 400 错误,这取决于模型,因此请处理两种情况。

前缀检查会影响谁

如果以下任一情况成立,您无需做任何更改:

  • 由 Claude Code、claude.ai 或 Claude Managed Agents 管理您的对话历史。
  • 由 Claude Agent SDK 管理历史,且您提供给 SDK 的系统提示保持不变。
  • 您的代码遵循仅追加集成的三个习惯,并且在传输途中没有任何东西改写其请求。
  • 您没有调用任何具有保留思考的模型。

如果您的请求会经过某个库、代理或网关,请将它发送的内容与您发送的内容进行比较。如果您运行着这样的组件,请参阅库、代理和网关,了解应当原样传递哪些内容。

哪些内容必须保持不变,以及原因

请将您的集成设计为 “append-only”(仅追加)。以下三个习惯可以做到这一点:

  1. 将每个助手轮次完全按照 API 返回的原样发送回去,包括文本为空的思考块。
  2. 为每个对话只构建一次 system 和 tools,并且每次都发送这同一份副本。
  3. 将每次更新放在末尾的一条新消息中,并保持其不变。

每个思考块的推理都恰好针对其之前的内容:system、tools 以及每一条更早的消息。这些内容就是该块的前缀,也正是前缀检查所比较的内容。

前缀检查与 “prompt caching”(提示缓存)类似,不同之处在于:更改会使其后的思考失效,而不仅仅是未命中缓存。

以一个在系统提示中写入当天日期的应用为例。到了午夜,日期发生变化,对话中已有思考的前缀也随之改变。这些思考会失效,下一个请求可能会失败。仅追加的应用会保持系统提示原样不变,并在末尾的一条消息中说明新的日期。

在末尾​添加​更新
systemtools
更改第 2 ⁠轮的​消息
systemtools
更改 system 或 tools
systemtools
您的​消息
思考,有效
已更改或​新增
思考,无效

一次更改只会使已经位于其后的思考失效。位于其之前的思考,以及 Claude 在此之后生成的思考,都保持有效。

如果您的代码更改了系统提示、工具或历史

如果您的代码……应当怎么做
使用日期、模式或指令文件重新构建系统提示停止更改 system。将您自己的指令作为系统消息追加(即 messages 中的一个 role: "system" 条目),并在最新的轮次中说明新的值。对于其他人可以编辑的文本,请改为参阅其他人可以编辑的文本。
添加、移除或改写某个工具,或在 MCP 服务器连接时获得新工具停止更改 tools,并在系统消息中添加或移除工具。
裁剪、折叠或总结较早的轮次,并保持最新的轮次不变让 API 编写摘要,或移除保留的轮次中的思考。

其他原因,例如跳过文本为空的思考块或重建已保存的对话,各有其修复方法:请参阅更改工具或指令而不会导致前缀检查失败。要找出您的原因,请让智能体检查您的代码。

未通过前缀检查时各模型的行为

在 Claude API 和部分云平台上,在未设置 prefix_mismatch_behavior 的情况下,未通过前缀检查的结果取决于模型:

具有保留思考的模型结果
Claude Fable 5.2400 错误
Claude Mythos 5.2400 错误
Claude Mythos 5.1400 错误
Claude Fable 5.1可能出现 400 错误
Claude Opus 5.5可能出现 400 错误
Claude Sonnet 5.5可能出现 400 错误
Claude Haiku 5.5可能出现 400 错误

在表中显示"可能出现 400 错误"的地方,存在两种情况:未通过前缀检查的请求可能收到 400 错误,也可能不返回错误。当不返回错误时,未通过前缀检查的块会到达模型。Claude 会像读取其他任何输入一样读取它们,您需要为它们付费,而 Claude 会基于针对已发生更改的内容所做的推理来工作。

在这些模型上,您可以检查请求会遇到哪种情况,但仍应处理两种情况。

未设置 prefix_mismatch_behavior 的 Message Batches 条目不会收到错误,并且 API 可能会丢弃未通过前缀检查的块。

处理两种情况

要让每个请求都得到同一种结果,请将您的集成设计为仅追加,或设置 prefix_mismatch_behavior。否则,您的代码必须处理两种行为。

出现 400 错误后,在该对话后续的请求中发送 "drop_block" 即可恢复。这是有代价的:请参阅丢弃思考的代价。不要在您的所有对话中都发送它来掩盖错误。

技术细节

前缀检查的工作原理

具有保留思考的模型会在每个思考块的 signature 中记录其前缀的指纹。API 参考将前缀检查称为对话检查,而 400 错误会指出未通过前缀检查的块 is bound to a different conversation。

哪些模型会运行前缀检查

前缀检查在 Claude API 和部分云平台上运行。它会在发往这些模型之一的请求中,检查由具有保留思考的模型生成的思考块。在 Claude API 上,其他模型(例如 Claude Opus 5)不会运行前缀检查,前缀检查也不涵盖它们的块。

什么算作更改

  • 每个块都会与其自身的记录进行比较。API 会将本次请求中某个块之前的内容,与 Claude 生成该块时其签名所记录的内容进行比较。您的上一个请求不起任何作用。前缀检查只关注内容,而不关注会话、ID 或用户。相同的内容出现在新请求或分叉中也能通过前缀检查。
  • 前缀检查比较的是您发送的内容,而不是 Claude 读取的内容。在令牌阈值处进行压缩和上下文编辑只会改变 Claude 读取的内容,因此它们从不算作更改。在阈值压缩块之后,API 只比较从该块开始的消息,以及 system 和 tools。按需压缩有其自身的条件:请参阅保留的思考保持有效的条件。对于通过 URL 发送的文件,以及在 Claude API 上的 MCP 工具列表,API 比较的是它获取到的内容。
  • 您发送的思考必须是一段连续不间断的序列。思考块不会作为内容进行比较。但除第一个之外,您发送的每个思考块都必须与 Claude 生成它时拥有相同的上一个思考块。因此,您可以省略最早的、最新的或全部思考块,但不能省略中间的某一个。

一次更改可能小到只是工具描述中的一个词。更改、插入、移动或删除一条更早的消息都算作更改,无论其角色是什么。在思考块所在的消息中更改其之前的文本也算作更改。

什么不算作更改

以下不算作更改原因
model、effort、max_tokens、tool_choice、metadata、thinking.display 及其他参数只比较 system、tools 和消息
JSON 格式或键的顺序API 比较的是解析后的 JSON,而不是其文本
cache_control 标记它们说明的是缓存位置,而不是 Claude 读取的内容
设置了 defer_loading: true 且尚未被任何内容引用的工具在被引用之前,它不在 Claude 的上下文中

设置 prefix_mismatch_behavior

beta 标头 thinking-binding-controls-2026-08-01 会添加设置 thinking.block_binding.prefix_mismatch_behavior 以及响应中的 input_transformations 数组。

值如果某个块未通过前缀检查
"error"API 以 400 错误拒绝该请求,错误中会指出第一个无效的块
"drop_block"API 丢弃无效的块,请求成功。您无需为这些块付费,但丢弃它们可能会花费更多
未设置,或为 null取决于模型

只要更改仍然存在,未通过前缀检查的块在之后每个发送它们的请求中都保持无效。该设置只作用于携带它的那一个请求。在关闭思考("disabled" 或 "between_tools")的情况下,发送该设置在所有模型上都会导致 400 错误。

以下请求将 prefix_mismatch_behavior 设置为 "drop_block"。在第一个轮次中没有需要发送回去的思考,因此返回的 input_transformations 为空:

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=16000,
    thinking={
        "type": "adaptive",
        "block_binding": {"prefix_mismatch_behavior": "drop_block"},
    },
    messages=[
        {
            "role": "user",
            "content": "What is the greatest common divisor of 1071 and 462?",
        }
    ],
    betas=["thinking-binding-controls-2026-08-01"],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

print(f"Input transformations: {len(response.input_transformations or [])}")

监控生产流量

在未设置 prefix_mismatch_behavior 的情况下,在部分模型上,未通过前缀检查的请求可能不会收到错误。这时未通过前缀检查的思考块会到达模型。要在生产流量中找出这些块,请发送 thinking-binding-controls-2026-08-01 beta 标头,不设置该设置,并记录每个响应的 input_transformations 数组。该标头会添加这个数组,并不会改变模型接收到的内容。

每个这样的块都会在该数组中拥有各自的 thinking_mismatch_allowed 条目。一个条目如下所示:

{
  "input_transformations": [
    {
      "type": "thinking_mismatch_allowed",
      "path": "messages.1.content.0",
      "reason": "prefix_binding_mismatch"
    }
  ]
}

要找出更改,请参阅找出您的代码更改了什么。

检查您遇到哪种情况

在部分模型上,未通过前缀检查的请求可能收到 400 错误,也可能不返回错误。以下测试可以显示某个请求遇到的是哪一种:

  1. 选取一个包含这些模型之一所生成思考块的对话。更改或添加系统提示(system)。该块随后会未通过前缀检查,因为系统提示在 Claude 生成该块之后发生了更改。
  2. 将其发送给同一模型,附带 thinking-binding-controls-2026-08-01 beta 标头,并且不设置 prefix_mismatch_behavior。

响应为以下之一:

  • 一个显示 bound to a different conversation 的 400 错误:该请求收到了 400 错误。
  • 一个 input_transformations 数组中包含 thinking_mismatch_allowed 条目的 200 响应:该请求没有收到错误。每个条目都指出一个未通过前缀检查并到达了 Claude 的思考块。
  • 一个 input_transformations 数组为空的 200 响应:没有块未通过前缀检查,因此该测试无法说明任何情况。请确认该对话包含来自该模型的思考块。

该结果只描述这一个请求,并不保证之后的请求会怎样,因此请编写代码来处理两种情况。

后续步骤

针对您的代码对对话所做的每种更改,应当改为发送什么。

恢复失败的对话,找出您的代码更改了什么,并测试问题是否已消除。

什么是保留思考、思考块与什么绑定,以及切换模型或账户。

此页面对您有帮助吗?