| |

Claude キャッシュヒット率が0に低下?3ステップでdiagnosticsを使ってどの部分が変わったかを特定

Claude キャッシュヒット率が0に低下?3ステップでdiagnosticsを使ってどの部分が変わったかを特定

著者注:Claude のプロンプトキャッシュのヒット率が突然 0 に落ちた、あるいは請求額がどうしても下がらない——そんなときは diagnostics の3ステップでプレフィックスが分岐している箇所を特定し、さらに usage と組み合わせてキャッシュが本当にヒットしているかを判断できます。この記事では APIYI の API中継サービスを経由する場合の自己チェック方法も紹介します。(同じ問題を抱えている方は、この記事を読み終えたらお使いの Agent に送って調査させてみてください)

キャッシュがヒットしないのは決して不思議な現象ではありません。API はプレフィックスがどのセグメントから分岐しているかを教えてくれます。前のターンのレスポンス id を返すだけで、最初に一致しなかった箇所が model、system、tools、messages のどこにあるのかがわかります。

これは機能リリースの解説記事ではありません。すでに Claude のプロンプトキャッシュを使っていて、ヒット率が突然ゼロになった、あるいは請求額が高いまま下がらない開発者に向けた内容です。各手順で何が見えるのかまで具体的に書いていきます。

コアバリュー:この記事を読み終えれば、3回のリクエスト以内にキャッシュが無効になった原因を特定できます。diagnostics と usage がそれぞれ何を意味するのかを区別でき、中継サービスを経由するときにどの2つのフィールドを突き合わせればよいかもわかります。

claude-prompt-cache-diagnostics-hit-rate-troubleshooting-ja-image-0


Claude キャッシュ診断 diagnostics の核心ポイント

まずひと言で説明すると、前回のレスポンス id を渡すと、API が2回のリクエストを比較し、最初の分岐点が model、system、tools、messages のどこにあるかを指摘してくれるという機能です。これまではキャッシュがひっそりと無効化されると、usage.cache_read_input_tokens が 0 になったことしか分からず、どの部分が変わったのかは特定できませんでした。

ポイント 説明 あなたにとっての価値
スイッチ リクエストボディのトップレベルに diagnostics オブジェクトを含めた場合のみフィンガープリントを保存 ビジネスロジックを変えず、フィールドを1つ追加するだけ
比較方法 previous_message_id に前回のレスポンス id を渡す 最初の分岐セグメントを直接特定できる
結論フィールド cache_miss_reason が6種類のうちの1つを示す 各タイプに明確な修正箇所がある
併用する指標 usage.cache_read_input_tokens と合わせて確認する必要がある 「分岐なし」を「効果なし」と誤判定するのを避ける
利用可能な範囲 公式 Claude API でのみ提供 他のチャネル経由の場合は usage による自己チェックに切り替える必要がある

Claude キャッシュ診断のタイムライン

この機能は2026年5月にベータ版としてリリースされ、当時は anthropic-beta: cache-diagnosis-2026-04-07 というヘッダーが必要でした。9月の期間中にルールが一度厳格化され、明示的に diagnostics オブジェクトを含めたリクエストのみフィンガープリントが保存され、ヘッダーのみを含むリクエストは記録されなくなりました。

9月23日に正式版へと移行し、cache-diagnosis-2026-04-07 は不要になりました。古いヘッダーを含むリクエストも通常どおり利用できます。現在、POST /v1/messages のレスポンスには常に diagnostics フィールドが含まれ、有効化していない場合の値は null です。そのため、このフィールドが null だからといって、API に問題があるわけではありません。

フィンガープリントにはハッシュとトークン数の推定値のみが保存され、元のプロンプト内容は保存されません。response id でインデックスされ、スコープは自組織と自 workspace に限定され、保持期間は比較的短くなっています。


3ステップで diagnostics を使い Claude のキャッシュヒット率を調査する

以下では、公式のフィールド説明に沿って3つのステップを解説します。APIYI 経由で呼び出す場合、Messages ネイティブインターフェースの base_url に https://api.apiyi.com/v1 を設定し、リクエストパスは /v1/messages になります。ただし、後述の実測パートでは、中継サービス経由での diagnostics の実際の返却状況について説明します。

claude-prompt-cache-diagnostics-hit-rate-troubleshooting-ja-image-1

ステップ1:リクエストのトップレベルに diagnostics オブジェクトを追加する

diagnostics が唯一のスイッチです。これを含まないリクエストはフィンガープリントが保存されず、後から比較しようとしても対象がありません。最初のラウンドには比較対象がないため、previous_message_id には null を渡します。これは「このラウンドから記録を開始する」という意味です。

  • リクエストヘッダーには通常のバージョン番号を残します:anthropic-version: 2023-06-01
  • 正式版以降は不要になります:anthropic-beta: cache-diagnosis-2026-04-07
  • リクエストボディのトップレベルに追加します:"diagnostics": {"previous_message_id": null}
  • キャッシュ対象の system ブロックにはいつも通りブレークポイントを打ちます:"cache_control": {"type": "ephemeral"}
  • 確認できること:レスポンスでは diagnostics が null になり、cache_read_input_tokens は通常 0、cache_creation_input_tokens は 0 より大きくなります

最初のラウンドで null が返っても失敗ではありません。このラウンドはキャッシュを書き込んでいる段階で、そもそも比較できる前のラウンドが存在しないため、トラブルシューティングは不要です。

ステップ2:2ラウンド目以降は前ラウンドのレスポンス id を毎回渡す

2ラウンド目からは、前ラウンドのレスポンスにある id を previous_message_id に入力します。最もよくあるミスは、最初のラウンドだけ diagnostics を付け、その後は付け忘れてしまうケースです。次のラウンドが指し示すリクエストが記録されていないため、結果は previous_message_not_found になります。

  • 2ラウンド目のリクエストボディ:"diagnostics": {"previous_message_id": "<1ラウンド目のレスポンス id>"}
  • 3ラウンド目のリクエストボディ:"diagnostics": {"previous_message_id": "<2ラウンド目のレスポンス id>"}
  • マルチターンのループでは、1ラウンド目に null、2ラウンド目に r1.id、3ラウンド目に r2.id という順で渡します
  • ストリーミング呼び出しでは、結果は message_start イベントに現れます。id も同じようにラウンドごとに受け渡していきます
  • 確認できること:隣接する2ラウンドの間隔が十分短く、かつ同じ workspace 内であれば、レスポンスに比較結果が現れ始めます

ステップ3:cache_miss_reason を読み取り、原因ごとに修正する

diagnostics には3種類の値があります。読み取る前にまず区別しておきましょう。

  • null:リクエストに diagnostics が付いていない、または previous_message_id が null、あるいは比較が完了して不一致が見つからなかった
  • {"cache_miss_reason": null}:比較がまだ進行中です。レスポンスの開始が早すぎたため、このラウンドでは結論を出さず、次のラウンドを確認します
  • cache_miss_reason がオブジェクトの場合:すでに結論が出ており、分岐の種類と詳細が含まれています
  • 確認できること:種類がわかったら次の節の対応表に従って修正します。最も早い分岐を先に直してください。最初の不一致点しか報告されないため、後続の問題がそれに隠れている可能性があります

🚀 クイックスタート:まず自分のキャッシュプレフィックスが書き込み・ヒットできるか確認したい場合は、APIYI apiyi.com で同じ Key を使って Claude の各モデルを切り替え、2ラウンドの比較を行ってみてください。usage 内のキャッシュ書き込みと読み取りの2つの数値が一致するかを重点的に確認しましょう。


cache_miss_reason の6タイプと修正すべき箇所

cache_miss_reason を取得したら、次の表に照らして修正箇所を特定しましょう。

タイプ 意味 修正箇所
model_changed モデルが前のターンと異なる。ルーティング、A/Bテスト、fallback でモデルが切り替わった場合など。キャッシュはモデルごとに分離される 同じキャッシュ会話の中ではモデルを固定する
system_changed system が変化した。最も多いのはタイムスタンプやリクエストIDなど、毎回異なる値が挿入されているケース system をバイト単位で安定した定数にし、動的データはブレークポイント以降の最初の user メッセージに移す
tools_changed ツールの追加・削除、順序の入れ替え、あるいは input_schema のシリアライズ結果が不安定 毎ターン同じツールリストを送信し、順序を固定し、シリアライズはキーでソートする
messages_changed 末尾への追記ではなく、それ以前のメッセージが変更・並べ替え・削除された 履歴は追記のみとし、assistant の内容とツール結果はそのまま返す
previous_message_not_found 対応するフィンガープリントが見つからない。リクエストが変わったという意味ではない 毎ターン diagnostics を付け、workspace をまたがず、間隔を空けすぎない
unavailable このターンで診断結果が取得できない。tool_choice、thinking、context_management、output_config、output_format、または beta header の集合が一致しない場合や、会話が長すぎる場合など 1つのキャッシュ会話のライフサイクル全体で、これらのパラメータを一定に保つ

4つの *_changed タイプには cache_missed_input_tokens も付属し、分岐点以降でおよそどれだけのキャッシュ可能な入力トークンが失われたかを示します。この数値はバイト長から換算したもので、桁数を判断するためだけに使い、請求額の数字ではありません。まれに usage.input_tokens より大きくなることもあります。


diagnostics だけでは誤判定しやすい:usage と組み合わせて Claude のキャッシュヒットを判断する

diagnostics が答えてくれるのは「リクエストが変わったか」であり、usage.cache_read_input_tokens が答えてくれるのは「キャッシュにヒットしたか」です。この2つは別の問いなので、片方だけを見ていると誤った結論にたどり着きやすくなります。

diagnostics の結果 キャッシュ読み取り token 結論 対応方法
null 高 プレフィックスが安定し、キャッシュヒット 対応不要
null 低または 0 リクエストは変わっていないが、キャッシュが期限切れ リクエスト間隔を短くする、または 1 時間 TTL に変更する
*_changed 低 リクエストが変わったため、ヒットしなかった 前節の対照表に沿って修正する
*_changed 高 変化が後方で発生し、手前のブレークポイントは依然ヒット 修正する価値はあるが、影響は小さい

もう一度强调しておきます:null は「効いていない」という意味ではありません。むしろ最良の結果である可能性もあります。また、この表が当てはまらないケースもいくつかあります。1回目のラウンド、cache_miss_reason が null の場合(比較がまだ進行中)、そして previous_message_not_found と unavailable の場合です。これらの状況では有効な比較がそもそも発生していません。

claude-prompt-cache-diagnostics-hit-rate-troubleshooting-ja-image-2

どのラウンドがどのマスに当てはまるかまだ分からない場合は、APIYI apiyi.com で同じリクエストを2回続けて送信し、各ラウンドのキャッシュ読み書きの数値を記録してから、上のマトリクスと照らし合わせて1つずつ切り分けていきましょう。


Claude のキャッシュヒット率が低くなるよくある原因:3つの必須条件

ヒット率が低いとき、リクエスト内容が変わったわけではなく、そもそもキャッシュが書き込まれていないことがよくあります。次の3つの条件のうち、1つでも欠けるとキャッシュは有効になりません。

  1. 必ず明示的に cache_control を付ける:具体的なコンテンツブロックに置いて明示的なブレークポイントにする方法と、リクエストの最上位に cache_control を置き、システムが最後のキャッシュ可能ブロックに自動でブレークポイントを打つ方法があります。content が単なる文字列で、マーカーを付けられるコンテンツブロックがない場合は、永遠にキャッシュされません。
  2. 最小キャッシュ長に達している:Claude API では Sonnet 5.5 も Opus 5.5 も 512 tokens です。プレフィックスが十分に長くない場合、キャッシュは静かに無視され、エラーも返りません。
  3. プレフィックスがバイト単位で同一:履歴は追記のみ、system と tools は安定したままにします。空白、JSON フィールドの順序、タイムスタンプのどれか1つでも変わると、新しいプレフィックスとみなされます。

APIYI のキャッシュドキュメントには、さらに2つの厳しい制限が記されています。1回のリクエストで cache_control ブレークポイントは最大4つまで、各ブレークポイントは直近20個の content block までしかさかのぼれません。長いマルチターン会話で最後の1件だけにマーカーを付けても、履歴全体をカバーできません。

TTL もよく見落とされます。デフォルトは5分で、ヒットするたびに延長されますが、計測は書き込みまたは読み取りを行ったそのリクエストの開始時点からで、レスポンスの終了時からではありません。ストリーミングレスポンスの出力に4分かかった場合、次のリクエストはおよそ1分以内に送る必要があります。より長いウィンドウが必要なときは、cache_control に "ttl": "1h" を書きます。


Claudeのキャッシュヒット率が0に落ちたときのコスト試算

まず価格を整理します。単位は米ドル/100万トークン、データ時点は2026年10月25日です。実際の価格はコンソールのリアルタイム価格を基準にしてください。

モデル 入力 出力 キャッシュ読み取り 5分書き込み 1時間書き込み
Claude Sonnet 5.5 $2 $10 $0.10 $2.50 $4
Claude Opus 5.5 $4 $20 $0.20 $5 $8
Claude Haiku 5.5(10万トークン以下) $0.1 $0.5 $0.01 $0.125 $0.20
Claude Haiku 5.5(10万トークン超) $0.50 $2.50 $0.05 $0.625 $1

倍率は分けて見る必要があります。APIYIのキャッシュガイドで示されている一般的な基準は、ヒット時0.1倍、5分書き込み1.25倍、1時間書き込み2倍です。Sonnet 5.5は10月7日の公式調整に伴い、キャッシュ読み取りが$0.20から$0.10に下がり、基本入力価格の0.05倍になりました。書き込み価格は変わっていません。

今回の調整は全モデルの値下げではありません。Sonnet 5のキャッシュ読み取りは依然として$0.20です。そのため、Sonnet 5.5の計算に0.1倍を当てはめないでください。具体的なモデルと価格はプラットフォームのモデル一覧を基準にしてください。

採算分岐点を、プラットフォームの一般的な0.1倍基準で計算します。5分TTLは2回再利用すれば元が取れます(1.25 + 0.1 = 1.35で、キャッシュなしの2.0を下回る)。1時間TTLは3回の再利用が必要です(2 + 0.2 = 2.2で、3.0を下回る)。

もう一つの計算例を見てみましょう。Sonnet 5.5、固定プレフィックス3万トークン、1日200回リクエスト、すべて5分TTL内の場合:

  • 全部ヒット:200 × 3万 × $0.10/100万 = $0.60。これに1回分の書き込み$0.075を加えて、合計約 $0.675/日
  • 全部ミス:200 × 3万 × $2/100万 = $12/日

両者の1日あたりの請求額の差は約17.8倍です。これは単価の差ではありません。単価は$2対$0.10で、20倍の差があります。1時間TTLに変えると、1回の書き込みは$0.12で、ヒット価格は変わりません。リクエスト間隔がよく5分を超える場合は、書き込み費用が増える分と、プレフィックスを何度も再構築する費用のどちらが安いかを比較してみてください。

claude-prompt-cache-diagnostics-hit-rate-troubleshooting-ja-image-3

APIYI 経由で Claude のキャッシュヒット率を調査する方法

まず実測結果です。2026-10-26 に APIYI 上で Claude Sonnet 5.5 を使い、2 回実行しました。1 回目はキャッシュ書き込み 2523、読み取り 0。2 回目は同じ内容をそのまま送り返すと、キャッシュ読み取り 2523、書き込み 0 となり、トークン数も完全に一致しました。Claude Opus 5.5 でも長いプレフィックスで書き込みが発生し、ヒットすることも確認できました。

ただし、レスポンスには diagnostics フィールドがありません。非ストリーミング呼び出しにも、ストリーミング呼び出しの message_start にもありません。さらにベータヘッダーを付けて再送し、system をわざと変更して実際にミス(読み取り 0、書き込み 2526)も発生させましたが、それでもレスポンスにこのフィールドはありませんでした。すべてのリクエストは 200 を返し、エラーはありませんでした。API中継サービス層の上流経路は必ずしも公式の Claude API とは限らないため、中継サービス経由のケースでは主に usage 内の 2 つのフィールドを突き合わせて確認します。

セルフチェックで見られる現象 意味
今回の cache_read_input_tokens が前回の cache_creation_input_tokens と正確に一致 プレフィックスが完全にヒット
今回の読み取りが前回の書き込みより明らかに少ない より前の一部分だけがヒットし、途中の内容が変わっている
書き込みがずっと 0 マークが付いていない、長さが足りない、または OpenAI 互換形式を使っている
2 回目も書き込みが発生し、読み取りが 0 プレフィックスが変わっている。タイムスタンプ、UUID、シリアライズ順を確認

さらに特に注意したいのは、キャッシュはネイティブの /v1/messages でのみ有効という点です。OpenAI 互換形式の /v1/chat/completions で Claude を呼び出す場合、どのようにパラメータを渡してもキャッシュの課金情報は取得できません。

💡 調査のヒント:APIYI(apiyi.com)は cache_control をそのまま上流へ転送し、レスポンスの 2 つのキャッシュ関連フィールドもそのまま返します。コード側で API中継サービス層向けの追加対応は不要です。「今回の読み取り = 前回の書き込み」をログアラートにすれば、手作業による切り分けの大半を置き換えられます。


Claude キャッシュ診断 diagnostics の制限

diagnostics は万能ではありません。使う前に、その境界を理解しておきましょう。

  • 公式 Claude API でのみ提供されており、Amazon Bedrock や Google Cloud でホストされる Claude にはありません
  • フィンガープリントは短期間しか保持されないため、連続する複数ターンで短い間隔をあけてリクエストを送る必要があります
  • 2回のリクエストは同じ組織かつ同じ workspace に属している必要があり、レスポンスヘッダー anthropic-workspace-id で確認できます
  • 長い会話では、変化がメッセージリストの深い位置に隠れている場合、unavailable しか返ってこないことがあります
  • これはベストエフォートの仕組みであり、結果が取得できなくてもリクエストをブロックしたり、失敗させたりすることはありません

よくある質問 FAQ

Q1:なぜ diagnostics がずっと null なのでしょうか?

3つのケースが考えられます。`diagnostics` オブジェクトを付けてない、現在が最初のターンで `previous_message_id` が `null` である、比較が完了して相違がない、のいずれかです。キャッシュの読み取り値と合わせて判断しましょう。読み取り値が高ければすべて正常で、0 の場合はほとんどがキャッシュ切れです。中継サービス経由の場合、フィールド自体が返ってこないことがあるので、そのときは usage による自己チェックに切り替えてください。

Q2:previous_message_not_found はリクエストが変わったことを意味しますか?

いいえ。対応するフィンガープリントが見つからないことだけを示しています。よくある原因は3つです。前のターンで `diagnostics` を付けていなかった、前のターンが別の workspace からのものだった、間隔が空きすぎた、のいずれかです。毎ターン `diagnostics` を付けて間隔を短くすれば解決します。

Q3:診断には追加料金がかかりますか?

公式ドキュメントでは「診断費用」を独立した項目として挙げておらず、通常の Messages リクエストと一緒に課金されます。追加料金がないと明記もされていないため、課金については請求書とコンソールを基準にしてください。

Q4:中継サービス経由でもこの診断は使えますか?

APIYI での実測では `diagnostics` フィールドは取得できませんでしたが、キャッシュの書き込みとヒットは正常でした。「今回の読み取りが前回の書き込みと正確に一致するか」で判断できます。接続方法は APIYI apiyi.com のキャッシュ課金ドキュメントを参照してください。

Q5:cache_control を書いたのに一度もキャッシュされないのはなぜですか?

まず3点を確認しましょう。content が純粋な文字列になっているか、プレフィックスが 512 トークンに達しているか(Sonnet 5.5 と Opus 5.5)、OpenAI 互換形式を使っていないか、の3つです。いずれか1つでも満たしていないと、キャッシュはサイレントにスキップされます。

Q6:複数の問題が同時に発生した場合、どれから直すべきですか?

まず `cache_miss_reason` が報告したものから直しましょう。最初の分岐点だけが報告されるため、それを直してからもう一度実行すると、背後に隠れていた問題が現れてきます。APIYI apiyi.com 上で同じリクエストを繰り返し再生すれば、比較的早く1つずつ潰していけます。


Claude キャッシュ診断の核心ポイント(Key Takeaways)

  • diagnostics とは:直前のレスポンス id を渡して、プレフィックスの最初の分岐箇所を特定するもの
  • 有効化の方法:トップレベルに diagnostics を置き、1回目は null を渡し、以降は毎回渡す
  • null の意味:1回目や分岐がない場合も null になるため、これ単体を障害のシグナルとは見なせない
  • 判定の仕方:diagnostics と cache_read_input_tokens を併せて見て初めて結論が出せる
  • 必須条件:明示的なマーキング、512 tokens への到達、プレフィックスのバイト単位での一致
  • コスト差:3万トークンのプレフィックスを1日200回呼ぶ場合、1日の請求額は約17.8倍の差になる
  • 中継サービスのセルフチェック:APIYI apiyi.com 上で「今回の読み込みが前回の書き込みと一致するか」を確認する

まとめ

Claude のキャッシュヒット率の調査は、次の3点に集約できます。

  1. 分岐の特定:毎回 diagnostics を付けて cache_miss_reason を読み、最初に報告された箇所から修正する
  2. クロスチェック:diagnostics と usage の両方を見る。null は「効果がない」という意味ではない
  3. 必須条件の遵守:マーキングを徹底し、長さを満たし、履歴は追記のみとし、system と tools は安定させる

呼び出し経路で diagnostics が取得できない場合は、usage の2つのフィールドでセルフチェックを組み立てましょう。まず APIYI apiyi.com で2回のリクエストを送り、キャッシュの読み書きの数値を検証してから、本番環境に展開することをおすすめします。

📚 参考資料

  1. Claude 公式ドキュメント:Cache diagnostics — 診断フィールド、6つのタイプ、判断マトリクス
  2. リンク:platform.claude.com
  3. 説明:本記事の diagnostics に関するフィールド、タイムライン、制限は、すべてこのドキュメントに準拠しています

  4. Claude 公式ドキュメント:Prompt caching — キャッシュ規則、TTL、最小長、料金

  5. リンク:platform.claude.com
  6. 説明:キャッシュ可能な最小長および公式価格表の出典です

  7. APIYI モデル一覧:Claude 各モデルの入力・出力・キャッシュ読み取り価格

  8. リンク:docs.apiyi.com/models
  9. 説明:価格データは 2026-10-25 に更新されたものです

  10. APIYI Claude Prompt Caching キャッシュ課金ガイド:倍率、損益分岐点、セルフチェックの判断基準

  11. リンク:docs.apiyi.com/api-capabilities/claude-prompt-caching
  12. 説明:API中継サービス環境でのトラブルシューティングの根拠となる資料です

著者:APIYI 技術チーム
技術的なやり取り:APIYI のウェブサイトトップページからお気軽にお問い合わせください。詳しい資料は docs.apiyi.com のドキュメントセンターでご覧いただけます

関連記事

類似投稿