Claudeのサーバーツール結果は5分TTLで自動キャッシュされる仕組み
Web Search・Web Fetch・Code Executionの結果は、1時間TTLを設定していても常に5分TTLで自動キャッシュされます。仕組みと料金への影響、usageの読み方を解説します。
サーバーツール結果はなぜ設定を無視して5分でキャッシュされるのか
cache_controlの置き場所を扱った既存記事でも、サーバーツールを使うターンに自動でブレークポイントが付くことには触れています。ここで扱うのは、このブレークポイントのTTLが常に5分固定になる理由と、費用設計・順序制約への影響です。
Web Search・Web Fetch・Code Executionのようなサーバーツールが結果を返すと、APIはその結果にキャッシュのブレークポイントを自動で挿入します。このブレークポイントは常に既定の5分TTLで書き込まれます。リクエストに自分で付けたcache_controlが1時間TTLでも変わりません。
開発者がcache_controlを置いていない場所にキャッシュ書き込みが出る。usageを見て戸惑うのは、たいていこれが原因です。
自動ブレークポイントはいつ、どこに付くのか
自動ブレークポイントが付くのは、サーバー側のエージェントループが次の反復に進む直前です。結果ブロックの末尾に付くので、後続の反復は伸びていくプレフィックスをキャッシュから読めます。
1回のリクエストの中で起きること
- 1
リクエストに cache_control が1つ以上ある
system promptでもtools配列でもかまいません。これが自動ブレークポイントを有効にする前提です。
- 2
サーバーツールが結果を返す
Web Search・Web Fetch・Code Executionのいずれかが、サーバー側のループの中で実行されます。
- 3
APIが結果に5分TTLのブレークポイントを挿入する
自分で付けた
cache_controlのTTLとは無関係に、既定の5分で書き込まれます。 - 4
次の反復がキャッシュから読む
同じリクエストの後続の反復は、再処理せずにキャッシュ済みの部分を読み込みます。
プロンプトキャッシングを使っていないリクエストは、サーバーツールを呼んでも自動ブレークポイントを受け取りません。次の2つのリクエストで違いが出ます。まずパターン1は、cache_controlがなく、自動ブレークポイントも付かない例です。
{
"tools": [{ "type": "web_search_20260209", "name": "web_search" }],
"messages": [{ "role": "user", "content": "..." }]
}パターン2は、system promptのブロックにcache_controlを1つ置いた例です。この場合はサーバーツールの結果にも自動ブレークポイントが付きます。
{
"system": [
{ "type": "text", "text": "...", "cache_control": { "type": "ephemeral" } }
],
"tools": [{ "type": "web_search_20260209", "name": "web_search" }],
"messages": [{ "role": "user", "content": "..." }]
}違いはcache_controlが1つあるかどうかだけです。「サーバーツールを使えば自動でお得になる」のではなく、「プロンプトキャッシングを使うリクエストの中でサーバーツールを使うと、その結果にもキャッシュが及ぶ」という関係です。
usage.cache_creationの内訳をどう読むか
自動キャッシュが働いたかどうかは、レスポンスのusageで分かります。
{
"usage": {
"input_tokens": 120,
"cache_creation": {
"ephemeral_5m_input_tokens": 3400,
"ephemeral_1h_input_tokens": 8000
},
"cache_read_input_tokens": 8000,
"output_tokens": 210
}
}この例では、自分で1時間TTLを指定したsystem promptなどがephemeral_1h_input_tokensに、Web Searchの結果を自動キャッシュした分がephemeral_5m_input_tokensに、別枠で計上されています。2つは同じリクエストの中で同時に出ます。
「1時間TTLしか使っていないはずなのに5分TTLの書き込みがある」と気づいたら、まずサーバーツールの利用を疑うと切り分けが早く進みます。cache_creation_input_tokensはこの2つの合計値です。
キャッシュ関連の価格倍率
5分TTLの書き込み
1.25倍
自動ブレークポイントが使う側
1時間TTLの書き込み
2倍
自分でttl: 1hを指定した分
キャッシュ読み取り
0.1倍
Fable 5.1は0.025倍、Opus 5.5とSonnet 5.5は0.05倍
上のusageの例を、Claude Haiku 4.5(基本入力$1/MTok、5分書き込み$1.25、1時間書き込み$2、読み取り$0.10)で金額にすると次のとおりです。入力側だけの計算で、出力は含みません。
| 区分 | トークン | 単価(/MTok) | 金額 |
|---|---|---|---|
| 通常の入力 | トークン120 | 単価(/MTok)$1 | 金額$0.00012 |
| 5分書き込み(自動分) | トークン3,400 | 単価(/MTok)$1.25 | 金額$0.00425 |
| 1時間書き込み | トークン8,000 | 単価(/MTok)$2 | 金額$0.016 |
| キャッシュ読み取り | トークン8,000 | 単価(/MTok)$0.10 | 金額$0.0008 |
自動分の3,400トークンが仮に1時間書き込みなら$0.0068なので、差は1リクエストあたり$0.00255です。額は小さくても、反復の多いループを大量に回すとこの行が積み上がります。
サーバーツール結果が5分TTLに固定されるのは、単価の面では安い側に倒れています。実務で効くのは単価よりも、「設定していないのに書き込みが発生する」点です。費用監視を1時間TTLの前提で組んでいると、5分TTLの書き込みが想定外の行として現れます。
5分TTLのキャッシュは、読み取りのたびにTTLが更新されるため、使われ続けるかぎり期限が延びていきます。
1時間TTLと自動の5分TTLを混在させるときの順序制約
プロンプトキャッシングには、TTLの長いエントリほど手前に置くという制約があります。1時間のエントリは、同じリクエストの5分のエントリより前になければなりません。
自動ブレークポイントは常に5分TTLなので、この制約はたいてい自然に満たされます。1時間TTLをsystem promptやtools配列の先頭側に置いておけば、後から付く5分の自動ブレークポイントは必ずその後ろに来ます。
逆方向には注意が要ります。この順序規則を当てはめると、サーバーツールの結果より後ろに自分で1時間TTLのブレークポイントを足す設計は、手前に5分のブレークポイントがある状態になり、制約に反するおそれがあります。ループの後半でmessages側に1時間TTLを追加している構成は、サーバーツールを併用するときに順序を見直す対象です。
課金は、ヒット位置をA、最後の1時間ブロックをB、最後のcache_controlブロックをCとして、(B - A)が1時間書き込み、(C - B)が5分書き込みになります。この式を自動ブレークポイントに当てはめると、C側に来る構成ではその手前までが1時間書き込みの課金対象になる、という読み方になります。1時間キャッシュ自体をどんな場面で使うかはClaude APIの1時間キャッシュはいつ使うべきかで扱っています。
Web Search・Web Fetch・Code Executionでキャッシュ周りの挙動は違うか
自動ブレークポイントはこの3つに共通です。違いが出るのは、有効・無効を切り替えたときのキャッシュ無効化と、ツール側が持つ状態です。
| ツール | 有効・無効の切り替え | キャッシュとの関係 |
|---|---|---|
| Web Search | 有効・無効の切り替えsystemとmessagesのキャッシュを無効にする | キャッシュとの関係結果に5分TTLの自動ブレークポイント |
| Web Fetch | 有効・無効の切り替えsystemとmessagesのキャッシュを無効にする | キャッシュとの関係結果に5分TTLの自動ブレークポイント |
| Code Execution | 有効・無効の切り替え— | キャッシュとの関係コンテナの状態はプロンプトキャッシュと独立 |
Web SearchとWeb Fetchは、会話の途中のリクエストで有効・無効を切り替えるとキャッシュが飛びます。ツールを毎回出し入れする設計だと、1時間TTLを置いてもsystem以降が読み込まれません。ほかに、引用(citations)の切り替えもsystemとmessagesのキャッシュを無効にします。
Code Executionには、キャッシュとは別に2つの仕組みが同時に走ります。
Code Executionの出力とコンテナ
出力テキスト
ほかのサーバーツールと同じく結果ブロックとしてプロンプトの一部になり、自動ブレークポイントの対象になります。5分TTLが切れれば再書き込みです。
コンテナの状態
作成したファイルやREPLの状態は、コンテナIDを介して保たれます。コンテナは作成から30日で失効し、約5分間使われないとチェックポイントに保存されます。30日以内にそのIDで再開すれば復元されます。Files APIに作られたファイルは、明示的に削除するまで残ります。
「5分」という数字が両方に出てくるため混同しやすい箇所です。キャッシュのTTLが切れてもコンテナの中身は消えません。逆に、コンテナのチェックポイントがあるからといって、プロンプトキャッシュが残るわけでもありません。
Tool Search Tool経由で見つかったツールは、定義がtool_referenceとして会話の途中に追加され、プレフィックスのキャッシュが保たれます。これはツール定義側の話で、本記事の実行結果の自動キャッシュとは別の仕組みです。遅延ロードでキャッシュが壊れない理由はdefer_loadingでプロンプトキャッシュを壊さずツールを追加する仕組みで扱っています。
pause_turnで止まったターンを再開するとキャッシュはどうなるか
サーバー側のループは、長いターンの途中で止まり、stop_reason: "pause_turn"を返すことがあります。続きを進めるには、止まったレスポンスをそのまま次のリクエストに載せ、同じツールを含めて送り直します。止まった時点でserver_tool_useブロックの実行が済んでいないこともあり、ツールが欠けていると検証エラーになります。
再開は別のリクエストなので、ループ内の読み取りと違い、直前の自動書き込みが読まれるかどうかは経過時間しだいです。5分TTLですから、止まってから5分以内に再開すれば、それまでの書き込みを読める余地があります。待ちが長くなる実装では、再開までの間隔が5分を超えていないかをcache_read_input_tokensで見ておくと、キャッシュが効いているかが分かります。
サーバーツールとクライアントツールが同じ並列呼び出しに混ざった場合も、2つのリクエストに分かれます。APIはサーバーツールを実行せずにstop_reason: "tool_use"で戻り、クライアントのtool_resultを受け取った次のリクエストの冒頭でサーバーツールを実行します。
サーバーツール自動キャッシュはループのコストをどう変えるか
この仕組みが効くのは、1回のリクエストの中でサーバー側のループが複数回反復する場面です。Claudeが検索を繰り返したり、実行結果を踏まえて追加のコードを走らせたりするたびに、直前までの結果を丸ごと再処理すると、反復が増えるほど入力トークンが膨らみます。自動キャッシュはその再処理を読み込みに置き換えます。
自動ブレークポイントは、同じリクエスト内の後続の反復に向けたものと説明されています。別々のリクエストをまたぐキャッシュは、自分で置いたcache_controlのTTLで持たせるのが筋です。費用を見積もるときは、次の2つに分けると整理できます。
- ループ内の反復コストは、自動の5分キャッシュが吸収します
- リクエストをまたぐ延命は、自分で置いた
cache_controlのTTLで決まります
クライアント側でツール呼び出しを繰り返す構成は、1ターンごとに別のリクエストになります。Tool Runnerでツール呼び出しループを自動化する場合も、ターンをまたぐキャッシュの持ち方は自分のcache_controlの領分です。
Batch APIでも、すべてのサーバーツールが使えます。バッチ内で動くサーバー側のループは同期リクエストと同じですが、1ターンあたりの反復上限が高く設定されています。上限に達するとstop_reason: "pause_turn"で返り、続きは返された内容を付けて次のリクエストで再開します。反復が伸びやすいバッチほど、自動キャッシュが吸収する再処理の量は大きくなります。
まとめ
見直しが要るのは、次の2つの構成です。費用監視を1時間TTLの前提で組んでいると、ephemeral_5m_input_tokensの行が想定外の書き込みとして現れます。ループの後半でmessages側に1時間TTLを足していると、サーバーツール結果の5分ブレークポイントより後ろになり、順序制約に触れます。
それ以外の構成なら、ループ内は自動の5分キャッシュに任せ、リクエストをまたぐ分は自分のcache_controlで持たせる分担のままで足ります。プロンプトキャッシングの基本設計はPrompt Cachingの仕組みと適用判断にあります。