Claude Media
Claude APIの明示的キャッシュブレークポイントの置き方

Claude APIの明示的キャッシュブレークポイントの置き方

cache_controlをどのブロックに置くとキャッシュが当たり、どこに置くと毎回外れるか。ルックバックの仕組みと複数ブレークポイントの使いどころを一次ソースの原則から解説します。

cache_controlはブロック単位の位置指定

Claude APIのプロンプトキャッシュは自動キャッシュでもある程度動きますが、変更頻度が異なる複数のセクション(ほぼ変わらないツール定義と、日次で更新されるコンテキストなど)を個別にキャッシュしたい場合、個々のコンテンツブロックに cache_control を明示的に置く「明示的キャッシュブレークポイント」を使います。

プロンプトの先頭には静的な内容(ツール定義・システム指示・コンテキスト・例示)を置き、その再利用したい範囲の終端に cache_control を付けます。キャッシュのプレフィックスは toolssystemmessages の順で階層的に構築され、この順序自体が上位から下位への依存関係になります。

自動プレフィックスチェックが何をしているか

ブレークポイントは静的コンテンツの末尾に1つ置くだけでよく、あとはシステムが「過去のリクエストがどこまで書き込み済みか」を自動で探索します。この探索の仕組みには3つの原則があります。

  1. キャッシュへの書き込みはブレークポイントの位置でしか起きないcache_control を付けたブロックで、そのブロックまでのプレフィックス全体のハッシュを1件だけ書き込みます。それより前の位置には何も書き込まれません。ハッシュは累積(ブレークポイントまでの全体を含む)なので、ブレークポイント以前のどこか1ブロックでも変わると、次のリクエストではハッシュ自体が別物になります
  2. キャッシュの読み取りは、過去のリクエストが書き込んだエントリを後方へ探す。各リクエストはブレークポイント位置のプレフィックスハッシュを計算し、一致するキャッシュエントリを探します。無ければ1ブロックずつ手前へ遡り、各位置のプレフィックスハッシュが既存のキャッシュと一致するか確認します。探しているのは「安定して変わらない内容」ではなく「過去に誰かが書き込んだ実績のある位置」です
  3. ルックバックの探索範囲は20ブロック。ブレークポイント自身を1つ目として、最大20位置しか遡りません。この範囲内で一致が無ければ探索は打ち切られます(次の明示的ブレークポイントがあればそこから再開)。Claude APIでは、連続する tool_use ブロックはまとめて1位置、連続する tool_result ブロックもまとめて1位置として数えるため、並列ツール呼び出しが多いターンが1つ入っただけでは前回のエントリがウィンドウの外に押し出されにくくなっています

成長する会話でルックバックがどう動くか

会話が伸びていくたびに新しいブロックを追加し、毎リクエストの最終ブロックに cache_control を設定するケースを考えます。

ターンブロック数ブレークポイント結果
1ブロック数10ブレークポイントブロック10結果既存エントリなし。ブロック10に新規書き込み
2ブロック数15ブレークポイントブロック15結果ブロック15は未登録だがブロック10まで遡ると一致。ヒット。11〜15だけ新規処理し、ブロック15に新規書き込み
3ブロック数35ブレークポイントブロック35結果20位置(35〜16)を探索するが一致なし。ターン2の書き込み(ブロック15)は探索範囲の1つ外にありヒットしない

ターン3のように会話が長く伸びると、探索範囲の外にエントリが押し出されてキャッシュが外れます。この場合、ブロック15付近にも別のブレークポイントを追加しておけば、そこに独立したルックバックウィンドウが生まれ、ターン2のエントリを拾えます。

よくある失敗: 毎回変わるブロックにブレークポイントを置く

静的なシステムコンテキスト(ブロック1〜5)のあとに、タイムスタンプとユーザーメッセージを含む可変ブロック(ブロック6)が続くプロンプトを例にします。ここで cache_control をブロック6に設定すると次のようになります。

  • リクエスト1: ブロック6に書き込み。ハッシュにはタイムスタンプが含まれる
  • リクエスト2: タイムスタンプが変わるためブロック6のプレフィックスハッシュも変わる。ルックバックはブロック5、4、3、2、1と遡るが、そのどの位置にも過去のリクエストが書き込んだエントリは無い。ヒットなし。毎回キャッシュ書き込み費用を払い、一度も読み取りを得られない

ルックバックは「ブレークポイントの手前にある安定した内容」を勝手に見つけてキャッシュしてくれるわけではありません。あくまで「過去のリクエストが実際に書き込んだ位置」を探すだけです。この場合の正しい修正は、cache_control をブロック5(リクエスト間で変わらない最後のブロック)へ移すことです。そうすれば以降のすべてのリクエストがキャッシュ済みのプレフィックスを読み取れます。

原則をまとめるとcache_control は「共有したいリクエスト群の間でプレフィックスが同一であり続ける最後のブロック」に置きます。成長する会話では、1ターンで追加されるブロックが20未満である限り最終ブロックへの設定で足ります(それより前の内容は変わらないため、次のリクエストのルックバックが過去の書き込みを見つけられる)。タイムスタンプやリクエストごとに変わるコンテキスト、直近のメッセージのような可変な末尾を持つプロンプトでは、可変ブロックではなく静的プレフィックスの終端にブレークポイントを置きます。

具体的には、ブロック5に付けるべき cache_control を可変なブロック6へ付けてしまうのが典型的な失敗です。

// before(ブロック6=可変な末尾に付けてしまう。毎回ミス)
{ "type": "text", "text": "<timestamp + user message>", "cache_control": { "type": "ephemeral" } }
 
// after(ブロック5=直前の静的な最終ブロックに付ける)
{ "type": "text", "text": "<static block 5>", "cache_control": { "type": "ephemeral" } }

デフォルトのTTLは5分ですが、"ttl": "1h" を指定すると1時間キャッシュを保持できます(その代わり基本入力トークン価格の2倍)。長時間ツール定義を使い回すケースではTTL延長も選択肢になります。

複数ブレークポイントと自動キャッシュの使い分け

明示的ブレークポイントは最大4つまで定義でき、自動キャッシュと併用できます。使い分けの起点になるのは「まず自動キャッシュから始める」という公式の推奨順序です。自動キャッシュは多くの多ターン会話でそのまま機能し、各リクエストの末尾ブロックに自動でブレークポイントを移動させ続けます。次のいずれかに当てはまるときだけ、明示的ブレークポイントを追加または切り替えます。

  • ツール定義とコンテキストのように、変更頻度が異なる複数のセクションを個別にキャッシュしたい(ツール定義はほとんど変わらないが、コンテキストは日次で更新される、等)
  • 何がキャッシュされるかをより細かく制御したい
  • 静的なプレフィックスの末尾が「キャッシュ可能な最後のブロック」と一致しない(可変な末尾を持つプロンプトなど、前述の失敗例に該当する)
  • 会話が伸びて既存のブレークポイントが直近の書き込みから20ブロック以上離れてしまう事態を避けたい

併用する場合の役割分担は明快です。明示的ブレークポイントはシステムプロンプトのような静的な部分に固定で置き、自動キャッシュは伸びていく会話部分を追いかける、という組み合わせが典型です。たとえばシステムプロンプトに明示的な cache_control を1つ置いておけば、それとは別に自動キャッシュが messages 側の最終ブロックを自動追跡します。ただし自動キャッシュは4つあるブレークポイントの枠のうち1つを消費するため、明示的ブレークポイントをすでに4つ使い切っていると自動キャッシュの分の枠が残っていません(次節で詳述)。

会話が伸びるアプリケーションでは、既存のブレークポイントが直近の書き込みから20ブロック以上離れる前に、あらかじめ2つ目のブレークポイントをその近くに置いておくと、必要になる前にエントリが蓄積されます。Claude Codeのようなエージェント型のクライアントでも同じ原理が働きます。Claude Codeの利用上限をプロンプトキャッシュがどう軽くするかを見ても、ヒット率を左右しているのは結局「どのブロックが安定していて、どのブロックが揮発するか」の見極めです。

枠が尽きたときの挙動

明示的ブレークポイントには面ごとの制約があります。

  • 明示的ブレークポイントをすでに4つ使い切っている状態で、さらにトップレベルの cache_control を追加しようとすると、自動キャッシュ用の枠が残っておらずAPIは400エラーを返します
  • レガシー版のAmazon Bedrock(Claude Opus 4.6以前の統合)では自動キャッシュ自体に対応しておらず、トップレベルの cache_control を指定するとAPIが400エラーを返します。この面では自動キャッシュに頼らず、明示的ブレークポイントだけで構成する必要があります

ブレークポイント自体に追加コストは無い

ブレークポイントを置くこと自体には料金がかかりません。課金対象は次の3つだけです。

  • キャッシュ書き込み: 新しい内容をキャッシュに書き込むとき(5分TTLでベース入力トークンの1.25倍)
  • キャッシュ読み取り: キャッシュ済みの内容を利用するとき(ベース入力トークン価格の0.1倍、Claude Fable 5.1とClaude Mythos 5.1では0.025倍)
  • 通常の入力トークン: キャッシュされていない内容

ブレークポイントを増やしても、それだけでコストが増えることはありません。実際にキャッシュされ読み取られた内容に応じた金額を払うだけです。ブレークポイントはあくまで「どのセクションを独立してキャッシュ可能にするか」を制御するための仕組みです。

プリウォーミングでも同じ原則が適用される

ユーザーの実リクエストが来る前にキャッシュへ読み込ませておく「プリウォーミング」(max_tokens: 0 を使う手法)でも、ブレークポイントの置き方が結果を左右します。プリウォーミングのプレースホルダーメッセージにブレークポイントを置いてしまうと、書き込まれたキャッシュエントリがそのプレースホルダー自体に紐づき、実際のフォローアップリクエストでは二度とヒットしません。正しくは、フォローアップと共有する最後の静的ブロックに置く必要があります。この手法自体の詳しい仕組みとmax_tokens=1からの移行点はプロンプトキャッシュの事前ウォームアップで扱っています。

まとめ

明示的キャッシュブレークポイントを機能させる鍵は、ルックバックが「安定した内容」ではなく「過去に書き込まれた実績のある位置」しか探さないという原則です。静的なプレフィックスの終端にブレークポイントを置けば以降のリクエストで読み取りが発生しますが、毎回変わるブロックに置くと書き込みだけが続いてヒットしません。会話が長く伸びるアプリケーションでは、20ブロックのルックバック範囲を意識して複数のブレークポイントを配置することが、キャッシュヒット率を保つ実践的な対策になります。

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