Claude Platform Docs
Messages壓縮

壓縮與保留思考

在具有保留思考的模型上,隨需壓縮後保留的輪次中的思考區塊何時維持有效,以及如何檢查。

除非您會將「thinking block」(思考區塊)傳回給具有「preserved thinking」(保留思考)的模型,並在「compaction block」(壓縮區塊)之後保留輪次,否則您可以略過本頁。「Kept turns」(保留的輪次)是指緊接在該區塊之後的輪次:您未納入壓縮請求的最近輪次,如保留最近輪次的壓縮所述;或是在撰寫摘要期間送達的輪次,如在背景中進行壓縮所述。

具有保留思考的模型會將先前的思考區塊與產生它們的對話進行比對檢查。摘要會取代該對話的一部分,但當摘要是由 API 撰寫時,檢查會接受這項替換,因此保留輪次中的思考可以維持有效。

保留的思考維持有效的條件

保留輪次中的思考區塊在以下所有條件都成立時維持有效:

  • 壓縮請求在具有保留思考的模型上執行。 此條件涵蓋自思考區塊產生以來的每一個壓縮請求,而不僅是最近的一個。滿足此條件的一種方式,是將每個壓縮請求都傳送給對話所使用的模型。
  • 保留的輪次直接接在被摘要的訊息之後,且您原封不動地傳送它們。 請完全依照歷史記錄中的樣子傳送每則保留的訊息。不要在最後一則被摘要的訊息與第一則保留的訊息之間略過或新增任何訊息。第一則保留的訊息也必須與最後一則被摘要的訊息具有不同的角色,且不能是對話中途的 role: "system" 訊息。否則,API 會將其合併到最後一則被摘要的訊息中。讓第一則保留訊息正確的一種方式,是精確地壓縮您已傳送過的某個請求的 messages。如此一來,保留的輪次便會從 Claude 對該請求的回覆開始。
  • system 以及未標記 defer_loading: truetools 不變。 它們在壓縮請求上與在產生保留思考的請求上相同,並在後續的請求中保持相同。變更系統提示或工具說明如何安全地變更它們。

如果某個條件不成立,壓縮時不會有任何失敗,而且無論如何 API 都會在後續請求中接受該區塊。失敗會發生在第一個於 API 強制執行檢查之處傳送保留思考的後續請求:預設為 400 錯誤,或者如果請求將 thinking.block_binding.prefix_mismatch_behavior 設為 "drop_block",則會捨棄思考區塊。在 Message Batches API 中,未設定此欄位的項目不會失敗。在預設套用檢查的情況下,API 會改為捨棄這些區塊。API 如何處理失效的區塊說明這兩種結果,而API 何時強制執行檢查則說明哪些請求會受到檢查。

再次壓縮而不破壞較舊的思考

您可以再次壓縮並保留輪次:新區塊涵蓋舊摘要以及壓縮請求中其後的每則訊息,而您未納入該請求的任何輪次,都是新區塊的保留輪次。

保留的思考維持有效的條件中的第一項會計入自思考區塊產生以來的每一次壓縮,因此您在兩次壓縮中都保留的輪次,需要這兩次壓縮都在具有保留思考的模型上執行。

在思考區塊產生之前進行的壓縮不會對其造成影響。在區塊就位後產生的思考會綁定到該區塊,並在符合條件的後續壓縮中維持有效。

變更系統提示或工具

後續請求可以使用與壓縮請求不同的 system、不同的 tools 或不同的模型,API 仍會接受該區塊。這類變更可能會使保留輪次中的思考失效,但不會有其他影響。

若要變更 systemtools 而不使任何保留的思考失效,請先壓縮整個對話,使沒有任何輪次被保留。然後在下一個請求中變更它們。

若要新增指示或變更可用的工具而不動到 systemtools,請將變更附加到 messages,如在不編輯前綴的情況下進行變更所述。

被摘要輪次中的對話中途系統訊息也會被摘要,因此它們的文字指示在替換後便不再適用。若要讓其中某項持續生效,請在保留輪次之後的第一個新 user 輪次之後,緊接著以 role: "system" 訊息再次陳述。當壓縮請求也帶有 inline-tools-2026-09-15 時,這些輪次中的工具變更會自動延續:傳回的區塊會在其 tool_changes 欄位中記錄它們的淨效果,因此請原封不動地傳回該區塊。如果區塊沒有 tool_changes 欄位,請以相同方式重新陳述這些工具變更。放在區塊與保留輪次之間的系統訊息會破壞它們的思考。

檢查保留的思考是否成立

壓縮回應不會告訴您保留的思考是否成立,替換後的第一個請求才會。若要在測試中檢查:

  1. 在開啟思考的情況下進行一段簡短的對話。使用 API 會執行檢查的模型(請參閱API 何時強制執行檢查),並在每個步驟都使用該模型,因為無法讀取思考區塊的模型會在不產生錯誤的情況下捨棄它。
  2. 壓縮較舊的輪次,並保留至少一個包含思考區塊的輪次。
  3. 傳送下一個請求,依序放入區塊、保留的輪次,然後是新的 user 訊息,並將 thinking.block_binding.prefix_mismatch_behavior 設為 "error"
  4. 讀取結果。input_transformations 陣列為空的 200 回應,表示沒有任何思考區塊未通過檢查或被捨棄。指出區塊綁定到不同對話的 400 錯誤,則表示有區塊未通過。錯誤訊息的開頭是第一個未通過檢查之區塊的路徑,API 如何處理失效的區塊會完整顯示該訊息。

prefix_mismatch_behavior 欄位除了需要compact-2026-09-04「beta header」(beta 標頭)之外,還需要 thinking-binding-controls-2026-08-01 beta 標頭。在預設未開啟檢查的帳戶上,設定此欄位也會讓請求選擇加入檢查。

以下程式會執行這四個步驟。它會印出保留的輪次包含多少個思考區塊,以及 input_transformations 有多少個項目;沒有任何項目表示保留的思考成立:

from anthropic.types.beta import BetaMessageParam, BetaThinkingConfigParam

client = anthropic.Anthropic()

# Claude Fable 5.1 是第一個會將回傳的思考內容與對話進行比對檢查的模型。
MODEL = "claude-fable-5-1"
BETAS = ["compact-2026-09-04", "thinking-binding-controls-2026-08-01"]
SYSTEM = "You help plan a recipe app's release. Keep answers short."
# 設為 "error" 時,未通過檢查的思考區塊會使請求失敗並回傳 400。
THINKING: BetaThinkingConfigParam = {
    "type": "adaptive",
    "block_binding": {"prefix_mismatch_behavior": "error"},
}

# 1. 在啟用思考的情況下進行一段簡短對話。
history: list[BetaMessageParam] = [
    {"role": "user", "content": "What are the main entities in the app's data model?"}
]
first = client.beta.messages.create(
    model=MODEL,
    max_tokens=8192,
    system=SYSTEM,
    betas=BETAS,
    thinking=THINKING,
    messages=history,
)
history += [
    {"role": "assistant", "content": first.content},
    {
        "role": "user",
        "content": "Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?",
    },
]
second = client.beta.messages.create(
    model=MODEL,
    max_tokens=8192,
    system=SYSTEM,
    betas=BETAS,
    thinking=THINKING,
    messages=history,
)
history.append({"role": "assistant", "content": second.content})
thinking_blocks = sum(block.type == "thinking" for block in second.content)
print(f"Thinking blocks in the kept turn: {thinking_blocks}")

# 2. 摘要第一輪對話。第二輪對話不納入請求中。
summary = client.beta.messages.create(
    model=MODEL,
    max_tokens=4096,
    system=SYSTEM,
    betas=BETAS,
    thinking=THINKING,
    messages=history[:2],
    compaction={"type": "summarize"},
)
if summary.stop_reason != "compaction":
    raise SystemExit(f"No summary: {summary.stop_reason}")

# 3. 將該區塊放在保留的對話輪次之前,並提出下一個問題。
history = [
    {"role": "assistant", "content": summary.content},
    *history[2:],
    {"role": "user", "content": "Which day should the release go out?"},
]
third = client.beta.messages.create(
    model=MODEL,
    max_tokens=8192,
    system=SYSTEM,
    betas=BETAS,
    thinking=THINKING,
    messages=history,
)

# 4. 若回傳 200 且沒有區塊被捨棄,表示保留的思考內容有效。
print(f"Dropped thinking blocks: {len(third.input_transformations)}")
Output
Thinking blocks in the kept turn: 1
Dropped thinking blocks: 0

在正式環境中,"drop_block" 可在條件不成立時讓請求持續成功,並在 input_transformations 中以 reason: "prefix_binding_mismatch" 回報每個被捨棄的區塊。path 落在保留輪次中的項目,表示該輪次的思考未能成立。API 如何處理失效的區塊說明哪些內容會被捨棄,以及如何針對此情況發出警示。

Compatibility

Supported models
  • Fable 5 and 5.1
  • Mythos 5, 5.1, and Preview
  • Opus 4.6, 4.7, 4.8, 5, and 5.5
  • Sonnet 4.6 and 5
Supported platforms
  • Claude APIBeta
  • Claude Platform on AWSBeta
  • Google CloudBeta
  • Microsoft FoundryBeta

Was this page helpful?