コンパクションと思考の保持
思考の保持に対応したモデルで、オンデマンドコンパクション後に残したターン内の思考ブロックが有効なままとなる条件と、その確認方法。
「preserved thinking」(思考の保持)に対応したモデルに「thinking blocks」(思考ブロック)を送り返し、かつ「compaction」(コンパクション)ブロックの後にターンを残す場合を除き、このページは読み飛ばしてください。「kept turns」(残したターン)とは、ブロックの後に続くターンのことです。直近のターンを保持するコンパクションのようにコンパクションリクエストから除外した最近のターン、またはバックグラウンドでのコンパクションのように要約の作成中に届いたターンがこれにあたります。
思考の保持に対応したモデルは、以前の思考ブロックを、それを生成した会話と照合してチェックします。要約はその会話の一部を置き換えますが、APIが要約を作成した場合、チェックはその置き換えを受け入れるため、残したターン内の思考は有効なままでいられます。
残した思考が有効なままとなる条件
残したターン内の思考ブロックは、次のすべてが成り立つ間、有効なままとなります。
- コンパクションリクエストが思考の保持に対応したモデルで実行されること。 この条件は、最新のものだけでなく、思考ブロックが生成されて以降のすべてのコンパクションリクエストに適用されます。これを満たす方法の1つは、すべてのコンパクションリクエストを、会話で使用しているモデルに送信することです。
- 残したターンが要約されたメッセージの直後に続き、それらを変更せずに送信すること。 残した各メッセージは、履歴にあるとおりそのまま送信してください。最後の要約されたメッセージと最初の残したメッセージの間で、メッセージを省略したり追加したりしないでください。また、最初の残したメッセージは最後の要約されたメッセージとは異なるロールである必要があり、会話途中の
role: "system"メッセージであってはなりません。そうでない場合、APIはそれを最後の要約されたメッセージにマージします。最初の残したメッセージを正しく設定する方法の1つは、すでに送信したリクエストのmessagesをそのままコンパクションすることです。その場合、残したターンはそのリクエストに対するClaudeの返信から始まります。 systemと、defer_loading: trueが指定されていないtoolsが変更されないこと。 これらは、コンパクションリクエストと、残した思考を生成したリクエストとで同じであり、その後に続くリクエストでも同じままです。システムプロンプトまたはツールを変更するでは、それらを安全に変更する方法を説明しています。
条件が満たされない場合でも、コンパクション時には何も失敗せず、いずれにしてもAPIは後続のリクエストでブロックを受け入れます。失敗が発生するのは、APIがチェックを適用する状況で残した思考を送信する最初の後続リクエストです。デフォルトでは400エラーとなり、リクエストで thinking.block_binding.prefix_mismatch_behavior を "drop_block" に設定している場合は思考ブロックが破棄されます。Message Batches APIでは、このフィールドを未設定のままにしたアイテムは失敗しません。チェックがデフォルトで適用される場合、APIは代わりにブロックを破棄します。無効なブロックに対するAPIの処理では両方の結果を説明しており、APIがチェックを適用する条件ではどのリクエストがチェックされるかを説明しています。
古い思考を壊さずに再度コンパクションする
ターンを残したまま再度コンパクションできます。新しいブロックは、古い要約と、コンパクションリクエスト内でそれに続くすべてのメッセージをカバーし、そのリクエストから除外したターンは新しいブロックの残したターンになります。
残した思考の条件の1つ目は、思考ブロックが生成されて以降のすべてのコンパクションを対象とするため、2回のコンパクションを通じて残したターンでは、両方のコンパクションが思考の保持に対応したモデルで実行されている必要があります。
思考ブロックが生成される前のコンパクションは、その思考ブロックには影響しません。ブロックが配置された後に生成された思考はそのブロックに紐付けられ、条件を満たす後続のコンパクションを通じて有効なままとなります。
システムプロンプトまたはツールを変更する
後続のリクエストでは、コンパクションリクエストとは異なる system、異なる tools、または異なるモデルを使用でき、その場合でもAPIはブロックを受け入れます。このような変更は残したターン内の思考を無効にする可能性がありますが、それ以外の影響はありません。
残した思考を無効にせずに system または tools を変更するには、まず会話全体をコンパクションして、ターンが残らないようにします。その後、次のリクエストでそれらを変更します。
system や tools に手を加えずに指示を追加したり利用可能なツールを変更したりするには、プレフィックスを編集せずに変更を加えるで説明されているように、変更を messages に追加します。
要約されたターン内にある会話途中のシステムメッセージも要約されるため、それらのテキストによる指示は置き換え後に適用されなくなります。いずれかを引き続き有効にするには、残したターンに続く最初の新しい user ターンの直後に、role: "system" メッセージで再度記述してください。コンパクションリクエストが inline-tools-2026-09-15 も含む場合、それらのターン内のツールの変更は自動的に引き継がれます。返されたブロックはその正味の効果を tool_changes フィールドに記録するため、ブロックを変更せずに送り返してください。ブロックに tool_changes フィールドがない場合は、それらのツールの変更を同じ方法で再度記述してください。ブロックと残したターンの間に配置されたシステムメッセージは、それらのターンの思考を壊します。
残した思考が保持されたことを確認する
コンパクションのレスポンスからは、残した思考が有効かどうかはわかりません。それがわかるのは置き換え後の最初のリクエストです。テストで確認するには、次の手順を実行します。
- 思考を有効にして短い会話を行います。APIがチェックを実行するモデルを使用し(APIがチェックを適用する条件を参照)、すべてのステップでそのモデルを使用してください。思考ブロックを読み取れないモデルは、エラーを出さずにそのブロックを破棄するためです。
- 古いターンをコンパクションし、思考ブロックを含むターンを少なくとも1つ残します。
- 次のリクエストを送信します。ブロックを先頭に、次に残したターン、その後に新しい
userメッセージを配置し、thinking.block_binding.prefix_mismatch_behaviorを"error"に設定します。 - 結果を確認します。
input_transformations配列が空の200レスポンスは、チェックに失敗した思考ブロックや破棄された思考ブロックがなかったことを意味します。ブロックが別の会話に紐付けられていることを示す400エラーは、そのようなブロックがあったことを意味します。メッセージは最初に失敗したブロックのパスから始まり、無効なブロックに対するAPIの処理にその全文が示されています。
prefix_mismatch_behavior フィールドには、compact-2026-09-04 ベータヘッダーに加えて thinking-binding-controls-2026-08-01 ベータヘッダーが必要です。このフィールドを設定すると、チェックがデフォルトで有効になっていないアカウントでも、そのリクエストはチェックの対象になります。
次のプログラムは4つのステップを実行します。残したターンに含まれる思考ブロックの数と、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. 最初のターンを要約します。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)}")Thinking blocks in the kept turn: 1
Dropped thinking blocks: 0本番環境では、"drop_block" を使用すると、条件が満たされない場合でもリクエストは成功し続け、破棄された各ブロックが reason: "prefix_binding_mismatch" とともに input_transformations で報告されます。path が残したターン内にあるエントリは、そのターンの思考が保持されなかったことを意味します。無効なブロックに対するAPIの処理では、何が破棄されるかと、それに対してアラートを出す方法を説明しています。
Compatibility
| Supported models |
|
|---|---|
| Supported platforms |
|
Was this page helpful?