Claude Media
Preserved thinkingとは — Messages APIのthinking block保護策

Preserved thinkingとは — Messages APIのthinking block保護策

Claude Fable 5.1・Opus 5.5・Sonnet 5.5・Haiku 5.5で効く蒸留対策の仕組みと、システムプロンプトやツールの書き換えで起きる400エラーの切り分けと置き換え方を扱います。

Preserved thinkingとは

Preserved thinkingは、Messages APIが送り返されたthinkingブロックを再利用してよいかを検証する仕組みです。Claude Fable 5.1から始まり、現在はClaude Fable 5.1・Claude Opus 5.5・Claude Sonnet 5.5・Claude Haiku 5.5が対象です。APIはthinkingブロックのsignatureを見て、そのブロックより前のsystemプロンプト・tools・messagesが、生成したときと一字一句変わっていないかを確認します。変わっていれば、そのブロックとそれ以降のthinkingブロックは無効です。

狙いは蒸留(distillation)対策です。会話の前の部分を書き換え、暗号化されたthinkingブロックをClaudeに復号・出力させる手口が、他モデルの学習用データを不正に抽出する蒸留キャンペーンで使われてきました。書き換えそのものを検知して弾けば、この手口は通りません。10月12日に公表された防御の全体像と抽出量の変化は、蒸留対策の強化にまとめています。

Claudeのthinkingブロックは暗号化されて返ります。抽出した推論で別モデルを訓練すると、そのモデルはClaudeの能力の一部を引き継ぎつつ、サイバー攻撃や兵器開発のような悪用を防ぐ安全策は引き継ぎません。サポート記事はこの手口を、数千の偽アカウントを使う産業規模のものと説明しています。既存の対策である蒸留検知の分類器や、上位モデルから下位モデルへのセッション・推論の転送制限に、Preserved thinkingが加わった形です。

書き換えると無効になるもの、ならないもの

APIが比較するprefixは3つだけです。直近のリクエストで送ったsystemプロンプト、toolsの一覧、そのブロックより前にある全messageです。サーバー側のcompaction(コンパクション)を使う場合は、直近のcompactionブロック以降がprefixになります。

くらべる

変えるとthinkingが無効になるか

prefixの中

無効になる

  • systemの文字列やブロックの変更
  • toolsの追加・削除・改名・スキーマ変更(まだ誰も参照していないdefer_loading: trueのツールの追加は例外で、prefixを変えません)
  • 過去のuser・assistantメッセージの編集・並べ替え・削除
  • 過去のtool_resultの削除・短縮、画像の再エンコード
  • 呼ぶたびに中身が変わる画像・文書のURL
prefixの外

無効にならない

  • 末尾へのメッセージ追加
  • effort・max_tokens・output_config・tool_choice・metadataの変更
  • cache_controlマーカーの追加・移動・削除
  • 同じバイト列を返す署名付きURLの入れ替え
  • サーバー側のcompactionやcontext editingによる削除(APIは送った内容と比べる)

thinkingブロック自体は、先頭から・末尾から・全部を削除しても構いません。ただし途中の1件だけを抜くと、それ以降のブロックはすべて無効です。一度抜いたブロックを後から戻すと、抜けていた間に生成されたブロックが無効になります。

400が出たとき、何をどの順で確かめるか

無効なブロックへの対応はthinking.block_binding.prefix_mismatch_behaviorで選びます。

  • "error"(既定): 最初に失敗したブロックを名指しした400のinvalid_request_errorで拒否します
  • "drop_block": 失敗したブロックとそれ以降のthinkingブロックを落とし、リクエストは成立させます。落とされた分は課金されませんが、モデルはそのターンを過去の推論なしで答え、プロンプトキャッシュも編集地点から作り直されます

フィールドも、落としたブロックを示す応答のinput_transformations配列も、thinking-binding-controls-2026-08-01ベータヘッダーが必要です。ヘッダーなしでblock_bindingを送ると、block_binding: Extra inputs are not permittedで始まる別の400になります。Message Batches APIでは、フィールドを省いた項目は失敗せず、既定で強制される環境ではブロックが落とされます。バッチ項目を失敗させたいときは"error"を明示します。

手順

400を受けてから原因の編集を直すまで

  1. 1

    エラー文を読む

    400はmessages.1.content.0: ...のように、失敗したブロックのパスで始まり、thinkingブロックのsignatureが別の会話に紐づいていると伝えます。末尾の1文が、systemかtoolsの差分のように何が変わったかを名指しします。署名が壊れている場合は同じ400でも会話への言及がなく、prefix_mismatch_behaviorは効きません。

  2. 2

    同じボディを再送しない

    何度送っても同じ理由で失敗します。ベータヘッダーとprefix_mismatch_behavior: "drop_block"を付けて1回だけリトライし、この選択をセッションに保存して、再起動後のリクエストにも付けます。ヘッダーを送れないときは、履歴のthinking・redacted_thinkingブロックを一度すべて外して続けます。

  3. 3

    連続2回のリクエストを突き合わせる

    直近数ターンの送信ボディを記録しておき、名指しされた位置までのsystem・tools・messagesを前後で比べます。追記した分を除いて一致していなければ、差の出た箇所が原因の編集です。

  4. 4

    編集を置き換える

    差が見つかったら、次節の表で同じ効果を出す書き方に直します。drop_blockを外すのは、input_transformationsのprefix_binding_mismatchが出なくなってからです。

"drop_block"はエラーを隠すだけで、編集は直りません。落とされた推論をClaudeが再構築しようとして、トークン消費が増えることがあります。落とされたブロックが多いほど、また長いセッションの多くのターンで落とされるほど、増え方は大きくなります。セッションごとにprefix_binding_mismatchを含む応答を数え、通知を出しておく運用が公式ドキュメントで勧められています。

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": "1071と462の最大公約数は?"}
    ]
  }'

最初のターンでは再送するthinkingブロックがないので、input_transformationsは空の配列で返ります。2ターン目以降に、pathがmessages.3.content.0のような形で落とされたブロックを列挙します。

どの編集を、何に置き換えるか

公式ドキュメントは、実装で踏みやすい編集それぞれに、prefixを変えずに同じ効果を出す書き方を挙げています。共通の前提は、アシスタントターンをAPIが返した通りに一字一句送り返すことです。

踏みやすい編集置き換えベータヘッダー
systemに現在時刻・モードフラグ・再読み込みした指示を毎回埋め直す置き換えsystemは固定し、変わった時点にrole: "system"のメッセージを追加するベータヘッダー不要
最初のuserメッセージの環境情報(ブランチ・日付・メモリ)を毎回描き直す置き換え一度だけ描画して使い回し、変化は直近のuserターンにテキストで足すベータヘッダー不要
古いtool_resultをその場で削る・縮める置き換え送る前に縮める。後から消すならclear_tool_uses_20250919でサーバー側に任せるベータヘッダーcontext-management-2025-06-27
toolsの追加・削除置き換えtool_addition・tool_removalを載せたsystemメッセージを足すベータヘッダーinline-tools-2026-09-15
ターンごとの注意書きを足しては消す置き換えclear_at: "next_user_message"を付けたターン限定のsystemメッセージベータヘッダーmid-conversation-system-clear-at-2026-08-21
クライアント側で古いターンを要約・間引く置き換えon-demand compactionでAPIに要約させ、署名付きブロックで差し替えるベータヘッダーcompact-2026-09-04

toolsの置き換えには、旧名のmid-conversation-tool-changes-2026-07-01も使えます。これはツールを名前で参照する変更に限られます。MCPコネクタ経由のツールはmcp-client-2026-09-15を加えます。会話の途中のsystemメッセージは、Fable 5.1・Mythos 5.1・Fable 5・Mythos 5・Opus 5.5・Opus 4.8・Opus 5・Sonnet 5.5で使えます。Sonnet 5は対象外なので、モデルを切り替える実装では、対応しないモデル向けに従来どおりsystemを編集する経路を残します。

effortを途中で変えるのは、prefixの外なのでthinkingを無効にしません。ただしトップレベルのoutput_config.effortを変えるとキャッシュは作り直しです。Claude APIとGoogle Cloudでは、Fable 5.1・Mythos 5.1・Opus 5.5・Opus 5・Sonnet 5.5が対象です。中身が空のsystemメッセージにoutput_configを載せれば、キャッシュを保てます(ベータ、ヘッダーはmid-conversation-output-config-2026-07-01)。対応しないモデル(Fable 5を含む)に送ると400です。メッセージはoutput_config.effort requires a model that supports per-turn effort; this model does notです。Sonnet 5.5でbetween_toolsを使う場合は、effortを途中で変えると400になります。

一番確実な圧縮は、会話全体を1つのuserメッセージに要約し、それより前のターンを送り返さないことです。送り返すthinkingがないのでチェック自体が起きず、Claudeは要約から推論をやり直します。自前で書いた要約に直近ターンを残す方式は、残したターンのthinkingが要約前の履歴で作られているため失敗します。残すならthinkingブロックを外し、textとtool_useだけを持ち越します。

見落としやすい3つの落とし穴

落とし穴

エラーにならずに推論が消える実装

  • 空のthinkingを捨てるシリアライザ

    Claude Fable 5.1ではthinkingフィールドが既定で空で、推論の本体はsignatureに入っています。空のブロックを読み飛ばす実装だと、エラーは出ないまま毎ターンの推論が失われます。ストリームを自前で解析するなら、テキストが来なくてもsignature_deltaを受けて閉じるまでブロックを保持します。

  • 中身が変わるURL

    imageやdocumentのURL指定では、チェックの対象はURL文字列でなく取得したバイト列です。「最新のスクリーンショット」を返すエンドポイントや、会話の途中で編集された文書は、次のターンのthinkingを無効にします。Files APIのfile_idかbase64なら避けられます。

  • プロキシが動かす`system`

    ゲートウェイが呼び出し元のrole: "system"メッセージをトップレベルのsystemへ移すと、その時点で全thinkingが無効です。ツールを止めたいときも、toolsを消さずにtool_choice: {"type": "none"}を送ります。anthropic-betaの値とblock_bindingは、呼び出し元のままそのまま転送します。未知のキーを弾くオプション定義だと、利用者が"drop_block"を選べません。

対象のモデルとアカウント

サポート記事の表では、2026年8月31日(UTC)より前のアカウントは「適用外」です。一方、APIドキュメントでは、古いアカウントでもprefix_mismatch_behaviorを設定したリクエストは強制を受けます。設定せずベータヘッダーだけ送ると、リクエストは失敗しません。失敗したブロックはモデルに渡り、input_transformationsにthinking_mismatch_allowedとして記録されます。

モデル8月31日(UTC)以降のアカウントそれより前のアカウント
Claude Fable 5.18月31日(UTC)以降のアカウント既定で強制("error")それより前のアカウントフィールドを設定したリクエストのみ
Claude Opus 5.58月31日(UTC)以降のアカウント既定で強制("error")それより前のアカウントフィールドを設定したリクエストのみ
Claude Sonnet 5.58月31日(UTC)以降のアカウント既定で強制("error")それより前のアカウントフィールドを設定したリクエストのみ
Claude Haiku 5.58月31日(UTC)以降のアカウント既定で強制("error")それより前のアカウントフィールドを設定したリクエストのみ
Claude Mythos 5.1・Fable 5.1より前のモデル8月31日(UTC)以降のアカウントprefixチェックなしそれより前のアカウントprefixチェックなし

対象はClaude Platform組織のほか、Amazon Bedrock・Google Cloud Vertex AI・Microsoft Foundryの各アカウントです。手元のアカウントがどちらかは、thinkingブロックを含むFable 5.1の会話でブロックより前を書き換え、ヘッダーもblock_bindingも付けずに送ると分かります。ヘッダーを名指しした400なら既定で強制される側、200なら強制されない側です。

自分のキーで400が出ていないことは、コードが安全な証拠になりません。ツールを他人が自分のAPIキーで動かす場合、新しいアカウントの利用者が先に400を受けます。ヘッダーだけ付けて応答のthinking_mismatch_allowedを数えると、挙動を変えずに編集箇所を洗い出せます。

Claude Codeの最新版なら、点検を自動化できます。リクエストを組み立てるリポジトリを開き、同梱のClaude APIスキルで/claude-api preserved-thinking-migrationを実行します。数回分のマルチターンのセッションを記録して連続するリクエストを比べ、コードがprefixを書き換えている箇所を探します。続けて"drop_block"付きでセッションを再生し、APIが落としたthinkingブロックを数えます。token countingのエンドポイントも同じprefixチェックを走らせ、同じ400を返します。

モデルをまたぐと推論はどうなるか

読めるブロックはモデルごとに決まっています。Claude Fable 5.1とMythos 5.1は、互いと、それより前のモデルのブロックを読みます。Claude Opus 5.5はOpus 5以前のOpus・Sonnet・Haikuのブロックを読み、Claude APIとGoogle CloudではSonnet 5.5のブロックも読みます。FableやMythosのブロックは読みません。Claude APIでは、Fable 5.1とMythos 5.1がOpus 5.5のブロックを読めるので、Opus 5.5からFable 5.1への切り替えでは推論が残ります。

逆向きは落ちます。Fable 5.1・Mythos 5.1からOpus 5.5へ、またOpus 5.5からその2つ以外のモデルへ切り替えたターンは、それまでの推論なしで実行されます。ルーターが安いモデルへ振る場合や、分類器の拒否後のフォールバックも同じです。読めないブロックはAPIが黙って落とし、課金もinput_tokensへの計上もありません。

履歴は毎回すべて、thinkingブロック込みで送ります。APIはmessages配列を書き換えないので、Fable 5.1に戻した次のリクエストではブロックがまた読めます。推論が戻らなくなるのは、クライアントがモデル切替時にthinkingを自分で外した場合です。ベータヘッダーを付けると、落とされたブロックはreason: "model_binding_mismatch"で報告されます。

Claude Sonnet 5.5では、thinkingがモデルと会話に紐づく

2026年9月28日発表のClaude Sonnet 5.5にも、同じ紐づけが入っています。Sonnet 5.5は、Sonnet 5・Opus 4.8・Haiku 4.5以前のモデルが出したブロックを読みます。Opus 5・Opus 5.5・Fable・Mythosのブロックは読めません。Sonnet 5.5のブロックを読めるのは、Claude APIとGoogle CloudのOpus 5.5だけです。

Sonnet 5.5のthinkingは、作成したアカウントと、そのアカウントに紐づくアカウントでしか読めません。別アカウントが送ってきたブロックはAPIが落とし、リクエストは成功します。ベータヘッダー付きのClaude APIとGoogle Cloudでは、organization_binding_mismatchで報告されます。

同じClaude Platformの親組織、または同じGoogle Cloud組織のアカウントは、自動で紐づきます。Claude PlatformとAmazon Bedrockの間でフェイルオーバーするような構成は自動では紐づかず、サポート記事はアカウントチームへの連絡を案内しています。落とされた次の応答は遅くなり、トークンも増えることがあります。Claude Codeでセッションの途中にアカウントを切り替えた場合も同じです。

block_bindingはSonnet 5.5ではthinking: {"type": "adaptive"}でのみ使えます。between_toolsとの組み合わせは400になります。この制約がenabledとadaptiveの両方を受け付けるモデルとの違いで、1つのリクエストボディをモデル間で共用するときの注意点です。

Claude Code・Agent SDK利用者への影響

変更が要らないかどうかは、リクエストを誰が組み立てるかで決まります。サポート記事はClaude Code・Claude Cowork・Claude.aiを、APIドキュメントはClaude Managed AgentsとClaude Agent SDKを挙げています。影響を受けるのは、自前のハーネスやMCPサーバー統合でMessages APIを直接叩く実装です。

利用形態影響度分かれ目
Claude Code・Claude Cowork・claude.ai・Managed Agents・Agent SDKをそのまま使う影響度ほぼ影響なし分かれ目各製品がthinkingの送り返しを処理する
自前ハーネスでsystem・toolsを固定しmessagesに追記するだけ影響度ほぼ影響なし分かれ目prefixを変えない
クライアント側で要約・間引きをしている影響度条件次第分かれ目古いターンの書き換えがthinkingを無効にする
プロキシ・ゲートウェイとして間に立つ影響度条件次第分かれ目呼び出し元のrole: "system"をsystemへ移す実装は、全thinkingが無効になる
8月31日以降のアカウントでFable 5.1・Opus 5.5・Sonnet 5.5を使う影響度条件次第分かれ目既定の"error"で400を受ける

thinkingの一貫性はプロンプトキャッシュにも効く

systemとtoolsを固定してmessagesを追記だけにする規律は、プロンプトキャッシュのヒット率を保つ規律でもあります。thinkingを無効にする編集は、そのままキャッシュを作り直させる編集です。

thinking blocks cannot be modifiedエラーも、履歴のthinkingブロックを書き換えると起きます。ただしこちらは最後のassistantターンのブロックを直接改変したときのエラーで、prefixチェックとは別の仕組みです。

まとめ

system・tools・過去のmessagesに追記しかしない実装は、何も直さずに済みます。前方を書き換えている場合の進め方は、利用者のアカウントで分かれます。新しいアカウントの利用者には既定の"error"で400が返るので、エラー文が名指しした編集を直します。ツールを他人のキーで動かすなら、"drop_block"で止血しつつprefix_binding_mismatchが出なくなるまで観測する選択肢があります。Extended thinkingとAdaptive thinkingの違いを先に押さえると、どのモデルでどの方式が動くかが読みやすくなります。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. support.claude.com/en/articles/16761192-preserved-thinking-changing-how-the-m…
  2. platform.claude.com/docs/en/build-with-claude/preserved-thinking
この記事を共有:XはてブLinkedIn