---
title: 保留思考
url: https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking
description: 保留思考讓模型只有在較早回合的思考區塊是由該模型或一組固定的其他模型之一所產生，且該區塊之前的內容都未變更時，才能使用該思考區塊。
---

「Preserved thinking」（保留思考）是較新 Claude 模型的一項特性，用於防範「distillation」（蒸餾）。它決定模型能否使用您從較早回合傳回的「thinking block」（思考區塊）。從 Claude Fable 5.1 開始，當請求中傳回 `thinking` 或 `redacted_thinking` 區塊時，API 會檢查該區塊的 `signature` 是否符合兩項條件：

* **模型可以讀取該區塊。** 每個模型都能讀取自己的思考區塊，以及一組固定的其他模型的思考區塊。Claude Fable 5.1 可讀取來自 Claude Opus 5 的區塊，在 Claude API 上也可讀取來自 Claude Opus 5.5 的區塊；Claude Opus 5 和 Claude Opus 5.5 都無法讀取來自 Claude Fable 5.1 的區塊。如果目前的模型無法讀取某個區塊，API 會在該請求中將其捨棄，且不會產生錯誤。請參閱[在對話中途切換模型](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#switching-models)。
* **思考區塊之前的內容都未變更。** 區塊之前的頂層 `system` 提示、`tools` 和 `messages` 構成其「prefix」（前綴）。如果前綴與產生該區塊時您所傳送的內容不同，該區塊及其後的所有思考區塊都會失效，API 會依您的選擇以 400 錯誤拒絕請求，或捨棄失效的區塊。請參閱[保持前綴不變](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#prefix-check)。

來自 Claude Sonnet 5.5 和 Claude Haiku 5.5 的思考區塊也與產生它們的帳戶綁定。請參閱[思考區塊僅限產生它們的帳戶使用](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#account-bound-thinking)，了解 API 在何處強制執行此規則。

模型檢查適用於所有帳戶。對於在 2026 年 8 月 31 日 00:00 UTC 當天或之後建立的帳戶，API 預設會強制執行前綴檢查。對於較舊的帳戶，API 只會在設定了 `thinking.block_binding.prefix_mismatch_behavior` 的請求上強制執行前綴檢查。**無論您的帳戶建立時間為何，都請讓您的整合採用僅附加（append-only）的方式**，如此相同的程式碼就能在所有帳戶上運作，包括預設強制執行檢查的較新帳戶。

## 誰需要做出變更

如果您的請求是由 Claude Code、claude.ai、Claude Managed Agents 或 Claude Agent SDK 建構，或者您的程式碼在整個工作階段中保持 `system` 和 `tools` 固定，且只會附加內容到 `messages`，那麼您不需要做任何變更。Claude Mythos 5.1 以及 Claude Fable 5.1 之前的模型不會執行前綴檢查。如果您從不傳回思考區塊，前綴檢查就沒有可拒絕的內容，而模型也無法取得任何先前的推理。

如果您的整合在同一對話的兩次請求之間執行了下列任何操作，請檢查您的整合。每個項目都連結到替代做法：

* [重建 `system` 提示](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#new-instructions)：日期、模式旗標、重新讀取的專案指示，或在第一輪之後才連線的外掛程式或 MCP 伺服器
* [重新渲染第一則使用者訊息中的上下文](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#changing-context)
* [清除或縮短舊的工具結果，或重新編碼舊的圖片](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#server-side-trimming)
* [在用戶端摘要或捨棄舊的回合](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#custom-compaction-on-the-client)，並保留最近的回合及其思考
* [新增、移除或編輯 `tools` 中的項目](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#tool-changes)
* [在使用者回合中加入提醒](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#per-turn-reminders)，之後又將其移除或改寫
* [捨棄部分 `thinking` 區塊但保留後面的區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#append-assistant-turns-exactly-as-returned)，或將其移除後[又放回去](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#prefix-check)
* [從範本重建已儲存的工作階段](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#faq)，而不是重播實際傳送過的內容

在較舊的帳戶上，除非請求設定了 `prefix_mismatch_behavior`，否則上述任何操作都不會產生錯誤，因此使用您自己的金鑰執行時沒有錯誤，並不代表您的程式碼不受影響。如果有人使用自己的 API 金鑰執行您的工具，使用較新帳戶的人會比您更早遇到 400 錯誤。若要在不改變請求行為的情況下看到他們所看到的情況，請傳送 `thinking-binding-controls-2026-08-01` beta 標頭。在較舊的帳戶上，每個回應都會標示未通過檢查的區塊，而模型仍會讀取這些區塊（請參閱[設定不符行為並讀取 `input_transformations`](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#preserved-thinking-controls)）。

如果您的整合會將某個帳戶的 Claude Sonnet 5.5 或 Claude Haiku 5.5 思考區塊放在另一個帳戶發出的請求中傳送，也請檢查您的整合。請參閱[思考區塊僅限產生它們的帳戶使用](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#account-bound-thinking)。

## 在對話中途切換模型

Claude Fable 5.1 和 Claude Mythos 5.1 能讀取彼此以及較早 Claude 模型所產生的思考區塊。沒有其他模型能讀取來自 Claude Fable 5.1 或 Claude Mythos 5.1 的思考區塊。

Claude Opus 5.5 可讀取來自 Claude Opus 5、較早的 Opus、Sonnet 和 Haiku 模型的思考區塊，並且在 Claude API 和 Google Cloud 上可讀取來自 Claude Sonnet 5.5 和 Claude Haiku 5.5 的思考區塊，但無法讀取來自 Claude Fable 或 Claude Mythos 模型的思考區塊。在 Claude API 上，Claude Fable 5.1 和 Claude Mythos 5.1 可讀取來自 Claude Opus 5.5 的思考區塊；其他模型則不行。因此，從 Claude Opus 5 轉移到 Claude Opus 5.5 的對話會保留其推理，在 Claude API 上從 Claude Opus 5.5 升級到 Claude Fable 5.1 或 Claude Mythos 5.1 的對話也是如此。從 Claude Fable 5.1 或 Claude Mythos 5.1 轉移到 Claude Opus 5.5，或從 Claude Opus 5.5 轉移到這兩者以外的任何模型的對話，在切換後的回合中將不會有前一個模型的推理。如本節稍後所述，這些區塊會被捨棄，而不是被拒絕。

Claude Sonnet 5.5 可讀取來自 Claude Sonnet 5、Claude Opus 4.8、Claude Haiku 4.5 及更早模型的思考區塊，在 Claude API 和 Google Cloud 上也可讀取來自 Claude Haiku 5.5 的思考區塊，但無法讀取來自 Claude Opus 5、Claude Opus 5.5 或任何 Claude Fable 或 Claude Mythos 模型的思考區塊。在 Claude API 和 Google Cloud 上，Claude Opus 5.5 可讀取來自 Claude Sonnet 5.5 的思考區塊；其他模型則不行。因此，從 Claude Sonnet 5 轉移到 Claude Sonnet 5.5 的對話會保留其推理，在 Claude API 和 Google Cloud 上從 Claude Sonnet 5.5 升級到 Claude Opus 5.5 的對話也是如此。從 Claude Opus 5、Claude Opus 5.5 或 Claude Fable 或 Claude Mythos 模型轉移到 Claude Sonnet 5.5 的對話，在切換後的回合中將不會有前一個模型的推理。任何其他離開 Claude Sonnet 5.5 的轉移也是如此，例如[伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)到 Claude Sonnet 5。

Claude Haiku 5.5 能讀取來自 Claude Sonnet 5、Claude Opus 4.8、Claude Haiku 4.5 及較早模型的思考區塊，但無法讀取來自 Claude Opus 5、Claude Opus 5.5、Claude Sonnet 5.5 或任何 Claude Fable 或 Claude Mythos 模型的思考區塊。在 Claude API 和 Google Cloud 上，Claude Opus 5.5 和 Claude Sonnet 5.5 能讀取來自 Claude Haiku 5.5 的思考區塊；其他模型則不能。因此，從 Claude Haiku 4.5 轉移到 Claude Haiku 5.5 的對話會保留其推理，在 Claude API 和 Google Cloud 上從 Claude Haiku 5.5 升級到 Claude Opus 5.5 或 Claude Sonnet 5.5 的對話也是如此。從 Claude Opus 5、Claude Opus 5.5、Claude Sonnet 5.5 或 Claude Fable 或 Claude Mythos 模型轉移到 Claude Haiku 5.5 的對話，在切換後的輪次中將不會有先前模型的推理，任何其他離開 Claude Haiku 5.5 的轉移也是如此。

* **從較早模型，或在 Claude API 上從 Claude Opus 5.5 轉移到 Claude Fable 5.1 的對話會保留其推理。** 較早模型的思考區塊仍可讀取，因此模型從切換後的第一輪起就能照常思考。
* **從 Claude Fable 5.1 轉移到 Claude Mythos 5.1 以外任何模型的對話，會在該請求中失去 Claude Fable 5.1 的推理。** 這種情況發生在路由器將某一輪傳送到較便宜的模型時、[分類器拒絕備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback)之後，或在[伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)期間。API 會在提示到達模型之前移除無法讀取的區塊。這些區塊不會計費，也不會計入 `input_tokens`。

請在每次請求中持續傳送完整的歷史記錄（包括思考區塊），並讓 API 捨棄目前模型無法讀取的內容。API 絕不會編輯您的 `messages` 陣列，因此被捨棄的區塊仍會保留在您的歷史記錄中。當相同的歷史記錄再次傳送給 Claude Fable 5.1 時，其區塊會再次變得可讀取，較早模型的思考也一樣。只有在您的用戶端自行移除這些區塊時，推理才會永久遺失，例如在切換模型時剝除思考內容，或根據每個模型所使用的內容重建歷史記錄的框架。

<Frame>
  ![動畫：切換到 Claude Opus 時，該輪會略過 Claude Fable 5.1 的思考；切換回來後，所有內容都會再次被讀取](https://platform.claude.com/docs/images/preserved-thinking-model-switch.svg)
</Frame>

使用 `thinking-binding-controls-2026-08-01` [beta 標頭](https://platform.claude.com/docs/zh-TW/api/beta-headers)時，回應會在頂層的 `input_transformations` 陣列中列出每個被捨棄的區塊，並附上 `reason: "model_binding_mismatch"`：

```json
{
  "input_transformations": [
    {
      "type": "thinking_dropped",
      "path": "messages.3.content.0",
      "reason": "model_binding_mismatch"
    }
  ]
}
```

若未使用該標頭，捨棄會靜默進行。此項目並不代表您的整合有錯誤，且 `prefix_mismatch_behavior` 對其沒有影響：目前模型無法讀取的區塊一律會被捨棄。

## 思考區塊僅限產生它們的帳戶使用

Claude Sonnet 5.5 或 Claude Haiku 5.5 產生的思考區塊，只能在產生它們的帳戶或與其連結的帳戶中使用。當其他帳戶傳送這些區塊之一時，API 會在模型看到之前捨棄該區塊，而請求會成功。模型會在沒有被捨棄區塊中推理的情況下作答。來自較早模型的區塊不受影響。

在 Claude API 和 Google Cloud 上，使用 `thinking-binding-controls-2026-08-01` [beta 標頭](https://platform.claude.com/docs/zh-TW/api/beta-headers)時，回應會在 `input_transformations` 中將每個被捨棄的區塊列為 `thinking_dropped` 項目，並附上 `reason: "organization_binding_mismatch"`。若未使用該標頭，捨棄會靜默進行。

## 保持前綴不變

在 Claude Fable 5.1、Claude Opus 5.5、Claude Sonnet 5.5 和 Claude Haiku 5.5 上，只有當您在其之前傳送的所有內容在後續請求中都保持不變時，思考區塊才會維持有效。受檢查的前綴包含三個部分：

* 頂層 `system` 提示
* `tools` 集合
* 該區塊之前的每一則 `message`

注意：使用伺服器端[壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction)時，受檢查的前綴從最近的壓縮區塊開始。

這三個欄位以外的請求參數，例如 `effort`、`max_tokens`、`output_config`、`tool_choice` 和 `metadata`，不屬於前綴檢查的範圍，`cache_control` 標記也不屬於。[哪些變更算是編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#what-counts-as-an-edit)提供了完整清單。

較早的思考區塊不在前綴中，但每個思考區塊都會記錄跨回合時在它之前的是哪個思考區塊。您可以從歷史記錄的開頭（最舊的優先）、結尾移除思考區塊，或全部移除。會失敗的是出現缺口：您保留的思考區塊必須是原始序列中連續不中斷的一段，因此從中間移除一個區塊會使其後的思考區塊失效。一旦移除某個區塊，就不要再放回去。將其放回會使它不在期間所產生的思考區塊失效。

請在整個工作階段中保持 `system` 和 `tools` 固定，並將 `messages` 視為僅附加。同樣的原則也能讓[提示快取](https://platform.claude.com/docs/zh-TW/build-with-claude/prompt-caching)的前綴保持穩定：使思考失效的編輯，正是會讓快取重新開始的編輯。

### API 如何處理失效的區塊

您可以透過 `thinking.block_binding.prefix_mismatch_behavior` 來選擇：

* **`"error"`（預設值）：** API 會以 400 `invalid_request_error` 拒絕請求，並指出第一個失敗的區塊。
* **`"drop_block"`：** API 會捨棄每個失敗的區塊及其後的每個思考區塊，且請求會成功。被捨棄的區塊不會計費。模型在該回合的回答不會使用被捨棄區塊中的推理，且提示快取會從編輯處重新開始。回應會在 `input_transformations` 中（串流時位於 `message_start` 事件上）列出每個被捨棄的區塊，並附上 `reason: "prefix_binding_mismatch"`。

<Warning>
  `"drop_block"` 能讓請求持續成功，但它並不會修正造成不符的編輯，而且有其代價。捨棄區塊可能會大幅增加產生的輸出 token，尤其是在較高的 effort 等級下，或每個回合都捨棄區塊時。如需更多資訊，請參閱[`"drop_block"` 的輸出 token 成本](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#drop-block-cost)。被捨棄的區塊不會計費，但 Claude 會重新建立它無法再讀取的推理，因此會產生更多輸出 token。在後續回合建立於先前推理之上的任務中，輸出品質也可能改變。請將 `"drop_block"` 作為修正編輯期間的權宜之計，而非長期設定。
</Warning>

請計算每個工作階段中 `input_transformations` 含有 `prefix_binding_mismatch` 項目的回應數量，針對這些回應發出警示，並以[在不編輯前綴的情況下進行變更](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#replace-prefix-edits)中對應的模式取代每項編輯。在 Message Batches API 中，未設定此欄位的項目不會失敗。在 API 預設強制執行檢查的情況下，它會改為捨棄失敗的區塊。如果您希望批次項目失敗，請在該處明確設定 `"error"`。

此欄位和 `input_transformations` 陣列都需要 `thinking-binding-controls-2026-08-01` [beta 標頭](https://platform.claude.com/docs/zh-TW/api/beta-headers)。[設定不符行為並讀取 `input_transformations`](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#preserved-thinking-controls) 展示了各 SDK 中的請求。

400 訊息的開頭為：

```text wrap
messages.1.content.0: Invalid `signature` in `thinking` block. The block is bound to a different conversation. Remove the block, or set `thinking.block_binding.prefix_mismatch_behavior` to "drop_block".
```

如果請求未傳送 beta 標頭，訊息會接著顯示：

```text wrap
That setting requires the `thinking-binding-controls-2026-08-01` value in the `anthropic-beta` header.
```

訊息通常以一句說明變更內容的句子結尾，例如 `system` 提示或 `tools` 清單與建立該區塊時不同。[思考疑難排解](https://platform.claude.com/docs/zh-TW/build-with-claude/thinking-troubleshooting#error-thinking-block-signature)說明了該句子可能指出的內容。

遭竄改或無法解密的簽章是另一種失敗。它一律會回傳 400（``Invalid `signature` in `thinking` block``，且沒有關於對話的句子），且 `prefix_mismatch_behavior` 不適用於此情況。

#### `"drop_block"` 的輸出 token 成本

在 Anthropic 針對多回合程式設計基準測試的測試中，每個工作階段捨棄一次思考區塊，會使輸出 token 在 low effort 下增加 2.5%、medium 下增加 3.9%、high 下增加 4.5%、max 下增加 20.1%。在第一個回合之後的每個回合都捨棄，會使輸出 token 在 low effort 下增加 4.6%、medium 下增加 9.7%、high 下增加 10.3%、max 下增加 67.1%。這些數字是誤差範圍很大的估計值，對您工作負載的影響取決於您的執行框架。

當 Claude 無法再讀取先前回合的推理時，它會重新建立該推理，因此捨棄思考區塊的請求會產生更多輸出 token，且回應時間可能更長。每個回合都捨棄的成本高於偶爾捨棄，而高出多少取決於您的執行框架：它編輯前綴的頻率，以及每個回合在多大程度上建立於先前的推理之上。

在依賴 `"drop_block"` 之前，請在您自己的工作負載上執行評估以衡量增幅。如果增幅很小，`"drop_block"` 可以在您修正編輯期間讓請求持續成功。無論如何，使用[在不編輯前綴的情況下進行變更](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#replace-prefix-edits)中的模式修正編輯，都是更好的長期解決方案。

#### 在程式碼中處理錯誤

這是本節前面所示的 400 `invalid_request_error`。請勿重新傳送相同的內容：它每次都會以相同方式失敗。請使用 beta 標頭和 `prefix_mismatch_behavior: "drop_block"` 重試一次作為權宜之計（[`"drop_block"` 可能會增加輸出 token](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#drop-block-cost)），並將該選擇與工作階段一起儲存，讓之後的每個請求也都傳送它，包括重新啟動之後。在 Claude Sonnet 5.5 和 Claude Haiku 5.5 上，`block_binding` 僅適用於 `thinking: {"type": "adaptive"}`。若在 Claude Sonnet 5.5 上使用 `between_tools`，或在 Claude Haiku 5.5 上使用 `thinking: {"type": "disabled"}`，請保持歷史記錄僅附加，或從被編輯的回合起剝除思考區塊。如果您無法傳送 beta 標頭，請從歷史記錄中一次移除所有 `thinking` 和 `redacted_thinking` 區塊，之後不再放回，然後繼續。接著修正造成不符的編輯。

### 設定不符行為並讀取 `input_transformations`

`thinking-binding-controls-2026-08-01` [beta 標頭](https://platform.claude.com/docs/zh-TW/api/beta-headers)會新增：

* 每個回應上的頂層 `input_transformations` 陣列
* `thinking` 設定上的 `block_binding` 物件，其唯一欄位為 `prefix_mismatch_behavior`

`block_binding` 可與 `thinking.type: "adaptive"` 和 `thinking.type: "enabled"` 一起使用。在 Claude Sonnet 5.5 和 Claude Haiku 5.5 上，`block_binding` 僅適用於 `thinking: {"type": "adaptive"}`。將它與 `between_tools`（於 Claude Sonnet 5.5 上）一起傳送，或在 Claude Haiku 5.5 上與 `thinking: {"type": "disabled"}` 一起傳送，會回傳 400 錯誤。在沒有 beta 標頭的情況下傳送它，會回傳 400 錯誤，其訊息以 `block_binding: Extra inputs are not permitted` 結尾。不執行前綴檢查的模型會接受此物件，且只回報模型檢查造成的捨棄，因此同一個請求內容可跨模型使用。API 參考文件將前綴檢查稱為對話檢查。

以下請求選擇捨棄而非拒絕。在第一輪中沒有可重播的內容，因此 `input_transformations` 會回傳空陣列：

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-fable-5-1",
      "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?"
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
    --format yaml <<'YAML'
  model: claude-fable-5-1
  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?
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.beta.messages.create(
      model="claude-fable-5-1",
      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 [])}")
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-fable-5-1",
    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 (const block of response.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  console.log(`Input transformations: ${response.input_transformations?.length ?? 0}`);
  ```

  ```csharp C#
  AnthropicClient client = new();

  var response = await client.Beta.Messages.Create(
      new()
      {
          Model = Model.ClaudeFable5_1,
          MaxTokens = 16000,
          Thinking = new BetaThinkingConfigAdaptive
          {
              BlockBinding = new()
              {
                  PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
              },
          },
          Messages =
          [
              new()
              {
                  Role = Role.User,
                  Content = "What is the greatest common divisor of 1071 and 462?",
              },
          ],
          Betas = [AnthropicBeta.ThinkingBindingControls2026_08_01],
      }
  );

  foreach (var block in response.Content)
  {
      if (block.TryPickText(out var textBlock))
      {
          Console.WriteLine(textBlock.Text);
      }
  }

  Console.WriteLine($"Input transformations: {response.InputTransformations?.Count ?? 0}");
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeFable5_1,
  	MaxTokens: 16000,
  	Thinking: anthropic.BetaThinkingConfigParamUnion{
  		OfAdaptive: &anthropic.BetaThinkingConfigAdaptiveParam{
  			BlockBinding: anthropic.BetaThinkingBlockBindingParam{
  				PrefixMismatchBehavior: anthropic.BetaThinkingPrefixMismatchBehaviorDropBlock,
  			},
  		},
  	},
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What is the greatest common divisor of 1071 and 462?")),
  	},
  	Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaThinkingBindingControls2026_08_01},
  })
  if err != nil {
  	log.Fatal(err)
  }

  for _, block := range response.Content {
  	if textBlock, ok := block.AsAny().(anthropic.BetaTextBlock); ok {
  		fmt.Println(textBlock.Text)
  	}
  }
  fmt.Printf("Input transformations: %d\n", len(response.InputTransformations))
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaThinkingBlockBinding;
  import com.anthropic.models.beta.messages.BetaThinkingConfigAdaptive;
  import com.anthropic.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  import com.anthropic.models.messages.Model;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5_1)
          .maxTokens(16000L)
          .addBeta(AnthropicBeta.THINKING_BINDING_CONTROLS_2026_08_01)
          .thinking(BetaThinkingConfigAdaptive.builder()
              .blockBinding(BetaThinkingBlockBinding.builder()
                  .prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
                  .build())
              .build())
          .addUserMessage("What is the greatest common divisor of 1071 and 462?")
          .build();

      BetaMessage response = client.beta().messages().create(params);

      response.content().stream()
          .flatMap(block -> block.text().stream())
          .forEach(textBlock -> IO.println(textBlock.text()));
      IO.println("Input transformations: "
          + response.inputTransformations().map(List::size).orElse(0));
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaThinkingBlockBinding;
  use Anthropic\Beta\Messages\BetaThinkingConfigAdaptive;
  use Anthropic\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
  use Anthropic\Client;

  $client = new Client();

  $response = $client->beta->messages->create(
      model: 'claude-fable-5-1',
      maxTokens: 16000,
      thinking: BetaThinkingConfigAdaptive::with(
          blockBinding: BetaThinkingBlockBinding::with(
              prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
          ),
      ),
      messages: [
          ['role' => 'user', 'content' => 'What is the greatest common divisor of 1071 and 462?'],
      ],
      betas: [AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01],
  );

  foreach ($response->content as $block) {
      if ($block->type === 'text') {
          echo $block->text, PHP_EOL;
      }
  }

  echo 'Input transformations: ', count($response->inputTransformations ?? []), PHP_EOL;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: "claude-fable-5-1",
    max_tokens: 16_000,
    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: [Anthropic::AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01]
  )

  response.content.each do |block|
    puts block.text if block.type == :text
  end

  puts "Input transformations: #{response.input_transformations&.length || 0}"
  ```
</CodeGroup>

```text Output wrap
The greatest common divisor of 1071 and 462 is 21.
Input transformations: 0
```

在 beta 標頭下，每個來自支援思考之模型的回應都會帶有 `input_transformations`。每個項目都以其 `path`（例如 `messages.1.content.0`）指出一個思考區塊，並提供 `reason`。項目有兩種類型：

* **`thinking_dropped`：** API 在模型讀取之前捨棄該區塊，且該區塊不會計費。`reason` 為 `prefix_binding_mismatch` 或 `model_binding_mismatch`（請參閱[在對話中途切換模型](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#switching-models)）。`reason` 也可能是 `organization_binding_mismatch`，表示該區塊來自另一個帳戶（請參閱[思考區塊僅限產生它們的帳戶使用](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#account-bound-thinking)）。
* **`thinking_mismatch_allowed`：** 該區塊未通過前綴檢查，但 API 未對此請求強制執行該檢查，因此該區塊會原封不動地送達模型並計費。`reason` 一律為 `prefix_binding_mismatch`。此項目只會出現在 API 預設不強制執行檢查的請求上，例如來自較舊帳戶的請求（請參閱[API 何時強制執行檢查](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#enforcement)）。將 `prefix_mismatch_behavior` 設為任一值都會讓請求選擇加入強制執行，因此設定了它的請求永遠不會出現此項目。

當沒有區塊被捨棄且沒有區塊未通過前綴檢查時，陣列為空。請忽略您無法辨識其 `type` 或 `reason` 的項目，因為之後的檢查會新增值。

[串流](https://platform.claude.com/docs/zh-TW/build-with-claude/streaming)時，陣列會出現在 `message_start` 事件的 `message` 物件上。在串流中途發生伺服器端備援後，最後的 `message_delta` 事件會再次帶有該陣列，其中包含實際提供服務之模型的項目。在[訊息批次](https://platform.claude.com/docs/zh-TW/build-with-claude/batch-processing)中，若項目明確設定 `"error"` 且其區塊未通過前綴檢查，該項目會以 `errored` 結束。未設定此欄位的項目不會失敗。在 API 預設強制執行檢查的情況下，它會改為捨棄失敗的區塊。[token 計數](https://platform.claude.com/docs/zh-TW/build-with-claude/token-counting)端點會執行相同的前綴檢查，並回傳相同的 400。

### API 何時強制執行檢查

對於新帳戶，API 會在 Claude Fable 5.1、Claude Opus 5.5、Claude Sonnet 5.5 和 Claude Haiku 5.5 上強制執行前綴檢查。

* **在 2026 年 8 月 31 日 00:00 UTC 當天或之後建立的帳戶：** API 會檢查 Claude Fable 5.1、Claude Opus 5.5、Claude Sonnet 5.5 和 Claude Haiku 5.5 的請求，並套用 `"error"`，除非您設定 `"drop_block"`。新帳戶的相同定義適用於 Claude API 和雲端平台。
* **較舊的帳戶：** API 只會在設定了 `prefix_mismatch_behavior` 的請求上強制執行檢查。設定此欄位會讓請求選擇加入，因此您無需建立新帳戶就能看到新帳戶所看到的情況。在未設定此欄位的請求上，API 仍會執行檢查，但會讓失敗的區塊通過並送達模型。使用 beta 標頭時，回應會在 `input_transformations` 中將每個此類區塊列為 `thinking_mismatch_allowed`，讓您在不改變模型所接收內容的情況下找出前綴編輯。

若要確認您的帳戶屬於哪一組，請取一段包含思考區塊的 Claude Fable 5.1 對話，變更該區塊之前的某些內容，然後在不使用 beta 標頭或 `block_binding` 欄位的情況下將其傳送給 Claude Fable 5.1。若回應為指出該標頭的 400，表示您的帳戶預設會強制執行檢查。若回應為 200，則表示不會。若要確認，請使用 beta 標頭再次傳送相同的請求，同樣不使用 `block_binding`：回應會在 `input_transformations` 中將您編輯處之後的每個思考區塊列為 `thinking_mismatch_allowed`。

### 哪些變更算是編輯

每一列比較兩個連續的請求：

| 請求之間的變更                                                                                                                         | 之後的思考區塊                                                                                                                                                                                                                                                         |
| ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 在結尾附加訊息                                                                                                                         | 有效                                                                                                                                                                                                                                                              |
| 新增一個設定 `defer_loading: true` 且尚未被任何內容參照的工具                                                                                      | 有效                                                                                                                                                                                                                                                              |
| 從歷史記錄的開頭、結尾移除 `thinking` 區塊，或全部移除                                                                                               | 有效（模型會失去該推理）                                                                                                                                                                                                                                                    |
| 變更 `system`、`tools` 和 `messages` 以外的任何請求參數（`effort`、`max_tokens`、`output_config`、`tool_choice`、`metadata`、`thinking.display` 等） | 有效                                                                                                                                                                                                                                                              |
| 新增、移動或移除 `cache_control` 標記                                                                                                     | 有效                                                                                                                                                                                                                                                              |
| 傳回相同位元組的輪替簽署 URL                                                                                                                | 有效                                                                                                                                                                                                                                                              |
| 伺服器端壓縮或上下文編輯移除或取代內容                                                                                                             | 有效（檢查比較的是您傳送的內容，而非伺服器編輯後的副本）                                                                                                                                                                                                                                    |
| 保留在原處的已清除[回合範圍系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#per-turn-reminders)             | 有效                                                                                                                                                                                                                                                              |
| 編輯、重新排序或刪除任何較早的 `user`、`assistant` 或 `system` 訊息                                                                                | 無效，但在[保留的思考維持有效的條件](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid)下，由[隨需壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-on-demand)產生的已簽署區塊取代其所摘要的訊息時除外 |
| 以變更後的值重新渲染您放在第一則使用者訊息中的上下文                                                                                                      | 所有思考區塊皆無效                                                                                                                                                                                                                                                       |
| 清除或縮短較早的 `tool_result`、重新編碼較早的圖片，或變更較早的 `tool_use` 輸入                                                                           | 之後的所有思考區塊皆無效                                                                                                                                                                                                                                                    |
| 在較早的使用者回合中新增文字區塊，或移除您上次新增的文字區塊                                                                                                  | 無效                                                                                                                                                                                                                                                              |
| 變更頂層 `system` 字串或區塊                                                                                                             | 無效                                                                                                                                                                                                                                                              |
| 新增、移除、重新命名或編輯 `tools` 中的工具                                                                                                      | 無效                                                                                                                                                                                                                                                              |
| 從歷史記錄中間移除 `thinking` 區塊並保留之後的區塊                                                                                                 | 之後的所有思考區塊皆無效                                                                                                                                                                                                                                                    |
| 放回您在較早請求中移除的 `thinking` 區塊                                                                                                      | 在其不在期間產生的思考區塊無效                                                                                                                                                                                                                                                 |
| 在下一個請求中傳回不同位元組的圖片或文件 URL                                                                                                        | 無效                                                                                                                                                                                                                                                              |
| 在之後的請求中刪除或改寫相同的回合範圍訊息                                                                                                           | 無效                                                                                                                                                                                                                                                              |

### 檢查您的程式碼是否編輯了前綴

<Tip>
  **使用 Claude API 技能自動執行此檢查。** 在最新版本的 [Claude Code](https://code.claude.com/docs/en/overview) 中，開啟建構您請求的儲存庫，並執行內建的 [Claude API 技能](https://platform.claude.com/docs/zh-TW/agents-and-tools/agent-skills/claude-api-skill#checking-an-integration-for-preserved-thinking)：

  讓 Claude Code 為您檢查程式碼

  ```text
  /claude-api preserved-thinking-migration
  ```

  此技能會擷取您自己的幾個多輪工作階段，並比對連續請求的差異，以找出您的程式碼在何處編輯了前綴。接著它會以 `"drop_block"` 重播這些工作階段，並計算 API 捨棄的思考區塊數量。之後，它會一次修正一個原因，並在每次修正後重新測量。
</Tip>

首先，比對您傳送的內容。擷取您的整合在幾個正常回合中傳送的請求內容，包括一次壓縮或一次工具變更。針對每一對連續請求，比較 `system`、`tools` 以及它們共有的 `messages`。除了新附加的回合之外，它們應該完全相同。

接著透過 API 確認。加入 `thinking-binding-controls-2026-08-01` beta 標頭，將 `prefix_mismatch_behavior` 設為 `"drop_block"`，並在 claude-fable-5-1上透過您的整合執行一個正常的多輪工作階段。以下範例以您的整合應有的方式執行兩輪：`messages` 只會增長，每個助理回合都完全依照 API 回傳的內容傳回（包括 `thinking` 區塊），且每個請求都設定了 `block_binding`。每輪結束後，它會印出回應中 `thinking` 區塊的數量以及被捨棄區塊的數量：

<CodeGroup>
  ```bash cURL
  # 計算回應中的 thinking 區塊數量，以及被 API 捨棄的區塊數量
  COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
    "dropped: \(.input_transformations | length)"'

  FIRST=$(curl -s https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -d '{
      "model": "claude-fable-5-1",
      "max_tokens": 16000,
      "thinking": {
        "type": "adaptive",
        "block_binding": { "prefix_mismatch_behavior": "drop_block" }
      },
      "messages": [
        {
          "role": "user",
          "content": "How many positive integers below 500 have exactly 6 positive divisors?"
        }
      ]
    }')
  echo "$FIRST" | jq -r "$COUNTS"

  # 第 2 輪：assistant 輪次依原樣傳回，接著是下一則使用者訊息
  MESSAGES=$(jq -n --argjson first "$FIRST" '[
    {
      role: "user",
      content: "How many positive integers below 500 have exactly 6 positive divisors?"
    },
    { role: "assistant", content: $first.content },
    { role: "user", content: "How many of those are odd?" }
  ]')

  jq -n --argjson messages "$MESSAGES" '{
    model: "claude-fable-5-1",
    max_tokens: 16000,
    thinking: {
      type: "adaptive",
      block_binding: { prefix_mismatch_behavior: "drop_block" }
    },
    messages: $messages
  }' | curl -s https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -d @- | jq -r "$COUNTS"
  ```

  ```bash CLI
  # 計算回應中的 thinking 區塊數量，以及被 API 捨棄的區塊數量
  COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
    "dropped: \(.input_transformations | length)"'

  FIRST=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
    --format json <<'YAML'
  model: claude-fable-5-1
  max_tokens: 16000
  thinking:
    type: adaptive
    block_binding:
      prefix_mismatch_behavior: drop_block
  messages:
    - role: user
      content: How many positive integers below 500 have exactly 6 positive divisors?
  YAML
  )
  echo "$FIRST" | jq -r "$COUNTS"

  # 第 2 輪：assistant 輪次依原樣傳回，接著是下一則使用者訊息
  ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
    --format json <<YAML | jq -r "$COUNTS"
  model: claude-fable-5-1
  max_tokens: 16000
  thinking:
    type: adaptive
    block_binding:
      prefix_mismatch_behavior: drop_block
  messages:
    - role: user
      content: How many positive integers below 500 have exactly 6 positive divisors?
    - role: assistant
      content: $(echo "$FIRST" | jq -c .content)
    - role: user
      content: How many of those are odd?
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  user_turns = [
      "How many positive integers below 500 have exactly 6 positive divisors?",
      "How many of those are odd?",
  ]

  # messages 會隨輪次增長：每個 assistant 回合都原封不動地依回傳內容送回
  messages = []
  for user_turn in user_turns:
      messages.append({"role": "user", "content": user_turn})
      response = client.beta.messages.create(
          model="claude-fable-5-1",
          max_tokens=16000,
          thinking={
              "type": "adaptive",
              "block_binding": {"prefix_mismatch_behavior": "drop_block"},
          },
          messages=messages,
          betas=["thinking-binding-controls-2026-08-01"],
      )
      messages.append({"role": "assistant", "content": response.content})
      thinking_blocks = sum(block.type == "thinking" for block in response.content)
      dropped = len(response.input_transformations or [])
      print(f"thinking blocks: {thinking_blocks}, dropped: {dropped}")
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const userTurns = [
    "How many positive integers below 500 have exactly 6 positive divisors?",
    "How many of those are odd?"
  ];

  // messages 會隨輪次增長：每個 assistant 輪次都會原封不動地依回傳內容送回
  const messages: Anthropic.Beta.BetaMessageParam[] = [];
  for (const userTurn of userTurns) {
    messages.push({ role: "user", content: userTurn });
    const response = await client.beta.messages.create({
      model: "claude-fable-5-1",
      max_tokens: 16000,
      thinking: {
        type: "adaptive",
        block_binding: { prefix_mismatch_behavior: "drop_block" }
      },
      messages,
      betas: ["thinking-binding-controls-2026-08-01"]
    });
    messages.push({ role: "assistant", content: response.content });
    const thinkingBlocks = response.content.filter((block) => block.type === "thinking");
    const dropped = response.input_transformations ?? [];
    console.log(`thinking blocks: ${thinkingBlocks.length}, dropped: ${dropped.length}`);
  }
  ```

  ```csharp C#
  AnthropicClient client = new();

  string[] userTurns =
  [
      "How many positive integers below 500 have exactly 6 positive divisors?",
      "How many of those are odd?",
  ];

  // messages 會隨回合增長：每個 assistant 回合都會原封不動地依回傳內容送回
  List<BetaMessageParam> messages = [];
  foreach (var userTurn in userTurns)
  {
      messages.Add(new() { Role = Role.User, Content = userTurn });
      var response = await client.Beta.Messages.Create(
          new()
          {
              Model = Model.ClaudeFable5_1,
              MaxTokens = 16000,
              Thinking = new BetaThinkingConfigAdaptive
              {
                  BlockBinding = new()
                  {
                      PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
                  },
              },
              Messages = messages,
              Betas = [AnthropicBeta.ThinkingBindingControls2026_08_01],
          }
      );
      messages.Add(new()
      {
          Role = Role.Assistant,
          Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
      });
      var thinkingBlocks = response.Content.Count(block => block.TryPickThinking(out _));
      var dropped = response.InputTransformations?.Count ?? 0;
      Console.WriteLine($"thinking blocks: {thinkingBlocks}, dropped: {dropped}");
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  userTurns := []string{
  	"How many positive integers below 500 have exactly 6 positive divisors?",
  	"How many of those are odd?",
  }

  // messages 會隨輪次增長：每個 assistant 回合都會原封不動地依回傳內容送回
  messages := []anthropic.BetaMessageParam{}
  for _, userTurn := range userTurns {
  	messages = append(messages, anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock(userTurn)))
  	response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  		Model:     anthropic.ModelClaudeFable5_1,
  		MaxTokens: 16000,
  		Thinking: anthropic.BetaThinkingConfigParamUnion{
  			OfAdaptive: &anthropic.BetaThinkingConfigAdaptiveParam{
  				BlockBinding: anthropic.BetaThinkingBlockBindingParam{
  					PrefixMismatchBehavior: anthropic.BetaThinkingPrefixMismatchBehaviorDropBlock,
  				},
  			},
  		},
  		Messages: messages,
  		Betas:    []anthropic.AnthropicBeta{anthropic.AnthropicBetaThinkingBindingControls2026_08_01},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	messages = append(messages, response.ToParam())
  	thinkingBlocks := 0
  	for _, block := range response.Content {
  		if block.Type == "thinking" {
  			thinkingBlocks++
  		}
  	}
  	fmt.Printf("thinking blocks: %d, dropped: %d\n", thinkingBlocks, len(response.InputTransformations))
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaContentBlock;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaThinkingBlockBinding;
  import com.anthropic.models.beta.messages.BetaThinkingConfigAdaptive;
  import com.anthropic.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  import com.anthropic.models.messages.Model;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      List<String> userTurns = List.of(
          "How many positive integers below 500 have exactly 6 positive divisors?",
          "How many of those are odd?");

      // builder 的訊息清單會隨輪次增長：每個 assistant 輪次都會原封不動地依回傳內容送回
      MessageCreateParams.Builder conversation = MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5_1)
          .maxTokens(16000L)
          .thinking(BetaThinkingConfigAdaptive.builder()
              .blockBinding(BetaThinkingBlockBinding.builder()
                  .prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
                  .build())
              .build())
          .addBeta(AnthropicBeta.THINKING_BINDING_CONTROLS_2026_08_01);

      for (String userTurn : userTurns) {
          conversation.addUserMessage(userTurn);
          BetaMessage response = client.beta().messages().create(conversation.build());
          conversation.addMessage(response);
          long thinkingBlocks = response.content().stream()
              .filter(BetaContentBlock::isThinking)
              .count();
          int dropped = response.inputTransformations().map(List::size).orElse(0);
          IO.println("thinking blocks: " + thinkingBlocks + ", dropped: " + dropped);
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaThinkingBlockBinding;
  use Anthropic\Beta\Messages\BetaThinkingConfigAdaptive;
  use Anthropic\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
  use Anthropic\Client;

  $client = new Client();

  $userTurns = [
      'How many positive integers below 500 have exactly 6 positive divisors?',
      'How many of those are odd?',
  ];

  // $messages 會隨回合累積：每個 assistant 回合都依原樣傳回
  $messages = [];
  foreach ($userTurns as $userTurn) {
      $messages[] = ['role' => 'user', 'content' => $userTurn];
      $response = $client->beta->messages->create(
          model: 'claude-fable-5-1',
          maxTokens: 16000,
          thinking: BetaThinkingConfigAdaptive::with(
              blockBinding: BetaThinkingBlockBinding::with(
                  prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
              ),
          ),
          messages: $messages,
          betas: [AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01],
      );
      $messages[] = ['role' => 'assistant', 'content' => $response->content];
      $thinkingBlocks = array_filter($response->content, fn ($block) => $block->type === 'thinking');
      $dropped = $response->inputTransformations ?? [];
      echo 'thinking blocks: ', count($thinkingBlocks), ', dropped: ', count($dropped), PHP_EOL;
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  user_turns = [
    "How many positive integers below 500 have exactly 6 positive divisors?",
    "How many of those are odd?"
  ]

  # messages 會隨輪次增長：每個 assistant 輪次都依原樣傳回
  messages = []
  user_turns.each do |user_turn|
    messages << {role: "user", content: user_turn}
    response = client.beta.messages.create(
      model: "claude-fable-5-1",
      max_tokens: 16_000,
      thinking: {
        type: "adaptive",
        block_binding: {prefix_mismatch_behavior: "drop_block"}
      },
      messages: messages,
      betas: [Anthropic::AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01]
    )
    messages << {role: "assistant", content: response.content}
    thinking_blocks = response.content.count { |block| block.type == :thinking }
    dropped = (response.input_transformations || []).length
    puts "thinking blocks: #{thinking_blocks}, dropped: #{dropped}"
  end
  ```
</CodeGroup>

```text Output wrap
thinking blocks: 1, dropped: 0
thinking blocks: 1, dropped: 0
```

兩輪都沒有捨棄任何區塊，因為先前的內容都沒有變更。請確認第一個回應包含 `thinking` 區塊。使用自適應思考時，有些回應不會包含思考區塊。如果工作階段中沒有任何回應包含思考區塊，就沒有可檢查的內容，無論您變更什麼，捨棄數量都會是 0，因此請再次執行範例。

請在您自己整合的每一輪中記錄 `input_transformations`。當 API 捨棄區塊時，項目看起來如下：

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

* **在包含 `thinking` 區塊的工作階段中，每一輪都為空：** 您的整合保持了前綴完整。
* **`reason: "prefix_binding_mismatch"`：** 自上一次請求以來，位於 `path` 的區塊之前有內容發生了變更。比對到該輪為止的 `system`、`tools` 和 `messages` 以找出變更，或以 `"error"` 重新傳送請求：400 通常會以一句說明變更內容的句子結尾。接著在[在不編輯前綴的情況下進行變更](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#replace-prefix-edits)中找出對應的替代做法。
* **`reason: "model_binding_mismatch"`：** 對話轉移到了無法讀取較早模型區塊的模型。這不是前綴編輯。請參閱[在對話中途切換模型](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#switching-models)。
* **`reason: "organization_binding_mismatch"`：** 該區塊來自另一個帳戶。請參閱[思考區塊僅限產生它們的帳戶使用](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#account-bound-thinking)。

若要刻意觀察失敗情況，請從先前的範例傳送第三輪，並僅在該請求中加入 `system` 提示，使其與前兩個沒有 `system` 提示的請求不同。使用 `"drop_block"` 時，捨棄數量不再是 0：回應中歷史記錄裡的每個思考區塊都會有一個項目，每個項目都附有 `reason: "prefix_binding_mismatch"`。使用 `"error"` 時，請求會回傳[API 如何處理失效的區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#mismatch-behavior)中所述的 400，且其最後一句會指出 `system` 提示。在 cURL 和 CLI 分頁中，移除 `jq` 篩選器即可看到錯誤內容。如果數量仍為 0，表示沒有可檢查的內容：請確認模型為 claude-fable-5-1、請求設定了 `block_binding`、您傳送的歷史記錄包含 `thinking` 區塊，且前兩個請求沒有 `system` 提示。

單純的兩輪很少能顯示問題。請針對下列每一項執行一個工作階段，並設定 `"error"`，讓回歸問題導致您的 CI 失敗：

* 第一次用戶端壓縮或修剪
* 在第一輪之後才連線的工具、外掛程式或 MCP 伺服器
* 模式或指示的變更
* 長時間的工具迴圈（如果您會加入提醒或縮短舊的工具結果）
* 切換到另一個模型再切換回來
* 儲存、重新啟動，並在之後的日期繼續

在較舊的帳戶上，您也可以在不選擇加入強制執行的情況下觀察正式環境流量：傳送 beta 標頭、不加入 `block_binding`，並記錄 `input_transformations`。僅傳送標頭不會改變模型所接收的內容。位於您所編輯內容之後的每個思考區塊都會未通過檢查，並各自產生一個 `thinking_mismatch_allowed` 項目，其 `path` 和 `reason` 欄位與 `thinking_dropped` 項目相同。編輯處之前的區塊仍會通過。對 `system` 或 `tools` 的編輯位於所有區塊之前，因此會使請求中的所有思考區塊都未通過檢查。一個項目看起來如下：

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

請從[較舊的帳戶](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#enforcement)執行以下範例，因為較新的帳戶會以 400 拒絕其第三個請求。它傳送標頭但不使用 `block_binding`，並以第三個請求延伸先前的工作階段，該請求加入了系統提示，刻意變更前綴。每輪結束後，它會印出 `thinking` 區塊的數量以及被標示區塊的數量：

<CodeGroup>
  ```bash cURL
  # 計算回應中的 thinking 區塊數，以及未通過前綴檢查的區塊數
  COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
    "flagged: \([.input_transformations[] |
      select(.type == "thinking_mismatch_allowed")] | length)"'

  FIRST=$(curl -s https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -d '{
      "model": "claude-fable-5-1",
      "max_tokens": 16000,
      "thinking": { "type": "adaptive" },
      "messages": [
        {
          "role": "user",
          "content": "How many positive integers below 500 have exactly 6 positive divisors?"
        }
      ]
    }')
  echo "$FIRST" | jq -r "$COUNTS"

  # 第 2 輪：assistant 回合依原樣傳回，接著是下一則使用者訊息
  MESSAGES=$(jq -n --argjson first "$FIRST" '[
    {
      role: "user",
      content: "How many positive integers below 500 have exactly 6 positive divisors?"
    },
    { role: "assistant", content: $first.content },
    { role: "user", content: "How many of those are odd?" }
  ]')

  SECOND=$(jq -n --argjson messages "$MESSAGES" '{
    model: "claude-fable-5-1",
    max_tokens: 16000,
    thinking: { type: "adaptive" },
    messages: $messages
  }' | curl -s https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -d @-)
  echo "$SECOND" | jq -r "$COUNTS"

  # 第 3 輪：僅此請求加入系統提示，刻意改變前綴
  jq -n --argjson messages "$MESSAGES" --argjson second "$SECOND" '{
    model: "claude-fable-5-1",
    max_tokens: 16000,
    thinking: { type: "adaptive" },
    system: "Answer briefly.",
    messages: ($messages + [
      { role: "assistant", content: $second.content },
      { role: "user", content: "And how many of the odd ones are below 100?" }
    ])
  }' | curl -s https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -d @- | jq -r "$COUNTS"
  ```

  ```bash CLI
  # 計算回應中的 thinking 區塊數量，以及未通過前綴檢查的區塊數量
  COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
    "flagged: \([.input_transformations[] |
      select(.type == "thinking_mismatch_allowed")] | length)"'

  FIRST=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
    --format json <<'YAML'
  model: claude-fable-5-1
  max_tokens: 16000
  thinking:
    type: adaptive
  messages:
    - role: user
      content: How many positive integers below 500 have exactly 6 positive divisors?
  YAML
  )
  echo "$FIRST" | jq -r "$COUNTS"

  # 第 2 輪：assistant 輪次依原樣傳回，接著是下一則使用者訊息
  SECOND=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
    --format json <<YAML
  model: claude-fable-5-1
  max_tokens: 16000
  thinking:
    type: adaptive
  messages:
    - role: user
      content: How many positive integers below 500 have exactly 6 positive divisors?
    - role: assistant
      content: $(echo "$FIRST" | jq -c .content)
    - role: user
      content: How many of those are odd?
  YAML
  )
  echo "$SECOND" | jq -r "$COUNTS"

  # 第 3 輪：僅此請求加入系統提示，刻意改變前綴
  ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
    --format json <<YAML | jq -r "$COUNTS"
  model: claude-fable-5-1
  max_tokens: 16000
  thinking:
    type: adaptive
  system: Answer briefly.
  messages:
    - role: user
      content: How many positive integers below 500 have exactly 6 positive divisors?
    - role: assistant
      content: $(echo "$FIRST" | jq -c .content)
    - role: user
      content: How many of those are odd?
    - role: assistant
      content: $(echo "$SECOND" | jq -c .content)
    - role: user
      content: And how many of the odd ones are below 100?
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  user_turns = [
      "How many positive integers below 500 have exactly 6 positive divisors?",
      "How many of those are odd?",
      "And how many of the odd ones are below 100?",
  ]

  # messages 會隨輪次增長：每個 assistant 輪次都原封不動地傳回
  messages = []
  for turn, user_turn in enumerate(user_turns, start=1):
      messages.append({"role": "user", "content": user_turn})
      response = client.beta.messages.create(
          model="claude-fable-5-1",
          max_tokens=16000,
          thinking={"type": "adaptive"},
          # 只有最後一個請求加入系統提示，刻意改變前綴
          system="Answer briefly." if turn == len(user_turns) else anthropic.omit,
          messages=messages,
          betas=["thinking-binding-controls-2026-08-01"],
      )
      messages.append({"role": "assistant", "content": response.content})
      thinking_blocks = sum(block.type == "thinking" for block in response.content)
      flagged = sum(
          transformation.type == "thinking_mismatch_allowed"
          for transformation in response.input_transformations or []
      )
      print(f"thinking blocks: {thinking_blocks}, flagged: {flagged}")
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const userTurns = [
    "How many positive integers below 500 have exactly 6 positive divisors?",
    "How many of those are odd?",
    "And how many of the odd ones are below 100?"
  ];

  // messages 會隨回合增長：每個 assistant 回合都原封不動地依回傳內容送回
  const messages: Anthropic.Beta.BetaMessageParam[] = [];
  for (const [turnIndex, userTurn] of userTurns.entries()) {
    messages.push({ role: "user", content: userTurn });
    const response = await client.beta.messages.create({
      model: "claude-fable-5-1",
      max_tokens: 16000,
      thinking: { type: "adaptive" },
      // 只有最後一個請求加入系統提示，刻意改變前綴
      system: turnIndex === userTurns.length - 1 ? "Answer briefly." : undefined,
      messages,
      betas: ["thinking-binding-controls-2026-08-01"]
    });
    messages.push({ role: "assistant", content: response.content });
    const thinkingBlocks = response.content.filter((block) => block.type === "thinking");
    const flagged = (response.input_transformations ?? []).filter(
      (transformation) => transformation.type === "thinking_mismatch_allowed"
    );
    console.log(`thinking blocks: ${thinkingBlocks.length}, flagged: ${flagged.length}`);
  }
  ```

  ```csharp C#
  AnthropicClient client = new();

  string[] userTurns =
  [
      "How many positive integers below 500 have exactly 6 positive divisors?",
      "How many of those are odd?",
      "And how many of the odd ones are below 100?",
  ];

  // messages 會隨輪次增長：每個 assistant 輪次都會原封不動地依回傳內容送回
  List<BetaMessageParam> messages = [];
  for (var turnIndex = 0; turnIndex < userTurns.Length; turnIndex++)
  {
      messages.Add(new() { Role = Role.User, Content = userTurns[turnIndex] });
      var response = await client.Beta.Messages.Create(
          new()
          {
              Model = Model.ClaudeFable5_1,
              MaxTokens = 16000,
              Thinking = new BetaThinkingConfigAdaptive(),
              // 只有最後一個請求加入系統提示，刻意改變前綴
              System = turnIndex == userTurns.Length - 1 ? new("Answer briefly.") : null,
              Messages = messages,
              Betas = [AnthropicBeta.ThinkingBindingControls2026_08_01],
          }
      );
      messages.Add(new()
      {
          Role = Role.Assistant,
          Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
      });
      var thinkingBlocks = response.Content.Count(block => block.TryPickThinking(out _));
      var flagged = response.InputTransformations?.Count(transformation =>
          transformation.TryPickThinkingMismatchAllowed(out _)
      ) ?? 0;
      Console.WriteLine($"thinking blocks: {thinkingBlocks}, flagged: {flagged}");
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  userTurns := []string{
  	"How many positive integers below 500 have exactly 6 positive divisors?",
  	"How many of those are odd?",
  	"And how many of the odd ones are below 100?",
  }

  // messages 會隨輪次增長：每個 assistant 輪次都原封不動地依回傳內容送回
  messages := []anthropic.BetaMessageParam{}
  for i, userTurn := range userTurns {
  	messages = append(messages, anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock(userTurn)))
  	// 只有最後一個請求加入系統提示，刻意改變前綴
  	var system []anthropic.BetaTextBlockParam
  	if i == len(userTurns)-1 {
  		system = []anthropic.BetaTextBlockParam{{Text: "Answer briefly."}}
  	}
  	response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  		Model:     anthropic.ModelClaudeFable5_1,
  		MaxTokens: 16000,
  		Thinking: anthropic.BetaThinkingConfigParamUnion{
  			OfAdaptive: &anthropic.BetaThinkingConfigAdaptiveParam{},
  		},
  		System:   system,
  		Messages: messages,
  		Betas:    []anthropic.AnthropicBeta{anthropic.AnthropicBetaThinkingBindingControls2026_08_01},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	messages = append(messages, response.ToParam())
  	thinkingBlocks := 0
  	for _, block := range response.Content {
  		if block.Type == "thinking" {
  			thinkingBlocks++
  		}
  	}
  	flagged := 0
  	for _, transformation := range response.InputTransformations {
  		if transformation.Type == "thinking_mismatch_allowed" {
  			flagged++
  		}
  	}
  	fmt.Printf("thinking blocks: %d, flagged: %d\n", thinkingBlocks, flagged)
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaContentBlock;
  import com.anthropic.models.beta.messages.BetaInputTransformation;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaThinkingConfigAdaptive;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  import com.anthropic.models.messages.Model;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      List<String> userTurns = List.of(
          "How many positive integers below 500 have exactly 6 positive divisors?",
          "How many of those are odd?",
          "And how many of the odd ones are below 100?");

      // builder 的訊息清單會隨輪次增長：每個 assistant 輪次都會原封不動地依回傳內容送回
      MessageCreateParams.Builder conversation = MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5_1)
          .maxTokens(16000L)
          .thinking(BetaThinkingConfigAdaptive.builder().build())
          .addBeta(AnthropicBeta.THINKING_BINDING_CONTROLS_2026_08_01);

      for (int turnIndex = 0; turnIndex < userTurns.size(); turnIndex++) {
          if (turnIndex == userTurns.size() - 1) {
              // 只有最後一個請求會加入系統提示，刻意改變前綴
              conversation.system("Answer briefly.");
          }
          conversation.addUserMessage(userTurns.get(turnIndex));
          BetaMessage response = client.beta().messages().create(conversation.build());
          conversation.addMessage(response);
          long thinkingBlocks = response.content().stream()
              .filter(BetaContentBlock::isThinking)
              .count();
          long flagged = response.inputTransformations().stream()
              .flatMap(List::stream)
              .filter(BetaInputTransformation::isThinkingMismatchAllowed)
              .count();
          IO.println("thinking blocks: " + thinkingBlocks + ", flagged: " + flagged);
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaThinkingConfigAdaptive;
  use Anthropic\Beta\Messages\BetaThinkingMismatchAllowedInputTransformation;
  use Anthropic\Client;

  $client = new Client();

  $userTurns = [
      'How many positive integers below 500 have exactly 6 positive divisors?',
      'How many of those are odd?',
      'And how many of the odd ones are below 100?',
  ];

  // $messages 會隨輪次增長：每個 assistant 輪次都原封不動地依回傳內容送回
  $messages = [];
  foreach ($userTurns as $turnIndex => $userTurn) {
      $messages[] = ['role' => 'user', 'content' => $userTurn];
      $response = $client->beta->messages->create(
          model: 'claude-fable-5-1',
          maxTokens: 16000,
          thinking: BetaThinkingConfigAdaptive::with(),
          // 只有最後一個請求加入系統提示，刻意改變前綴
          system: $turnIndex === array_key_last($userTurns) ? 'Answer briefly.' : null,
          messages: $messages,
          betas: [AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01],
      );
      $messages[] = ['role' => 'assistant', 'content' => $response->content];
      $thinkingBlocks = array_filter($response->content, fn ($block) => $block->type === 'thinking');
      $flagged = array_filter(
          $response->inputTransformations ?? [],
          fn ($transformation) => $transformation instanceof BetaThinkingMismatchAllowedInputTransformation,
      );
      echo 'thinking blocks: ', count($thinkingBlocks), ', flagged: ', count($flagged), PHP_EOL;
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  user_turns = [
    "How many positive integers below 500 have exactly 6 positive divisors?",
    "How many of those are odd?",
    "And how many of the odd ones are below 100?"
  ]

  # messages 會隨輪次增長：每個 assistant 輪次都原封不動地傳回
  messages = []
  user_turns.each_with_index do |user_turn, turn_index|
    messages << {role: "user", content: user_turn}
    # 只有最後一個請求加入系統提示，刻意改變前綴
    system_param = (turn_index == user_turns.length - 1) ? {system_: "Answer briefly."} : {}
    response = client.beta.messages.create(
      model: "claude-fable-5-1",
      max_tokens: 16_000,
      thinking: {type: "adaptive"},
      messages: messages,
      betas: [Anthropic::AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01],
      **system_param
    )
    messages << {role: "assistant", content: response.content}
    thinking_blocks = response.content.count { |block| block.type == :thinking }
    flagged = (response.input_transformations || []).count do |transformation|
      transformation.type == :thinking_mismatch_allowed
    end
    puts "thinking blocks: #{thinking_blocks}, flagged: #{flagged}"
  end
  ```
</CodeGroup>

```text Output wrap
thinking blocks: 1, flagged: 0
thinking blocks: 1, flagged: 0
thinking blocks: 1, flagged: 2
```

第三個回應會標示較早回合中的每個思考區塊（在此次執行中每輪一個），因為新的系統提示位於所有區塊之前。模型仍然讀取了它們。

請以處理 `prefix_binding_mismatch` 捨棄的方式處理這些項目。編輯位於所列出的第一個區塊之前：將到該區塊 `path` 為止的 `system`、`tools` 和 `messages` 與上一次請求進行比對以找出編輯，然後以[在不編輯前綴的情況下進行變更](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#replace-prefix-edits)中對應的模式取代它。在新帳戶上，或在任何設定了 `prefix_mismatch_behavior` 的請求上，API 會改為拒絕請求或捨棄失敗的區塊。這些項目是強制執行時會移除內容的下限：使用 `"drop_block"` 時，失敗的區塊也會連帶移除該輪其餘的思考區塊，而移除一個區塊也可能使下一個區塊失敗。當 API 只記錄檢查結果時，它會個別判斷每個區塊，且只在該區塊本身失敗時才將其列出。

## 在不編輯前綴的情況下進行變更

每種常見的前綴編輯都有一種替代做法，能提供模型相同的資訊，同時保持較早的位元組不變，讓後續的思考維持有效。請在第一欄中找出您的程式碼目前所做的編輯：

| 不要這樣做                                       | 改用                                                                                                                                                                                                                                                                                                                                                  | Beta 標頭                                                                                                                                                                         |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 重建頂層 `system` 提示                            | [對話中途系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#new-instructions)                                                                                                                                                                                                                                            | 無                                                                                                                                                                               |
| 在每次請求時重新渲染第一則使用者訊息中的上下文（環境、日期、記憶、專案指示）      | 只渲染一次並原封不動地重新傳送。當內容變更時，[將新版本放在最新的回合中](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#changing-context)                                                                                                                                                                                                                 | 無                                                                                                                                                                               |
| 就地清除或縮短舊的 `tool_result` 內容，或重新編碼舊的圖片        | 在第一次傳送之前（而非之後）縮短工具結果或縮小圖片。若之後要清除舊結果，請使用 `clear_tool_uses_20250919` [在伺服器上修剪上下文](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#server-side-trimming)                                                                                                                                                                   | `context-management-2025-06-27`                                                                                                                                                 |
| 注入提醒並在下一次請求時將其刪除                            | [回合範圍系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#per-turn-reminders)（`clear_at: "next_user_message"`）                                                                                                                                                                                                         | `mid-conversation-system-clear-at-2026-08-21`                                                                                                                                   |
| 新增或移除 `tools` 中的項目                          | [`tool_addition` 和 `tool_removal` 區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#tool-changes)                                                                                                                                                                                                                     | `inline-tools-2026-09-15`（當工具來自透過 MCP 連接器連線的 MCP 伺服器時，加上 `mcp-client-2026-09-15`），或較舊的 `mid-conversation-tool-changes-2026-07-01`，其適用於 Claude API、Amazon Bedrock 和 Google Cloud |
| 變更頂層 `output_config.effort`（會讓快取重新開始，不影響思考） | [每則訊息的 `output_config`](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#effort-changes)                                                                                                                                                                                                                                 | `mid-conversation-output-config-2026-07-01`                                                                                                                                     |
| 在用戶端捨棄或摘要舊的回合                               | 使用[隨需壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-on-demand)保留最近的回合及其思考、其他伺服器端[壓縮或上下文編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#server-side-trimming)，或不保留過時思考的[用戶端壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#custom-compaction-on-the-client) | `compact-2026-09-04`                                                                                                                                                            |
| 位元組在請求之間會變更的圖片或文件 URL                       | [來自 Files API 的 `file_id`](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#files-by-id)，或 base64                                                                                                                                                                                                                        | 無                                                                                                                                                                               |

以上所有做法都假設您[完全依照回傳的樣子傳回助理回合](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#append-assistant-turns-exactly-as-returned)。對話中途系統訊息、回合範圍系統訊息和工具變更並非在所有模型上都可用：[對話中途的系統訊息與工具變更](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages)列出了接受它們的模型。如果您的程式碼服務多個模型，對於不接受它們的模型，請繼續編輯頂層 `system` 提示。

若要在 Claude API 上於單一請求中使用多個 beta，請將它們的名稱合併在一個 `anthropic-beta` 標頭中：

```text wrap
anthropic-beta: thinking-binding-controls-2026-08-01,mid-conversation-system-clear-at-2026-08-21,inline-tools-2026-09-15
```

提供這些 beta 的其他平台使用相同的名稱。若要在這些平台上傳送它們，請參閱[其他平台上的 beta 功能](https://platform.claude.com/docs/zh-TW/api/beta-headers#beta-features-on-other-platforms)。

### 完全依照回傳的樣子傳回助理回合

請儲存每個回應中的 `content` 陣列，並將其原封不動地作為助理回合傳回：包含每種區塊類型、依照接收順序，也包括 `thinking` 欄位為空的 `thinking` 區塊。會捨棄未知區塊類型、捨棄空欄位或重新排序區塊的序列化程式，會為之後的每一輪編輯前綴。

在 Claude Fable 5.1、Claude Opus 5.5、Claude Sonnet 5.5 和 Claude Haiku 5.5 上，`thinking` 欄位預設為空，而 `signature` 承載推理內容，因此略過空區塊的序列化程式會移除思考。如果它移除了所有思考區塊，不會有任何失敗，但模型會在每一輪都失去先前的推理。如果您自行解析串流，即使沒有收到任何思考文字，也請保留該區塊：它會開啟、在 `signature_delta` 事件中接收其 `signature`，然後關閉。以空 `signature` 傳回的區塊會失敗。

### 使用對話中途系統訊息加入指示

有些 harness 會在每個請求中重建頂層 `system` 提示，以帶入目前時間、token 預算、模式旗標或新發現的專案上下文。這會使對話中的每個思考區塊失效。請改為在工作階段開始時凍結 `system`。當有內容變更時，在 `messages` 中變更生效的位置附加一則 [`role: "system"` 訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages)：

```json
{
  "role": "system",
  "content": "The user switched the workspace to read-only mode. Do not write files until told otherwise."
}
```

模型會以系統提示的權威性看待此訊息，且其之前的所有內容都保持不變。在工具迴圈中，請將訊息放在 `tool_result` 使用者訊息之後，絕不要放在助理的 `tool_use` 與其 `tool_result` 之間（請參閱[限制](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages#limitations)）。一旦傳送，該訊息就成為之後思考的前綴的一部分：請在之後的請求中將其保留在原處。

### 將變動的上下文放在最新的回合中

有些 harness 會在第一則使用者訊息中放入環境區塊（工作目錄、分支、日期、記憶、專案指示），並在每個請求中重新渲染。當任何值變更時，`messages[0]` 就會變更，對話中的每個思考區塊都會失效。請只渲染該區塊一次，並依原樣重新傳送。當某個值變更時，請在最新的回合中說明：在您即將傳送的使用者訊息中加入文字區塊，或者如果變更來自身為營運者的您，則附加一則[對話中途系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#new-instructions)。

```json
{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "Environment update: the current branch is now release-2."
    },
    { "type": "text", "text": "Run the tests again." }
  ]
}
```

一旦傳送，該文字區塊就成為之後思考的前綴的一部分：請在之後的請求中將其保留在原處。

### 以輪次範圍系統訊息傳送每輪提醒

一種常見的前綴編輯是每回合提示：例如「將獨立的讀取操作一起請求」或「您已經有一段時間沒有向使用者更新進度了」這類由您的程式碼在每批工具結果之後附加的文字。為了避免提醒不斷累積，請將每則提示作為帶有 `clear_at: "next_user_message"` 的[對話中途系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages)傳送，並放在 `tool_result` 使用者訊息之後。`clear_at` 需要 beta 標頭 `mid-conversation-system-clear-at-2026-08-21`。以下 `messages` 陣列是兩次工具呼叫及其結果之後的請求。`messages[3]` 是上一個請求的提示，保留在原處，而 `messages[6]` 是此請求的副本：

```json
[
  { "role": "user", "content": "Fix the failing test." },
  {
    "role": "assistant",
    "content": [
      { "type": "thinking", "thinking": "", "signature": "..." },
      {
        "type": "tool_use",
        "id": "toolu_01",
        "name": "read_file",
        "input": { "path": "tests/test_auth.py" }
      }
    ]
  },
  {
    "role": "user",
    "content": [{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "..." }]
  },
  {
    "role": "system",
    "clear_at": "next_user_message",
    "content": "Request every independent read in one turn."
  },
  {
    "role": "assistant",
    "content": [
      { "type": "thinking", "thinking": "", "signature": "..." },
      {
        "type": "tool_use",
        "id": "toolu_02",
        "name": "read_file",
        "input": { "path": "src/auth.py" }
      }
    ]
  },
  {
    "role": "user",
    "content": [{ "type": "tool_result", "tool_use_id": "toolu_02", "content": "..." }]
  },
  {
    "role": "system",
    "clear_at": "next_user_message",
    "content": "Request every independent read in one turn."
  }
]
```

僅包含 `tool_result` 區塊的使用者訊息也算作「下一則使用者訊息」，因此 `messages[3]` 已被清除。它不會為模型所見的內容增加任何東西，也不會消耗輸入 token，但由於它仍在陣列中，`messages[4]` 中的思考會維持有效。`messages[6]` 是模型在此回合看到的副本。在之後的請求中，請將兩者都保留在原處，並在下一則 `tool_result` 訊息之後附加新的副本。

### 使用 `tool_addition` 和 `tool_removal` 新增或移除工具

在工作階段中途編輯 `tools` 陣列，會使保留的思考區塊失效。請讓陣列維持您第一次傳送時的內容。若要變更模型可以使用的工具，請附加一則帶有 `tool_addition` 或 `tool_removal` 區塊的 `role: "system"` 訊息。這些屬於[對話中途的工具變更](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes)，需要 beta 標頭 `inline-tools-2026-09-15`，此標頭可在 Claude API 上使用。較舊的 `mid-conversation-tool-changes-2026-07-01` 標頭仍適用於以參照方式指名工具的變更，可在 Claude API、Amazon Bedrock 和 Google Cloud 上使用。

您有兩種方式使用這些區塊：

* **預先宣告所有工具。** 在第一個請求中，將工作階段可能需要的所有工具放入 `tools`，並對模型暫時不應看到的工具設定 `defer_loading: true`。接著使用指定這些工具名稱的 `tool_addition` 和 `tool_removal` 區塊來開啟和關閉工具。
* **從快照開始，並隨時新增工具。** 在第一個請求中，將您已知的工具放入 `tools`。當出現新工具時，在 `tool_addition` 區塊中定義它，而不是編輯 `tools`。

無論哪種方式，`tools` 都不會改變，因此先前的思考仍然有效，提示快取也仍會命中，唯一的例外會在本節稍後說明。

例如，在模式切換後撤回危險的工具：

```json
{
  "role": "system",
  "content": [
    { "type": "tool_removal", "tool": { "type": "tool_reference", "name": "delete_branch" } },
    { "type": "text", "text": "Branch deletion is disabled for the rest of this session." }
  ]
}
```

若要開啟您以 `defer_loading: true` 宣告的工具，請附加一個指定其名稱的 `tool_addition` 區塊：

```json
{
  "role": "system",
  "content": [
    { "type": "tool_addition", "tool": { "type": "tool_reference", "name": "deploy" } },
    { "type": "text", "text": "Authentication succeeded. Deployment is now available." }
  ]
}
```

有時您無法預先宣告工具，因為您還不知道其結構描述：例如您的應用程式在執行階段發現的工具，或在第一個回合之後才連線的 MCP 伺服器。請在 `tool_addition` 區塊中定義它，而不要更動 `tools`。使用 `inline-tools-2026-09-15` 時，區塊的 `tool` 可以是 `{"type": "tool_definition", "definition": {...}}`，其中承載的項目與您原本會放入 `tools` 的項目相同：

```json
{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": {
          "name": "db_query",
          "description": "Run a read-only SQL query against the analytics database.",
          "input_schema": {
            "type": "object",
            "properties": { "sql": { "type": "string" } },
            "required": ["sql"]
          }
        }
      }
    }
  ]
}
```

新工具會出現在 `messages` 中，`tools` 不會變更，先前的思考也會維持有效。請在 `tools` 中至少保留一個未設定 `defer_loading: true` 的工具：如果其中的每個工具都是延遲載入的，您以這種方式定義的第一個工具會造成一次完整的提示快取未命中。

如果 API 透過 [MCP 連接器](https://platform.claude.com/docs/zh-TW/agents-and-tools/mcp-connector)為您連線到 MCP 伺服器，請同時傳送 `mcp-client-2026-09-15`。它涵蓋了 `mcp-client-2025-11-20` 的所有功能，因此請改為傳送它。區塊的 `definition` 接著可以是 `mcp_servers` 中所列伺服器的 `mcp_toolset`。當 API 必須擷取伺服器的工具清單時，回應會以該伺服器的 `mcp_tool_listing` 區塊開頭。請將其與助理回合的其餘部分一起原封不動地傳回，並在之後每個帶有該區塊的請求中持續傳送 `mcp-client-2026-09-15`。該區塊會將工具集固定為該清單，因此 API 不會為此再次聯絡伺服器。這些 MCP 連接器功能可在 Claude API 上使用。

若只有較舊的標頭，您仍可將工作階段中途得知的工具以 `defer_loading: true` 附加到 `tools`，然後透過 `tool_addition` 區塊提供它。這樣做是安全的，因為在 `tool_addition` 區塊參照延遲工具之前，前綴檢查會忽略該工具。新增未設定 `defer_loading: true` 的工具會變更前綴，並使先前的思考失效。

帶有這些區塊的 `role: "system"` 訊息會加入之後思考的前綴。請在之後的請求中將其保留在原處。

### 使用每則訊息的 `output_config` 變更 effort

在請求之間變更頂層的 `output_config.effort` 不會使思考失效，因為 effort 不是前綴的一部分。但變更頂層 effort 確實會重新開始提示快取。在模型和平台支援[每則訊息 effort](https://platform.claude.com/docs/zh-TW/build-with-claude/effort#change-effort-mid-conversation-beta) 的情況下，請改用它：附加一則 `content` 為空並帶有新等級的 `role: "system"` 訊息。它需要 beta 標頭 `mid-conversation-output-config-2026-07-01`。在 Claude Haiku 5.5 上，每則訊息 effort 可在 Claude API 和 Google Cloud 上使用，並且需要自適應思考。

```json
{ "role": "system", "content": [], "output_config": { "effort": "low" } }
```

新等級何時生效取決於您放置訊息的位置。若直接放在帶有新輸入的 `user` 訊息之後，它會從 Claude 對該訊息的回覆開始生效。若放在其他任何位置，例如 `assistant` 訊息之後，或僅包含 `tool_result` 區塊的 `user` 訊息之後，它會從下一則帶有新輸入的 `user` 訊息開始生效，因此已在進行中的工具迴圈會維持目前的等級直到那時。一旦傳送，該訊息就是 `messages` 的一部分，因此也是後續思考的前綴的一部分：在後續請求中請將其保留在原處，若要再次變更 effort，請再附加一則。

### 在伺服器上修剪上下文

另一種常見的前綴編輯是用戶端修剪：捨棄或摘要最舊的回合，並逐字保留最近的回合。保留回合的思考區塊是在被移除的歷史記錄仍存在時產生的，因此它們無法通過檢查。伺服器端的對應做法不算是編輯，因為檢查比較的是您所傳送的對話：

* [隨需壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-on-demand)（beta）會從另一個獨立請求傳回摘要，該請求可以[在背景執行](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-background)。您再以傳回的區塊取代它所摘要的訊息。檢查會接受這種替換，因此在符合[保留思考的條件](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid)時，您保留的回合及其思考可以維持有效。[請求摘要](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-on-demand#request-a-summary)示範了該請求，並列出所需的 beta 標頭。
* [在 token 閾值時壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-threshold)會在上下文接近您設定的閾值時，將較舊的回合摘要成一個壓縮區塊，受檢查的前綴則從該區塊重新開始。它的 [`instructions` 參數](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-threshold#custom-summarization-instructions)可接受您自訂的摘要提示，例如「保留每個股票代號、部位大小和陳述的假設」。
* [上下文編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/context-editing)會依規則清除舊的工具結果或舊的思考區塊，從最舊的開始。可用的策略為 `clear_tool_uses_20250919` 和 `clear_thinking_20251015`。

### 在用戶端進行壓縮

您仍然可以在用戶端進行「compaction」（壓縮）。如果您自行撰寫摘要，請不要傳回在改寫之前產生的思考區塊。如果由 API 透過隨需壓縮撰寫摘要，請參閱[保留的思考維持有效的條件](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid)，了解保留的思考在哪些情況下仍然有效。

#### 簡單壓縮（建議）

當對話變得太長時，將整個工作階段摘要為一則使用者訊息，並只傳送該訊息加上下一個指示。先前的內容都不會重播，因此沒有任何思考會無法通過檢查，模型會從摘要重新開始推理。

<Frame>
  ![Simple compaction（簡單壓縮）：請求 4 傳送完整歷史，每個助理回合都帶有思考；請求 5 傳送一則使用者訊息，其中包含回合 1 到 4 的摘要加上下一個指示，因此不會傳送任何先前的思考，也沒有任何內容需要檢查](https://platform.claude.com/docs/images/preserved-thinking-simple-compaction.svg)
</Frame>

```json
[
  {
    "role": "user",
    "content": "<summary of the session so far>\n\n<the next instruction>"
  }
]
```

Claude 模型是以此方案在長時程任務上訓練的，對大多數工作負載而言表現良好。

#### 保留尾部壓縮

保留尾部壓縮會摘要較舊的回合，並逐字保留最近的回合，因此模型仍能逐字看到最後幾次交流。如果您自己撰寫摘要，就會違反規則：被保留的助理回合仍帶有思考區塊，而這些區塊是在原始回合（而非摘要）位於其前方時產生的。這些區塊會失敗。

若要保留這些思考，請讓 API 透過隨需壓縮撰寫摘要。[保留最近輪次的壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-keep-recent-turns)說明了做法，而[保留的思考維持有效的條件](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid)列出了保留的思考何時仍然有效。

本節其餘部分涵蓋您自己撰寫的摘要。

<Frame>
  ![Keep-tail compaction（保留尾部壓縮）：歷史被替換為回合 1 和 2 的摘要，後接逐字的回合 3 到 5；助理回合 3 和 4 上的思考是在原始回合（而非摘要）之後產生的，因此會失敗；以 prefix\_mismatch\_behavior drop\_block 傳送的相同請求會成功，API 會捨棄這兩個區塊並在 input\_transformations 中列出它們](https://platform.claude.com/docs/images/preserved-thinking-keep-tail-compaction.svg)
</Frame>

修正方式：保持回合完全不變，並傳送 `prefix_mismatch_behavior: "drop_block"`。API 會捨棄過時的思考區塊，模型會讀取被保留回合的 `text` 和 `tool_use` 區塊，請求便會成功。

將壓縮後的歷史作為 `messages` 傳入，並在 `thinking` 設定上設定 `block_binding`。在以下範例中，`compacted_messages` 是您的壓縮步驟所產生的陣列：摘要訊息，後接完全按照 API 傳回內容保留的回合，包括 `thinking` 區塊：

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
    -d "{
      \"model\": \"claude-fable-5-1\",
      \"max_tokens\": 16000,
      \"thinking\": {
        \"type\": \"adaptive\",
        \"block_binding\": { \"prefix_mismatch_behavior\": \"drop_block\" }
      },
      \"messages\": $COMPACTED_MESSAGES
    }"
  ```

  ```bash CLI
  ant beta:messages create --beta thinking-binding-controls-2026-08-01 <<YAML
  model: claude-fable-5-1
  max_tokens: 16000
  thinking:
    type: adaptive
    block_binding:
      prefix_mismatch_behavior: drop_block
  messages: $COMPACTED_MESSAGES
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  # compacted_messages：先是摘要訊息，接著是依原樣傳回的保留輪次
  response = client.beta.messages.create(
      model="claude-fable-5-1",
      max_tokens=16000,
      thinking={
          "type": "adaptive",
          "block_binding": {"prefix_mismatch_behavior": "drop_block"},
      },
      messages=compacted_messages,
      betas=["thinking-binding-controls-2026-08-01"],
  )

  print(response.input_transformations)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  // compactedMessages：先是摘要訊息，接著是依原樣回傳的保留輪次
  const response = await client.beta.messages.create({
    model: "claude-fable-5-1",
    max_tokens: 16000,
    thinking: {
      type: "adaptive",
      block_binding: { prefix_mismatch_behavior: "drop_block" }
    },
    messages: compactedMessages,
    betas: ["thinking-binding-controls-2026-08-01"]
  });

  console.log(response.input_transformations);
  ```

  ```csharp C#
  AnthropicClient client = new();

  // compactedMessages：先是摘要訊息，接著是依原樣傳回的保留輪次
  var response = await client.Beta.Messages.Create(
      new()
      {
          Model = Model.ClaudeFable5_1,
          MaxTokens = 16000,
          Thinking = new BetaThinkingConfigAdaptive
          {
              BlockBinding = new()
              {
                  PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
              },
          },
          Messages = compactedMessages,
          Betas = [AnthropicBeta.ThinkingBindingControls2026_08_01],
      }
  );

  Console.WriteLine(response.InputTransformations?.Count ?? 0);
  ```

  ```go Go
  client := anthropic.NewClient()

  // compactedMessages：先是摘要訊息，接著是依原樣傳回的保留輪次
  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeFable5_1,
  	MaxTokens: 16000,
  	Thinking: anthropic.BetaThinkingConfigParamUnion{
  		OfAdaptive: &anthropic.BetaThinkingConfigAdaptiveParam{
  			BlockBinding: anthropic.BetaThinkingBlockBindingParam{
  				PrefixMismatchBehavior: anthropic.BetaThinkingPrefixMismatchBehaviorDropBlock,
  			},
  		},
  	},
  	Messages: compactedMessages,
  	Betas:    []anthropic.AnthropicBeta{anthropic.AnthropicBetaThinkingBindingControls2026_08_01},
  })
  if err != nil {
  	log.Fatal(err)
  }

  fmt.Println(len(response.InputTransformations))
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaThinkingBlockBinding;
  import com.anthropic.models.beta.messages.BetaThinkingConfigAdaptive;
  import com.anthropic.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  import com.anthropic.models.messages.Model;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      // compactedMessages：先是摘要訊息，接著是依原樣回傳的保留輪次
      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5_1)
          .maxTokens(16000L)
          .thinking(BetaThinkingConfigAdaptive.builder()
              .blockBinding(BetaThinkingBlockBinding.builder()
                  .prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
                  .build())
              .build())
          .messages(compactedMessages)
          .addBeta(AnthropicBeta.THINKING_BINDING_CONTROLS_2026_08_01)
          .build();

      BetaMessage response = client.beta().messages().create(params);

      IO.println(response.inputTransformations());
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaThinkingBlockBinding;
  use Anthropic\Beta\Messages\BetaThinkingConfigAdaptive;
  use Anthropic\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
  use Anthropic\Client;

  $client = new Client();

  // $compactedMessages：先是摘要訊息，接著是依原樣傳回的保留輪次
  $response = $client->beta->messages->create(
      model: 'claude-fable-5-1',
      maxTokens: 16000,
      thinking: BetaThinkingConfigAdaptive::with(
          blockBinding: BetaThinkingBlockBinding::with(
              prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
          ),
      ),
      messages: $compactedMessages,
      betas: [AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01],
  );

  var_dump($response->inputTransformations);
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  # compacted_messages：先是摘要訊息，接著是依原樣傳回的保留輪次
  response = client.beta.messages.create(
    model: "claude-fable-5-1",
    max_tokens: 16_000,
    thinking: {
      type: "adaptive",
      block_binding: {prefix_mismatch_behavior: "drop_block"}
    },
    messages: compacted_messages,
    betas: [Anthropic::AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01]
  )

  puts response.input_transformations
  ```
</CodeGroup>

回應會照常攜帶新的助理回合，並為每個被捨棄的區塊附上一個 `input_transformations` 項目。以圖中的歷史為例，就是助理回合 3 和 4 上的思考：

```json
{
  "input_transformations": [
    {
      "type": "thinking_dropped",
      "path": "messages.2.content.0",
      "reason": "prefix_binding_mismatch"
    },
    {
      "type": "thinking_dropped",
      "path": "messages.4.content.0",
      "reason": "prefix_binding_mismatch"
    }
  ]
}
```

只要這兩個回合仍留在歷史中，就請在後續請求中持續傳送 `"drop_block"`。模型從此請求開始產生的思考會位於摘要之後，並保持有效。如果您不想依賴 beta 標頭，替代方案是在建立壓縮歷史時，自行從被保留的助理回合中移除 `thinking` 和 `redacted_thinking` 區塊。

#### 背景（非同步）壓縮

背景壓縮會在對話持續進行時，於關鍵路徑之外建立摘要，並在幾個請求之後將其替換進來。若要保留這段期間產生的思考，請讓 API 透過隨需壓縮撰寫摘要。[在背景中進行壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-background)列出了步驟，而這些思考與被保留的最近回合一樣，在符合相同的[保留思考的條件](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid)時仍然有效。

您自行建立的摘要會以與保留尾部壓縮相同的方式違反規則，只是有所延遲：在建立摘要期間產生的每個助理回合所帶有的思考都早於替換，而一旦摘要替換進來，這些思考就會全部失敗。如果您使用自行建立的摘要，請將替換視同保留尾部壓縮處理，從替換開始傳送 `"drop_block"`，或改為同步壓縮。

#### 不適用於保留思考的模式

* **從中間刪除回合。** 移除個別回合會使其後的每個 thinking 區塊失效，任何壓縮方案都無法避免這一點。如果您刪除回合是為了變更指示，請改為附加一則[對話中途系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#new-instructions)。若要選擇性地移除舊的工具結果或舊的思考，請使用伺服器端的[上下文編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/context-editing)。
* **在工具回合進行中壓縮。** 請勿在助理回合的 `tool_use` 與回應它的 `tool_result` 之間進行壓縮。請將該助理回合連同完整的思考一起傳回，讓模型能帶著其推理完成該回合。請參閱[保留 thinking 區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/thinking#preserving-thinking-blocks)。

### 以 ID 參照檔案，而非使用內容會變動的 URL

對於具有 `url` 來源的 `image` 或 `document` 區塊，檢查涵蓋的是擷取到的位元組，而非 URL 字串。內容會變動的 URL 會使後續的思考失效：例如「最新螢幕截圖」端點，或有人在回合之間編輯的文件。指向同一檔案的輪替簽署 URL 則不會。對於您在多個回合中參照的內容，請使用 [Files API](https://platform.claude.com/docs/zh-TW/build-with-claude/files) 上傳一次並使用 `file_id`，或傳送 base64。

### 函式庫、代理伺服器與閘道

函式庫、代理伺服器或閘道位於他人的歷史記錄與 API 之間，因此其自身的改寫都算作編輯，而其使用者無法看到或修正這些改寫。

* **原樣傳遞您無法辨識的內容。** 將呼叫端的 `anthropic-beta` 值和 `thinking.block_binding` 原封不動地轉送，並將 `input_transformations` 傳回給呼叫端。會拒絕未知鍵的選項結構描述，會讓您的使用者無法選擇 `"drop_block"`。
* **將 `role: "system"` 訊息保留在呼叫端放置的位置。** 將其移入頂層 `system` 欄位會變更該請求的 `system`，並使對話中的每個 thinking 區塊失效。
* **若要在某個請求中關閉工具使用，請傳送 `tool_choice: {"type": "none"}`。** 請勿移除 `tools`。
* **不要隱藏 400 錯誤。** 如果您的程式碼攔截了該錯誤、移除思考並代替呼叫端重試，請記錄此行為：呼叫端的歷史記錄仍然被編輯過，而模型在之後的每個請求中都會失去先前的推理。

## 常見問題

<AccordionGroup>
  <Accordion title="我需要新帳戶才能測試保留思考嗎？">
    不需要。傳送 `thinking-binding-controls-2026-08-01` beta 標頭並設定 `thinking.block_binding.prefix_mismatch_behavior`。設定此欄位會讓該請求選擇加入強制檢查，無論帳戶建立多久。`"error"` 會以與新帳戶相同的 400 錯誤拒絕被編輯過的歷史，而 `"drop_block"` 會讓請求通過，並在 `input_transformations` 中列出被捨棄的內容。若要在不強制檢查的情況下找出較舊帳戶的前綴編輯，請傳送標頭但不設定該欄位：失敗的區塊仍會傳給模型，而 `input_transformations` 會將它們列為 `thinking_mismatch_allowed`。請參閱[檢查您的程式碼是否編輯了前綴](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#how-to-tell-whether-your-integration-is-impacted)。
  </Accordion>

  <Accordion title="如果思考區塊之前的任何內容發生變化，即使只是一個工具描述，對話就無法使用了嗎？">
    不會。失敗的是歷史中位於您變更之處之後的既有思考，而您可以選擇如何處理它。使用 `prefix_mismatch_behavior: "drop_block"` 時，API 會捨棄這些區塊，請求會成功：模型會在沒有該推理的情況下回答該回合，而提示快取會從編輯處重新開始。使用預設的 `"error"` 時，API 會以 400 錯誤拒絕請求，直到您復原編輯或以 `"drop_block"` 重新傳送。請參閱[API 如何處理失效的區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#mismatch-behavior)。[哪些變更算是編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#what-counts-as-an-edit)列出了哪些變更會有影響。
  </Accordion>

  <Accordion title="在請求之間變更 effort 或其他思考設定，會使先前的思考失效嗎？">
    不會。`output_config.effort`、`max_tokens` 和 `thinking` 設定不屬於受檢查的前綴，前綴只涵蓋 `system`、`tools` 和 `messages`。頂層 effort 變更會使大部分提示快取失效。在模型和平台支援[每則訊息 effort](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#effort-changes) 的情況下，每則訊息的 effort 變更會保留提示快取，並作為新的 effort 等級使用，直到再次變更為止。
  </Accordion>

  <Accordion title="我的工具清單會在工作階段中途變更。如何避免使對話失效？">
    不要編輯 `tools`。在工作階段開始時宣告完整的工具集，將尚未可用的工具標記為 `defer_loading: true`，並使用 `tool_addition` 和 `tool_removal` 區塊提供或撤回它們。如果您只在工作階段中途才得知某個工具的結構描述，請在 `tool_addition` 區塊內定義它（`inline-tools-2026-09-15`，若是 API 的 MCP 連接器所連線的伺服器，則再加上 `mcp-client-2026-09-15`），並保持 `tools` 不變。攜帶這些區塊的 `role: "system"` 訊息會成為後續思考前綴的一部分，因此之後請不要移動、改寫或刪除它們。請參閱[使用 `tool_addition` 和 `tool_removal` 新增或移除工具](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#tool-changes)。
  </Accordion>

  <Accordion title="我透過摘要較舊的回合並逐字保留最近的回合來進行壓縮。這樣仍然可行嗎？">
    可以，前提是由 API 撰寫摘要。[隨需壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-on-demand)（beta 標頭 `compact-2026-09-04`）會將較舊的回合摘要為一個已簽署的區塊，由您傳送以取代這些回合。最近的回合在符合[保留思考的條件](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid)下會保留其思考。

    如果您自己撰寫摘要，被保留回合的思考將無法通過檢查，因為這些區塊是針對您已替換的歷史產生的。請從您保留的回合中移除 `thinking` 和 `redacted_thinking` 區塊，並保留其 `text` 和 `tool_use` 區塊，或傳送 `prefix_mismatch_behavior: "drop_block"` 讓 API 捨棄它們。簡單壓縮不會留下任何會失敗的思考，是建議的做法：一則摘要訊息加上下一個使用者回合，不重播任何先前的回合。伺服器端的[壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/compaction)和[上下文編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/context-editing)不算是編輯。請參閱[在用戶端進行壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#custom-compaction-on-the-client)。
  </Accordion>

  <Accordion title="如何處理在工作階段中途變更的指示檔案，例如 AGENTS.md 或 CLAUDE.md？">
    在工作階段開始時載入它們一次，並保持頂層的 `system` 提示和 `tools` 固定不變。當檔案變更時，請在 `messages` 中的該時間點附加新版本，而不是編輯原始內容。對於來自您這位營運者的指示，請使用[對話中途系統訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages)。對於您視為不受信任、不應具有系統提示權限的檔案文字，請改為將內容放在下一個 `user` 回合中。請參閱[使用對話中途系統訊息加入指示](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#new-instructions)和[限制](https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages#limitations)。
  </Accordion>

  <Accordion title="我可以在重新啟動後或隔天繼續已儲存的工作階段嗎？">
    可以。繼續的工作階段就是一般的後續請求：`system`、`tools` 和先前的 `messages` 必須與您上次傳送的內容相同。JSON 格式和鍵的順序無關緊要；重要的是值。請完整保存您傳送和接收的內容，並重播它們：渲染後的系統提示、工具定義，以及按傳回內容保存的每個助理回合。不要從之後可能已變更的輸入重新渲染，例如日期、更新過的指示檔案或新的工具版本。任何新內容都應放在附加的訊息中。請參閱[完全依照回傳的樣子傳回助理回合](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#append-assistant-turns-exactly-as-returned)。
  </Accordion>

  <Accordion title="已儲存的工作階段現在每個請求都失敗。如何讓它恢復運作？">
    儲存的歷史中含有編輯，因此重播它不可能成功。從現在起以 `prefix_mismatch_behavior: "drop_block"` 傳送該工作階段，或一次性移除其 `thinking` 和 `redacted_thinking` 區塊後繼續。在 Claude Sonnet 5.5 和 Claude Haiku 5.5 上，`block_binding` 僅適用於 `thinking: {"type": "adaptive"}`。若使用 `between_tools`（Claude Sonnet 5.5），或在 Claude Haiku 5.5 上使用 `thinking: {"type": "disabled"}`，請保持歷史僅附加，或從被編輯的回合開始移除思考區塊。只要之前的內容不再變更，模型從該點開始產生的思考就會保持有效。接著請找出該編輯，讓新的工作階段不會再遇到它。請參閱[在程式碼中處理錯誤](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#handle-the-error-in-code)。
  </Accordion>

  <Accordion title="我的執行框架可以將某個回合路由到非 Claude 模型。這些回合會使 Claude 先前的思考失效嗎？">
    不會，前提是它們附加在既有歷史之後，且先前的內容沒有任何變更：不含思考區塊的助理訊息就和其他附加的訊息一樣。請將另一個模型的輸出作為 `text` 和 `tool_use` 內容傳送。
  </Accordion>

  <Accordion title="我可以將一段對話的推理帶入新的對話嗎？">
    無法帶入不同的對話。思考區塊只有在緊接於產生它的確切 `system`、`tools` 和 `messages` 之後時才可使用。在分岔點之前原封不動重播該歷史的分支會保留其思考。從其他任何內容開始的對話都無法使用它，因此請從任務狀態的摘要開始該對話，如同[簡單壓縮](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#custom-compaction-on-the-client)：目標、已做的決定、目前為止的檔案和結果，以及下一步。來自 Claude Sonnet 5.5 和 Claude Haiku 5.5 的思考區塊也無法從其他帳戶重複使用（請參閱[思考區塊僅限產生它們的帳戶使用](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#account-bound-thinking)）。
  </Accordion>
</AccordionGroup>

## 後續步驟

<CardGroup cols={2}>
  <Card title="思考疑難排解" icon="hammer" href="https://platform.claude.com/docs/zh-TW/build-with-claude/thinking-troubleshooting">
    診斷並修正最常見的思考失敗：設定 400 錯誤、空白或遺失的思考區塊、max\_tokens 停止，以及快取未命中。
  </Card>

  <Card title="對話中途系統訊息與工具變更" icon="messages" href="https://platform.claude.com/docs/zh-TW/build-with-claude/mid-conversation-system-messages">
    在對話進行到一半時變更系統指令或工具可用性，而不使其之前的快取前綴失效。
  </Card>

  <Card title="壓縮" icon="stack" href="https://platform.claude.com/docs/zh-TW/build-with-claude/compaction">
    伺服器端上下文壓縮，用於管理接近上下文視窗限制的長對話。
  </Card>

  <Card title="提示快取" icon="database" href="https://platform.claude.com/docs/zh-TW/build-with-claude/prompt-caching">
    以 `cache_control` 快取提示前綴以降低成本與延遲，可使用自動快取或具 5 分鐘或 1 小時 TTL 的明確斷點。
  </Card>
</CardGroup>
