はじめに

この記事では、Anthropic Claudeのプロンプトキャッシュについてまとめました。

Anthropoc Caludeとは

Anthropic Claudeは、Anthropic社が開発した高度なAI言語モデルです。
このモデルは、自然言語処理タスクにおいて高い性能を発揮し、特に会話型AIやテキスト生成、分析などの用途に適しています。

Anthropic Claudeは、AWSやGoogle Cloudなどのクラウドプラットフォームを通じて利用可能であり、さまざまな業界で活用されています。

Anthropic Claudeのプロンプトキャッシングの仕組み

プロンプトキャッシングを導入すると、指定したプロンプトをキャッシュすることができます。

キャッシュするとキャッシュブレークポイント(cache_control)が設定されているプロンプトのプレフィックス(先頭部分)が、キャッシュされているかを確認します。

キャッシュされている場合、プレフィックス部分のプロンプトを再利用することで、LLM側での内部処理が不要になり、処理時間とコストを削減することができます。
キャッシュされていない場合は、プロンプト全体を新規に処理した後に、プロンプトのプレフィックスを保存します。
この仕組みにより、繰り返し使用されるプロンプトの再処理を避け、システム全体の効率を向上させています。

OpenAIにも同様にプロンプトキャッシュが導入されています。
GoogleのGeminiシリーズにもコンテキストキャッシュという名称は異なりますが、同様の機能があります。

キャッシュにはサービス側で自動キャッシュしてくれる暗黙的キャッシュと、ユーザーがキャッシュする箇所を指定する明示的キャッシュがあります。 この記事は明示的キャッシュについて紹介します。


プロンプトキャッシュの料金

料金

キャッシュの料金は以下の通りです。

  • キャッシュ書き込み: 入力トークンよりも25%高価格
  • キャッシュ読み取り: 入力トークンよりも90%低価格

初回に発生するキャッシュの書き込みでは、料金が上がってしまいますが、複数回LLMとの会話が行われると、キャッシュが活用されるので、その分料金が安くなります。

サポートモデル

プロンプトキャッシュをサポートしているモデルは以下になります。

  • Claude Sonnet系は3.5以降
  • Claude Haikua系は3以降
  • Claude Opus系は3以降

プロンプトキャッシュ


プロンプトキャッシュの利用方法

プロンプトキャッシュを利用するにはClaudeのAPIをコールする際にcache_controlパラメータを指定します。

  • cache_controltypeで指定できるタイプは現状はephemeralのみなので、実質固定値
  • ephemeralは「一瞬の~」という意味
curl <https://api.anthropic.com/v1/messages> \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-3-7-sonnet-20250219",
    "max_tokens": 1024,
    "system": [
      {
        "type": "text",
        "text": "You are an AI assistant tasked with analyzing literary works. Your goal is to provide insightful commentary on themes, characters, and writing style.\n"
      },
      {
        "type": "text",
        "text": "<the entire contents of Pride and Prejudice>",
        "cache_control": {"type": "ephemeral"}
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "Analyze the major themes in Pride and Prejudice."
      }
    ]
  }'

プロンプトキャッシュが設定されたいリクエストを送信すると、初回はキャッシュにプロンプトを書き込み、2回目にリクエストしたときに、プロンプトキャッシュ内にキャッシュがあるかどうかを判定し、キャッシュがヒットした場合は、キャッシュされたプロンプトを再利用します。これにより、処理時間を短縮し、コストを削減することができます。

プロンプトキャッシュを有効にした場合、APIレスポンス内の以下のフィールドにキャッシュ書き込みしたトークン数とキャッシュ読み取りしたトークン数が表示されます。
(ストリーミング時は message_start イベント内)

  • cache_creation_input_tokens: キャッシュ書き込みしたトークン数
  • cache_read_input_tokens:キャッシュ読み込みにより削減された入力トークン数
  • input_tokens:キャッシュ分を除いた入力トークン数
# 1回目でプロンプトキャッシュへの書き込みが発生 (入力トークンのうち、188086トークンのキャッシュ書き込み、21トークンがキャッシュされなかった)
{"cache_creation_input_tokens":188086,"cache_read_input_tokens":0,"input_tokens":21,"output_tokens":393}

# 2回目でキャッシュされた分を読み込み (前回キャッシュした188086トークンをキャッシュから読み込み)
{"cache_creation_input_tokens":0,"cache_read_input_tokens":188086,"input_tokens":21,"output_tokens":393}

プロンプトキャッシュの制限

プロンプトキャッシュを使用する際の制限事項について記載します。

キャッシュ可能な最小プロンプト長

以下より短いプロンプトは、cache_controlでマークされていてもキャッシュされません。

  • Claude Opus 4.6、Claude Opus 4.5の場合:4096トークン
  • Claude Sonnet 4.6の場合:2048トークン
  • Claude Sonnet 4.5、Claude Opus 4.1、Claude Opus 4、Claude Sonnet 4、Claude Sonnet 3.7(非推奨)の場合:1024トークン
  • Claude Haiku 4.5の場合:4096トークン
  • Claude Haiku 3.5(非推奨)とClaude Haiku 3の場合:2048トークン

キャッシュの制限

設定可能なキャッシュブレークポイント

cache_controlが設定されているメッセージの位置をキャッシュブレークポイントといいます。
Claudeではメッセージの開始からキャッシュブレークポイントが設定されているところまでをキャッシュします。
1リクエストで設定可能なキャッシュブレークポイント(cache_control)の数は最大4つまです。

messages=[
    {
        "role": "user",
        "content": "1. こんにちは",
    },
    {
        "role": "assistant",
        "content": "2. こんにちは",
    },
    {
        "role": "user",
        "content": "3. 今日の天気はなんですか?",
        "cache_control": {"type": "ephemeral"} # ここより上にあるものがキャッシュ判定されるので、1~3までをキャッシュ
    }
]

キャッシュの有効期間

キャッシュの有効期間(TTL)は最低5分間です。
ただし、キャッシュの有効期間は、キャッシュされたプロンプトが使用されると、更新され、期間を延長することができます。

キャッシュ可能な要素

  • ツール: ツール配列内で定義したツール要素ブロック
  • システムメッセージ: system配列内のコンテンツブロック
  • メッセージ: messages.content配列内のコンテンツブロック(ユーザーの入力とアシスタントの出力の両方)
  • 画像とドキュメント: ユーザーが入力したmessages.content配列内のコンテンツブロック
  • ツールの使用とツールの結果: messages.content配列内のコンテンツブロック (ユーザーの入力とアシスタントの出力の両方)

キャッシュの共有

キャッシュは組織間で共有されておらず、分離されています。
そのため、同一のプロンプトであっても、他の組織が使用しているプロンプトキャッシュを使用することはできません。

完全一致

キャッシュヒットには、cache controlでマークされたブロックまでのすべてのテキストと画像を含むプロンプトセグメントが100%同一である必要があります。
同じブロックがキャッシュの読み取りと作成時にcache controlでマークされている必要があります。


プロンプトキャッシュのユースケース

  • 1回当たりの入力トークン数が多いプロンプトを処理する必要があるケース
  • ユーザーとLLMの会話がマルチターン(複数回行われる)のケース

キャッシュブレークポイントの位置による検証

キャッシュブレークポイントのイメージを掴むために、キャッシュの位置によって、プロンプトキャッシュがどのような挙動になるか検証します。

1. 初回書き込み: キャッシュブレークポイントを末尾に追加してリクエスト

キャッシュブレークポイントポイントを末尾に設定した以下のメッセージを送信したとします。

messages:
  1 role: [user], text: [user1...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]

この場合は初回のリクエストになるので、キャッシュの書き込みが発生しますが、読み込みは発生しません。

cache_tokens. write: [5415], read: [0]
tokens. input: [3], output: [182]

キャッシュブレークポイントなしで送信した場合

先ほどと同じメッセージで、キャッシュブレークポイントを設定せずに送信します。

messages:
  1 role: [user], text: [user1...略], cache_control: []

キャッシュブレークポイントを指定していないと、キャッシュの書き込みも読み込みも発生しません。

cache_tokens. write: [0], read: [0]
tokens. input: [5418], output: [179]

assistantの回答とuserのプロンプトを追加して送信

assistantの返答とuserの返信文をメッセージに追加します。

messages:
  1 role: [user], text: [user001...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]
  2 role: [assistant], text: [assitant...略], cache_control: []
  3 role: [user], text: [user001 reply...略], cache_control: []

この場合はキャッシュブレークポイントを設定したuser001...略の部分のメッセージが前回書き込みしたキャッシュと一致するため、キャッシュの読み込みが発生し、入力トークンを削減することができます。

cache_tokens. write: [0], read: [5415]
input: [188], output: [31]

2. キャッシュブレークポイントを複数追加してリクエスト

1.でキャッシュ書き込みをした状態で、末尾に新たにキャッシュブレークポイントを追加し、キャッシュブレークポイントを複数設定した状態で送信します。

messages:
  1 role: [user], text: [user001...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]
  2 role: [assistant], text: [assitant001...略], cache_control: []
  3 role: [user], text: [user001 reply...略], cache_control: []
  4 role: [user], text: [user002...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]

前回キャッシュ済みのuser001...略読み込みと、新たに追加したassistant001...略~user002...略のキャッシュへの書き込みが発生します。

cache_tokens. write: [1190], read: [5415]
tokens. input: [3], output: [39]

assistantの回答とuserのプロンプトを追加して送信

新たにメッセージを追加して、送信します。

messages:
  1 role: [user], text: [user001...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]
  2 role: [assistant], text: [assitant001...略], cache_control: []
  3 role: [user], text: [user001 reply...略], cache_control: []
  4 role: [user], text: [user002...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]
  5 role: [assistant], text: [assistant002...略], cache_control: []
  6 role: [user], text: [user002...略], cache_control: []

前回キャッシュ済みのuser001...略assistant001...略~user002...略の部分が、キャッシュ読み込みされて、入力トークンが削減されます。

cache_tokens. write: [0], read: [6605]
tokens. input: [48], output: [29]

3. キャッシュブレークポイントを末尾にスライドリクエスト

1.のキャッシュ書き込みをした状態で、2.ようにもとのキャッシュブレークポイントに追加するのではなく、末尾にスライドした状態でリクエストを送信します。
前回書き込みしたキャッシュの読み込みと、新たに追加したプロンプトのキャッシュへの書き込みが発生する。

messages:
  1 role: [user], text: [user001...略], cache_control: []
  2 role: [assistant], text: [assitant001...略], cache_control: []
  3 role: [user], text: [user001 reply...略], cache_control: []
  4 role: [user], text: [user003...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]
cache_tokens. write: [1190], read: [5415]
tokens. input: [3], output: [145]

assistantの回答とuserのプロンプトを追加して送信

新たにメッセージを追加して、送信します。

messages:
  1 role: [user], text: [user001...略], cache_control: []
  2 role: [assistant], text: [assitant001...略], cache_control: []
  3 role: [user], text: [user001 reply...略], cache_control: []
  4 role: [user], text: [user003...略], cache_control: [{'type': 'ephemeral', 'ttl': '5m'}]
  5 role: [assistant], text: [assitant003...略], cache_control: []
  6 role: [user], text: [user003 reply...略], cache_control: []

前回キャッシュ済みのuser001...略~user003...略の部分が、キャッシュ読み込みされて、入力トークンが削減されます。

cache_tokens. write: [0], read: [6605]
tokens. input: [154], output: [31]

実質的には2のときと同様の挙動を示すことになります。
一般的なマルチターンのチャットアプリであれば、会話が末尾に追加されていことになるので、2のように複数のキャッシュブレークポイントを設定する必要はなく、3のように末尾に追加することで、適切にキャッシュできるでしょう。

2のように複数キャッシュブレークポイントを設定する場合は、ツールなどを用いるより複雑な要件の場合に使用することになると思われます。


おわりに

この記事では、プロンプトキャッシュについて紹介しました。
プロンプトキャッシュを活用することで、処理時間と料金を削減することができるので、有効活用しましょう。