Claudeのプロンプトキャッシュの失敗の原因を検知してみる

Claudeのプロンプトキャッシュの失敗の原因を検知してみる

Claude API に Cache diagnostics という機能が追加されたので、キャッシュが利用されない原因を検知できるか試してみました。
2026.05.26

リテールアプリ共創部の末永です。

Claude のプロンプトキャッシュは、長いシステムプロンプトや tool 定義を使うアプリケーションで、コストやレイテンシを抑えるために使える機能です。

ただ、プロンプトキャッシュが利用されなかったときに、原因を追うのは少し面倒です。Cache diagnostics という機能が追加されたので、キャッシュが利用されない原因を検知できるか試してみました。

Cache diagnostics で分かること

Claude の Prompt caching は、プロンプトの先頭部分が前回リクエストと一致している場合に利用されます。system prompt に timestamp を埋め込んだり、tool の順番が変わったりすると、意図せずキャッシュ対象の先頭部分(prefix)が変わります。

Cache diagnostics では、前回レスポンスの id を次のリクエストに渡すことで、前回と今回のリクエストのどこが変わったかを確認できます。

Cache diagnostics closes that gap. Pass the id of your previous response, and the API compares the two requests and tells you where they diverged (the model, the system prompt, the tools, or the message history) so you can fix the root cause instead of guessing.

Cache diagnostics - Anthropic Docs

返ってくる cache_miss_reason.type には、system_changedtools_changed などがあります。system prompt が変わった、tool 定義が変わった、message history が変わった、といった原因をレスポンスから見られるようになります。

image

Prompt caching には、リクエスト全体に cache_control を付けて cache breakpoint を自動で進める方法と、コンテンツブロックに明示的に cache_control を付ける方法があります。今回は system prompt を変えたときに system_changed を検知したいため、後者の Explicit cache breakpoints を使います。

なお、diagnostics は「リクエストが変わったか」を見るための情報です。実際にキャッシュがヒットしたかは usage.cache_read_input_tokens 側を見る必要があります。

AI SDK の呼び出しに diagnostics を足す

今回の検証では Vercel AI SDK を使いました。AI SDK の Anthropic provider には Prompt caching 用の cacheControl がありますが、Cache diagnostics の diagnostics.previous_message_id は通常のオプションから直接渡せなかったため、createAnthropicfetch で body に追加しています。

該当部分だけ抜き出すと次のような感じです。

const anthropic = createAnthropic({
  headers: {
    "anthropic-beta": "cache-diagnosis-2026-04-07",
  },
  fetch: async (input, init) => {
    const headers = new Headers(init?.headers);
    headers.set("anthropic-beta", "cache-diagnosis-2026-04-07");

    const body = JSON.parse(String(init?.body)) as Record<string, unknown>;
    body.diagnostics = {
      previous_message_id: previousMessageId,
    };

    const response = await fetch(input, {
      ...init,
      headers,
      body: JSON.stringify(body),
    });

    lastResponse = await response.clone().json();
    return response;
  },
});

Cache diagnostics は beta header が必要なので、anthropic-beta も付けています。レスポンスは response.clone().json() で読み、diagnostics を後続の処理で使えるようにしています。

キャッシュ対象にしたい system message には、AI SDK の providerOptionscacheControl を付けます。

const messages: ModelMessage[] = [
  {
    role: "system",
    content: systemPrompt,
    providerOptions: {
      anthropic: {
        cacheControl: { type: "ephemeral" },
      },
    },
  },
  {
    role: "user",
    content: "~",
  },
];

あとは通常どおり generateText を呼びます。

const result = await generateText({
  model: anthropic(MODEL),
  messages,
});

補足ですが、AI SDK では messages 配列に role: "system" を含めると warning が出ます。system prompt は top-level の system option に渡す形が推奨されています。

cache_miss_reason を Langfuse で WARNING にする

今回見たいのは、キャッシュが利用されなかったときに原因を検知できるかです。そこで、cache_miss_reason.type*_changed だった場合に Langfuse の observation を WARNING にします。

function warningFromDiagnostics(diagnostics: Diagnostics | undefined) {
  const reason = diagnostics?.cache_miss_reason;

  if (!reason) {
    return undefined;
  }

  if (reason.type.endsWith("_changed")) {
    return `Claude cache diagnostics warning: ${reason.type}`;
  }

  return `Claude cache diagnostics inconclusive: ${reason.type}`;
}

この関数を使って、Langfuse の generation に levelstatusMessage を設定します。

const warning = warningFromDiagnostics(lastResponse?.diagnostics);

generation.update({
  output: {
    text: result.text,
    diagnostics: lastResponse?.diagnostics ?? null,
    cacheReadTokens: result.usage.inputTokenDetails.cacheReadTokens,
    cacheWriteTokens: result.usage.inputTokenDetails.cacheWriteTokens,
  },
  level: warning ? "WARNING" : "DEFAULT",
  statusMessage: warning ?? "No cache-prefix divergence reported.",
});

今回は system prompt の一部を変えて、意図的に system_changed が返る状態を作りました。これで Langfuse 上でも、該当の generation が WARNING として見れます。

キャッシュされないケースを確認する

検証では、キャッシュ対象にしている system prompt の一部だけを変えました。

この状態で前回レスポンスの iddiagnostics.previous_message_id に渡すと、cache_miss_reasonsystem_changed が返りました。

スクリーンショット 2026-05-26 8.53.53
スクリーンショット 2026-05-26 8.54.20

画像の cacheReadTokens が 0 になっていることからも、このリクエストではキャッシュが利用されていないことが分かります。

最後に

Cache diagnostics を使うと、プロンプトキャッシュが利用されなかった原因を API レスポンスとして確認できました。

すべてのアプリケーションに必須というより、長いシステムプロンプトや tool 定義をキャッシュしていて、キャッシュミスがコストやレイテンシに影響しやすい場合に入れておくと便利そうです。ここでは Langfuse を使用していますが、他の観測ツールでももちろん活用できます。

では👋


生成AI活用はクラスメソッドにお任せ

過去に支援してきた生成AIの支援実績100+を元にホワイトペーパーを作成しました。御社が抱えている課題のうち、どれが解決できて、どのようなサービスが受けられるのか?4つのフェーズに分けてまとめています。どうぞお気軽にご覧ください。

生成AI資料イメージ

無料でダウンロードする

この記事をシェアする

関連記事