Claude Media
ツール定義のcache_controlはどこに置くか

ツール定義のcache_controlはどこに置くか

Anthropic APIでツール定義をプロンプトキャッシュに乗せるcache_controlの配置ルールをまとめます。MCPツールセットやcomputer use/browser useでの特殊な挙動も扱います。

基本ルール:配列末尾のツール1つに付ける

結論から言うと、tools 配列の最後のツール1つcache_control: {"type": "ephemeral"} を置きます。これで配列の先頭からそのツールまでの、ツール定義プレフィックス全体がキャッシュされます。ツールを1つずつ個別にキャッシュする仕組みではありません。

プロンプトキャッシュとは、Anthropic APIがリクエストの先頭側の共通部分(システムプロンプト、ツール定義、会話履歴の一部)を再利用し、2回目以降の呼び出しでコストとレイテンシを削減する仕組みです。まずはAnthropic APIのPrompt Cachingを理解するで全体像を押さえておくと、この記事のツール定義側のルールも位置づけがつかみやすくなります。キャッシュは tools → system → messages というプレフィックス階層に沿って効くため、tools の途中に変更が入ると、そこから後ろの systemmessages のキャッシュもまとめて無効になります。ツール定義を毎回同じ順序・同じ内容で送り、その末尾に cache_control を置くことが、キャッシュを最大限効かせる出発点になります。

ツール定義がキャッシュ対象になる意味は、エージェントを組んでいる人ほど大きく感じられます。ファイル操作・検索・実行系のツールを何十個も並べたエージェント構成では、ツール定義だけでリクエストの入力トークンの大半を占めることも珍しくありません。プレフィックス階層の一番手前にある tools から順にキャッシュを効かせておくことが、後段のシステムプロンプトや会話履歴のキャッシュ効率にもそのまま連動します。

cache_control は複数のツールに個別に付けるものではなく、キャッシュしたい範囲の末尾にあたる1つのツールにだけ付けます。

{
  "tools": [
    { "name": "get_weather", "description": "..." },
    {
      "name": "get_time",
      "description": "...",
      "cache_control": { "type": "ephemeral" }
    }
  ]
}

この例では get_weatherget_time の両方を含むツール定義プレフィックス全体がキャッシュされます。3つ目のツールを追加で送るときに get_time のマーカーをそのまま残しておけば、get_weatherget_time の部分は引き続きキャッシュから読まれ、新しいツールの分だけが追加コストになります。逆に言えば、get_weather の定義文を書き換えるだけでも、そこから後ろの get_time を含むプレフィックス全体が無効化されるということです。ツール定義の変更頻度が高いチームほど、この巻き込み範囲を意識した設計が効いてきます。

複数のツールにそれぞれ cache_control を付けてしまうミスは、実装の途中でよく見かけます。個々のツールを個別にキャッシュしたくなる直感は自然ですが、プレフィックス階層はあくまで先頭からの連続した範囲に対して効くものなので、末尾以外のツールにマーカーを付けても意味を持ちません。マーカーは「ここまでを1つの塊としてキャッシュする」という区切りの印であり、区切りを増やすほどキャッシュが細分化されるわけではないという点は誤解しやすいところです。

1リクエストあたりの cache_control マーカーは4箇所までという上限があるため、ツール定義・system・会話履歴のどこにブレークポイントを置くかは、変更頻度の低い部分から優先して割り当てるのが基本方針です。マーカーを使い切ってしまうと、本当に固定したい部分にブレークポイントを置けなくなるため、4箇所という上限は「使える分だけ使う」ではなく「優先順位を決めて配分する」ものだと捉えたほうが実装しやすくなります。

MCPツールセットの特殊挙動

mcp_toolset を使っている場合は、末尾のツールを自分で選べません。MCPツールセット内のツール順序はクライアント側からは制御できないためです。この場合は cache_control を個々のツールにではなく、mcp_toolset エントリ自体に置きます。APIが展開後の最後のツールに自動的にブレークポイントを適用してくれる仕組みです。

computer use・browser useのツールセットエントリも同じルールに従います。これらのツールセットも複数のツールをまとめて1つのエントリとして展開する構造を持つため、cache_control はツールセットエントリ自体に置き、ブレークポイントはそのツールセットの定義が終わった直後に着地します。メンバーツールの configs エントリの内側には設定できません。ツールセットのメンバーは1つの定義としてまとめてロードされるため、内側で個別に区切る余地がない設計です。

バッチアクション内のcache_controlは1つのブレークポイントにまとまる

computer useのバッチアクションでは、そのターンに含まれる tool_usetool_result ブロックのどれかに cache_control マーカーを付けると、そのバッチの終端で効果を発揮します。同じバッチの中に複数のマーカーが混ざっていても、まとめて1つのブレークポイントとして扱われます。ただし各マーカーは、それぞれリクエスト全体で4箇所までという上限にはカウントされるため、バッチ内で複数箇所にマーカーを置いても得はなく、1バッチにつき1つで十分です。

defer_loadingでツール検索を使ってもキャッシュが壊れない理由

Tool Searchを使って数百〜数千のツールをオンデマンドで読み込む構成では、defer_loading を付けたツールはシステムプロンプトのプレフィックスに含まれません。Claudeがツール検索経由でそのツールを発見した時点で、会話履歴の中に tool_reference ブロックとしてインラインに追加される仕組みです。プレフィックス自体は変更されないため、動的にツールを増やしてもキャッシュは保たれます。

この設計の意味は、常時ロードする少数のツール(キャッシュ対象)と、必要になったときだけ検索で見つける大量のツール(キャッシュ非対象)を分けて運用できるということです。会話の最初は小さな常時ロードツールセットだけでキャッシュを温め、Claudeがツール検索で追加のツールを見つけるたびにそれが会話履歴に積み上がっていっても、毎ターンのキャッシュヒット自体は崩れません。defer_loading はstrict modeの文法構築とも独立して動きます。strict modeの文法は、遅延ロード中かどうかにかかわらず全ツールセットから構築される仕組みです。動的にツールが増えても、プロンプトキャッシュと文法キャッシュの両方が保たれます。

何がキャッシュを無効化するか

ツール定義そのものを変更すると、toolssystemmessages の全階層のキャッシュが無効になります。それ以外の変更は、無効になる範囲が階層ごとに異なります。

変更無効になる範囲
ツール定義の変更無効になる範囲tools / system / messagesすべて
Web検索・引用機能のオン/オフ切り替え無効になる範囲system / messages
tool_choice の変更無効になる範囲messages
disable_parallel_tool_use の変更無効になる範囲messages
画像の有無の切り替え無効になる範囲messages
thinkingパラメータの変更無効になる範囲messages(モデルによってはtools / systemも)
output_config.effort の変更無効になる範囲thinkingパラメータと同じ(既定値の明示指定は省略と等価)

tool_choice を会話の途中で切り替える必要がある設計では、その変更点より前に cache_control を置いておくと、切り替え自体はmessagesキャッシュだけの無効化で済み、ツール定義とシステムプロンプトのキャッシュは保たれます。同じ考え方は disable_parallel_tool_use や画像の有無の切り替えにも当てはまります。無効になる範囲がmessages階層に限られる変更は、tools階層より手前にブレークポイントを置いておくだけで被害を最小限にできるということです。

ツールごとの個別事情もあります。要点を表にまとめます。

ツールキャッシュとの関係
computer use / browser useキャッシュとの関係スクリーンショットが会話履歴に積み上がるため、messagesキャッシュは崩れやすい。前段のツール定義・システムプロンプト部分だけでも保つ設計が現実的
text editor / bashキャッシュとの関係標準的なクライアントツールで、キャッシュとの特別な相互作用はない
web検索・web fetchキャッシュとの関係有効/無効の切り替え自体がsystemmessagesの両方を無効化する
ツール検索で発見したツールキャッシュとの関係tool_referenceブロックとして履歴に積まれるだけなので、プレフィックスキャッシュは崩れない
コード実行のコンテナ状態キャッシュとの関係プロンプトキャッシュとは独立に管理される。キャッシュの有無はコンテナの再利用に影響しない

Web検索やコード実行を使ったターンのキャッシュは自動で付く

プロンプトキャッシュを有効にしたリクエストで、Claudeがweb検索・web fetch・コード実行のようなサーバーツールを使うと、APIはそのサーバーツールの結果に自動でキャッシュブレークポイントを置き、エージェントループの次の反復に備えます。この自動ブレークポイントは常に5分のデフォルトTTLで、自分で設定した cache_control のTTLとは独立です。レスポンスの usage を見ると、1時間TTLのマーカーだけを使っているつもりでも cache_creation.ephemeral_5m_input_tokens に書き込みが記録されることがあるのはこのためです。この自動付与は、リクエストに既に1つ以上の cache_control マーカーがある場合にだけ働きます。

cache_controlの配置ミスがコストに跳ね返る理由

cache_control を末尾のツールではなく途中のツールに置いてしまうミスは、動作自体は壊れませんが、キャッシュが効く範囲を意図せず狭めます。末尾より手前にマーカーを置くと、それより後ろにあるツール定義は毎回キャッシュ対象外の生のトークンとして送られ続けることになり、プレフィックス階層の恩恵を部分的にしか受けられません。ツールを追加・削除するたびにマーカーの位置を末尾へ動かし忘れるのも同じ失敗の典型です。

MCPツールセットで個々のツールにマーカーを付けて制御しようとすること自体が、そもそも設計として合っていません。クライアント側が制御できるのはエントリ単位までという制約を先に理解しておくことが、無駄な試行錯誤を避ける近道です。ツール数が少ないうちは配置ミスの影響も軽微ですが、Advanced Tool Useで紹介されているように5つのMCPサーバ・58ツールの構成で約55Kトークン、社内の別の構成では134Kトークンがツール定義だけで埋まるケースもあり、こうした規模になるとキャッシュの効き方1つでリクエストごとのコストが大きく変わってきます。

まとめ

基本ルールは単純です。cache_control はツール配列の末尾のツール1つに置きます。そこまでのツール定義プレフィックス全体がキャッシュ対象になる仕組みです。配置場所さえ守れば、あとの挙動は自動で決まります。

MCPツールセットやcomputer use / browser useのツールセットでは、そもそも末尾のツールを自分で選べません。この場合はエントリ自体にマーカーを置き、展開後の末尾へは自動で適用されます。バッチアクション内の複数マーカーは1つのブレークポイントとして扱われますが、上限4箇所には個別にカウントされる点は注意が必要です。ツール検索の defer_loading はプレフィックスに影響しないため、動的にツールを増やしてもキャッシュは保たれます。

この記事を共有:XはてブLinkedIn