Claude APIのプロンプトキャッシュ実践ガイド|キャッシュが効かない原因と直し方

高く積まれたコインの山がキャッシュチップを経て少ない山に変わるコスト削減のイメージ
API実装ガイド

Claude APIのプロンプトキャッシュ実践ガイド
キャッシュが効かない原因と直し方

「有効にしたのに請求が減らない」を卒業する。仕組みの理解から診断チェックリストまで解説します。

Claude APIのプロンプトキャッシュは、うまく使えば入力トークンのコストを最大90%近く削減できる強力な機能です。しかし「cache_controlを付けたのに全然効いている気配がない」というつまずきも非常によくあります。

本記事では、キャッシュの仕組みを1つの原則から理解した上で、エラーは出ないのに静かに効かなくなる原因を診断できるようになることを目指します。

スポンサーリンク

大原則:プロンプトキャッシュは「前方一致」

プロンプトキャッシュを理解する上で最も重要なのはこの一点です。キャッシュは各ブレークポイントまでの、レンダリングされたバイト列の完全一致で判定される「前方一致」の仕組みです。

プレフィックスのどこか1バイトでも変わると、それ以降がすべて無効化される

タイムスタンプ1つ、UUID1つが紛れ込んでいるだけで、そこから後ろのキャッシュはまるごと効かなくなります。「一部だけ効いて一部は効かない」という中途半端な状態にはならず、変化点より後ろは常に全滅する仕組みです。

レンダリング順序を意識する

リクエストはtoolssystemmessagesの順でレンダリングされます。この順序を理解した上で、安定した内容を前に、変動する内容を後ろに配置するのが設計の基本方針です。

基本の書き方

自動キャッシュ(迷ったらこれ)

トップレベルのcache_controlを指定すると、リクエスト内で最後にキャッシュ可能なブロックへ自動的に配置されます。細かい制御が不要なら、まずこれで十分です。

Python — 自動キャッシュ

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=16000,
    cache_control={"type": "ephemeral"},
    system="あなたは専門的なアシスタントです...",
    messages=[{"role": "user", "content": "要点をまとめて"}]
)

手動ブレークポイント(最大4箇所)

Python — 手動ブレークポイント

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=16000,
    system=[{
        "type": "text",
        "text": "あなたはこの大規模ドキュメントの専門家です...",
        "cache_control": {"type": "ephemeral"}  # デフォルトは5分TTL
    }],
    messages=[{"role": "user", "content": "要点をまとめて"}]
)

TTLの選択

TTL書き込みコスト向いているケース
5分(デフォルト)1.25倍短時間に連続してリクエストが来る通常のチャット
1時間2倍バースト的なトラフィックで、リクエスト間隔が空きがちな場合

損益分岐点を理解する

キャッシュ読み取りは通常の約0.1倍、書き込みは5分TTLで1.25倍・1時間TTLで2倍のコストがかかります。ここから、何回読み取れば元が取れるかが逆算できます。

TTL損益分岐点計算根拠
5分2回目で黒字化1.25倍(書込)+ 0.1倍(読取)= 1.35倍 < 2倍(キャッシュなしで2回)
1時間3回以上で黒字化2倍(書込)+ 0.2倍(読取2回)= 2.2倍 < 3倍(キャッシュなしで3回)

裏を返せば、同じプレフィックスを2回未満しか使わないなら、キャッシュを付けるだけ損です。1回きりのプロンプトにマーカーを付けても、書き込みコストが上乗せされるだけで回収できません。

キャッシュが効かない「サイレントな原因」チェックリスト

ここが本記事の核心です。エラーは一切出ないのに、キャッシュヒット率がゼロのままというケースの典型的な原因を列挙します。

① システムプロンプト内の日時埋め込み

f"現在時刻: {datetime.now()}"のような形でシステムプロンプトに現在時刻を埋め込んでいると、リクエストのたびにプレフィックスが変わり、キャッシュは毎回新規作成されます。

② リクエストIDやUUIDの埋め込み

デバッグ用にリクエストごとの一意なIDをプロンプトの先頭〜中盤に埋め込んでいるケース。これも同様に、そのリクエスト固有の値である以上、後続のリクエストとプレフィックスが一致しません。

③ JSONのキー順が非決定的

dictSetをそのままjson.dumps()している場合、実行のたびにキーの並び順が変わることがあります。sort_keys=Trueを指定していないと、内容は同じでもバイト列としては別物になります。

④ ユーザーIDのシステムプロンプトへの補間

f"ユーザーID: {user_id}"のようにユーザー固有の情報をシステムプロンプトの前方に混ぜていると、ユーザーごとにプレフィックスが異なるため、ユーザー間でキャッシュを共有できません。

⑤ ツールセットがリクエストごとに変動

toolsはプロンプトの一番先頭でレンダリングされます。ユーザーの状況に応じてツールを動的に増減させていると、その時点でプレフィックス全体が変わり、system・messagesを含めたすべてのキャッシュが無効化されます。

⑥ モデルの切り替え

キャッシュはモデルごとに独立しています。A/Bテストなどでモデルを動的に切り替えている場合、切り替えるたびにキャッシュはゼロから積み直しになります。

効果測定の方法

レスポンスのusageフィールドには、キャッシュの状態を表す3つの数値が含まれます。

キャッシュ効果の確認

print(response.usage.cache_creation_input_tokens)  # 今回新たに書き込んだトークン数
print(response.usage.cache_read_input_tokens)      # キャッシュから読み取ったトークン数
print(response.usage.input_tokens)                 # キャッシュされていない通常トークン数

診断フロー:readが常にゼロなら、サイレントな原因が潜んでいる

同一プレフィックスのリクエストを繰り返してもcache_read_input_tokensが常にゼロの場合、上記チェックリストのいずれかに該当している可能性が高いです。2つのリクエストのプロンプトを実際にバイト単位で比較して、差分を探すのが確実な調査方法です。

よくある勘違い:input_tokensの数値がプロンプト全体だと思ってしまう

input_tokensキャッシュされなかった残りの部分だけを表します。プロンプト全体のサイズは「input_tokens + cache_creation_input_tokens + cache_read_input_tokens」の合計です。長時間動いているエージェントでinput_tokensだけを見て「思ったより小さい」と勘違いしないよう注意してください。

知っておくと差がつく上級知識

最小キャッシュ可能サイズはモデルごとに異なる

短いプロンプトは、マーカーを付けても黙ってキャッシュされません(エラーにはならず、cache_creation_input_tokensがゼロになるだけです)。最小サイズはモデルによって異なるため、想定より小さいプロンプトを扱う場合は注意してください。

並列リクエストの罠

キャッシュエントリは、最初のレスポンスのストリーミングが開始してから初めて読み取り可能になります。同一プレフィックスのリクエストをN本同時に並列発射すると、全リクエストがまだ何も書き込まれていない状態でキャッシュミスし、全員がフルプライスを払うことになります。

対策:1本を先行させてから残りを投げる

ファンアウト処理をする場合は、1本のリクエストを送って最初のトークンが返ってくるのを待ってから、残りのリクエストをまとめて発射すると、後続がキャッシュを読み取れます。

会話が長い場合のブレークポイント運用

マルチターンの会話では、最新ターンの末尾にブレークポイントを置く運用にすると、会話が伸びるたびに増分でヒット率を積み上げていけます。1つの会話中で多数のツール呼び出しがある場合は、ブレークポイントの20ブロックのルックバック制限にも注意が必要です。1ターンで20ブロックを超えるようなやり取りが多い場合、中間地点にもブレークポイントを置いておくと安全です。

よくある質問

Q. キャッシュを有効にすると追加料金はかかりますか?

A. 書き込み時にのみ通常より高い単価(5分TTLで1.25倍、1時間TTLで2倍)がかかります。読み取り時は逆に約0.1倍まで下がるため、同じプレフィックスを複数回使う前提であれば全体としては安くなります。

Q. tool_choiceを変更するとキャッシュは失われますか?

A. 無効化の範囲はパラメータによって階層が異なります。ツール定義自体の変更やモデルの切り替えは全キャッシュを無効化しますが、tool_choiceや画像の追加、thinkingのON/OFF切り替えは、toolsキャッシュ・systemキャッシュには影響しても、messagesキャッシュは保持されるなど、変更内容によって影響範囲が異なります。

Q. Batch APIと併用できますか?

A. プロンプトキャッシュ自体はBatch APIでも利用可能です。同じプレフィックスを持つリクエストをバッチにまとめる際は、通常のリクエストと同様にキャッシュの前方一致の原則が適用されます。

まとめ

本記事のポイント

  • プロンプトキャッシュは「前方一致」。プレフィックスの1バイトの変化でそれ以降が全滅する
  • 損益分岐点は5分TTLで2回、1時間TTLで3回以上の再利用が目安
  • 効かない原因の多くはタイムスタンプ・UUID・非決定的なJSON・動的なツールセットなどのサイレントな要因
  • cache_read_input_tokensが常にゼロなら、プロンプト構築コードの安定性を疑う

マーカーを増やす前に、まずプロンプトを組み立てるコード側が「毎回同じバイト列を生成しているか」を疑ってみてください。多くの場合、原因は設定ではなくコードの中に潜んでいます。

※本記事の情報は2026年7月時点のものです。料金体系・仕様は変更される可能性があるため、最新情報はAnthropic公式ドキュメントをご確認ください。

タイトルとURLをコピーしました