Prompt Cachingの仕様はAnthropicの公式サイトに詳しい説明があります。
とはいえ、うまく理解できない部分があったため、実際に動かして理解を深めてみました。
また、理解を深められたことで、状況に応じてこう使えばいいんだと気づきを得た部分もありました。
半分自分のメモなので簡略化している部分もありますが、どなたかの参考になれば幸いです。
前提
- Prompt Cachingの基本的な内容・使い方については、先日の私の記事をご覧いただけますと幸いです
-
本記事で利用しているソースも上記記事がベースとなります
-
Amazon Bedrock経由で実行していますが、この記事では冒頭のAnthropic公式サイトを参照しています(基本的に動きは同じ認識であるため、より詳しく書かれている方を参照しています)
試したこと一覧
試した内容の一覧です。
- message(ユーザーメッセージ)にだけチェックポイントを置けば、sysytem、toolもキャッシュされる
- message(ユーザーメッセージ)、sysytem、toolの合計がキャッシュの最小トークン数を超えたらキャッシュされる
- キャッシュを利用するには完全一致である必要がある
- 既にキャッシュが効いている状態で増分をキャッシュする際、増分は最小トークン数未満でOK
試したこと詳細
確認1.message(ユーザーメッセージ)にだけチェックポイントを置けば、sysytem、toolもキャッシュされる
以下の内容でmessageにだけチェックポイントを置いて実行してみます。
- tool:playwright mcpのツールをすべてセット
- system:[{'type': 'text', 'text': 'あなたはPlaywright MCPでブラウザ画面を操作するAIアシスタントです'}]
- message:[{'type': 'text', 'text': "[{'type': 'text', 'text': 'こんにちは'}]"}, {'cachePoint': {'type': 'default'}}]
↓
3538トークンのキャッシュ書き込みが確認できます。
{'input_tokens': 4, 'input_token_details': {'cache_creation': 3538, 'cache_read': 0}}
(output_tokens,total_tokensは省略しています。後続の説明も同様です。)
ここから、一応、本当にsysytemとtoolも含まれているか?の確認です。
追加確認:systemがキャッシュされていることの確認
以下のとおり、systemを微妙に修正して実行します。
- あなたはPlaywright MCPでブラウザ画面を操作する
超優秀なAIアシスタントです
↓
結果、書き込まるトークン数が3538→3543と少し増えます。
よって、systemもキャッシュされていたことが確認できます。
{'input_tokens': 4, 'input_token_details': {'cache_creation': 3543, 'cache_read': 0}}
追加確認:toolがキャッシュされていることの確認
toolをなしにして実行します。
↓
結果、入力トークン数自体が大幅に減ってキャッシュされなくなります。
よって、toolもキャッシュされていることが確認できます。
{'input_tokens': 61, 'input_token_details': {'cache_creation': 0, 'cache_read': 0}}
公式サイトでの記述
ちなみに、以前の私の記事だと、systemにだけチェックポイントを置いてtoolをキャッシュさせていたのですが、これはtool→system→messageの順番で先頭からチェックポイントまでをキャッシュする仕様であるため、systemにキャッシュポイントを置けばtoolもキャッシュされるということになります。
確認2. message(ユーザーメッセージ)、sysytem、toolの合計がキャッシュの最小トークン数を超えたらキャッシュされる
前提
一定のトークン数がないとキャッシュされない仕様となっています。
最小トークン数はモデルによって異なります。
確認1で用いたのはsonnet 4.5で、その最小トークン数は1024です。
確認の都合上、ここでは最小トークン数:4096であるhaiku 4.5を用いて確認します。
haiku 4.5で実行
1の内容でモデルだけ変えてそのまま実行します。
↓
結果、3542は、最小トークン数:4096に達していないのでキャッシュされません。(ちなみに3542の大半はtool)
{'input_tokens': 3542, 'input_token_details': {'cache_creation': 0, 'cache_read': 0}}
次に、sysytemのトークン数を増やします。
だいぶ無理やりですがこんな感じで
- system:[{'type': 'text', 'text': 'あなたはPlaywright MCPでブラウザ画面を操作するAIアシスタントです。以降、prompt cachingの最小トークン数を満たすためのダミーデータです。ダミーデータダミーデータ・・・(略)'}]
↓
結果、4162( > 4096)でキャッシュが効くようになりました。
元々は大半がtoolでしたので、tool・systemそれぞれ単独では4096に達していませんが、合計で4096を超えたらキャッシュされることが確認できました。
{'input_tokens': 4, 'input_token_details': {'cache_creation': 4162, 'cache_read': 0}}
公式サイトでの記述
この動作は以下の記述の「the entire prompt」部分だと解釈しています。

確認3.キャッシュを利用するには完全一致である必要がある
確認1では3538トークンがキャッシュされました。
完全に同じ内容で再実行すると、キャッシュが利用されていることが確認できます。
{'input_tokens': 4, 'input_token_details': {'cache_creation': 0, 'cache_read': 3538}}
messageの「こんにちは」を「何ができるか教えてください」に変えてみます。
結果、キャッシュは一切利用されず、別途キャッシュが書き込まれました。
{'input_tokens': 4, 'input_token_details': {'cache_creation': 3541, 'cache_read': 0}}
解説
公式だと以下の記述があります。
- Exact Matching: Cache hits require 100% identical prompt segments, including all text and images up to and including the block marked with cache control
そのため、tool・systemまでは一致していても、チェックポイントが置かれているmessageまで一致しないとキャッシュ読込されないということになります。
学び
ですので、どこにチェックポイントを置くべきか?は構築するAI機能の内容次第です。
systemまでは毎回一致するけど、messageは一致しないAI機能においては、systemの方にチェックポイントを置いておく必要があります。
試しに、systemにチェックポイントを置いて実行してみます。(messageの方は外しておきます。)
messageを「こんにちは」で実行すると、3197トークンキャッシュされます。(toolとsystemのみキャッシュ)
{'input_tokens': 345, 'input_token_details': {'cache_creation': 3197, 'cache_read': 0}}
続けて、messageを「何ができるか教えてください」で実行します。
すると、今度はキャッシュ読込されていることが確認できます。
{'input_tokens': 348, 'input_token_details': {'cache_creation': 0, 'cache_read': 3197}}
確認4. 既にキャッシュが効いている状態で増分をキャッシュする際、増分は最小トークン数未満でOK
確認したい内容
公式だと、利用用途の1つに「Long multi-turn conversations」、つまり会話履歴を保持するAI機能が挙げられています。
毎回のAI呼び出しの際に、これまでの会話履歴も一緒にプロンプトで渡すケースです。
毎回のAI呼び出し時のプロンプト構成は以下のようなイメージです。
- 1回目:tool、system、message(1)
- 2回目:tool、system、message(1)、message(2)
- 3回目:tool、system、message(1)、message(2)、message(3)
prompt cachingを利用する際には、最後のメッセージ部分にチェックポイントを置きます。
確認1から1回目のtool、system、message(1)はキャッシュできています。
ここで確認したいのは、 2回目以降の増分が単独で最小トークン数に満たなくても追加でキャッシュできるか? が確認したい内容です。
(例えば、2回目でmessage(2)部分が最小トークン数に満たなくてもキャッシュされるか?)
確認内容
Playwright MCPを用いて、あるウェブサイトにアクセスして、スクリーンショットを撮ってもらうように指示しました。
(会話履歴ではありませんが、Playwright MCPを利用した指示も同様にstate(履歴)を保持して、各ステップでAIを呼び出す際に履歴を渡すようになっています。)
↓
結果
- ステップ1:人間の指示を解釈し、1つ目のPlaywright操作として指定されたウェブページにアクセス
{'input_tokens': 4, 'input_token_details': {'cache_creation': 3611, 'cache_read': 0}}
- ステップ2:1つ目の操作結果を踏まえて、スクリーンショットを撮る
{'input_tokens': 7, 'input_token_details': {'cache_creation': 1668, 'cache_read': 3611}}
- ステップ3:ステップ1,2の結果を踏まえて、開いたページの説明を行う
{'input_tokens': 7, 'input_token_details': {'cache_creation': 272, 'cache_read': 5279}}
(各ステップの説明は実行結果ではなく記事の説明用に記載したものです)
AIは3回呼び出しています。
1回目では、3611キャッシュ書き込みしています。
2回目では、1回目の3611をキャッシュ読込しつつ、追加で1668キャッシュ書き込みしています。
3回目では、5279キャッシュ読込しています。これは1回目・2回目のキャッシュ書き込み分です。
また、272キャッシュ書き込みしています。※最小トークン数:1024に満たなくても増分はキャッシュされることが確認できます。これはうれしいですね!
公式サイトでの記述
増分は最小トークン数でなくてもOKという明確な記述は見つけられませんでした。
(キャッシュ済みと増分とで新たに1つのキャッシュを作るという考え方なのかも?と推測しました)
踏まえて考えたこと
langgraphにも、strands agentにも会話履歴が長くなったときに、要約する等の機能があるかと思います。
ただ、確認3のとおり、キャッシュを効かせるには完全一致させる必要があるので、これをやるとキャッシュが効かなくなります。
増分は最小トークン数に満たなくてもOKととてもうまくキャッシュさせることができ、キャッシュヒットさせるとコスト1/10ですので、よほど削減できるケースを除いて、会話履歴を削減するよりもキャッシュさせておく方が有効なケースは多そうです。
ここはprompt cachingの登場によってアプローチが変わったところだなと思いました。
公式だと「Prompt caching is a powerful feature」から始まっていますが、まさしくそのとおりだなと思いました!
その他
動作確認していないが、調べて気づいた内容を記載します。
Bedrockの1分間トークン上限はキャッシュ読込分はノーカウント
Bedrock経由での実行時、1分間のトークン数上限があります。(Service Quotas)
例えば、sonnet 4.5だと1分間でデフォルト20万トークンです。
(「Cross-region model inference tokens per minute for Anthropic Claude Sonnet 4.5 V1」)
(Globalの方(「Cross-region model inference tokens per minute for Anthropic Claude Sonnet 4.5 V1」)だと50万トークン)
ただ、prompt cachingでキャッシュ読込できた部分はこれにカウントしないそうです。
※「CacheReadInputTokens don't contribute to this calculation.」とある
Anthropic公式では、「This approach significantly reduces processing time and costs」とコストと速度がメリットと記載されていますが、Bedrock経由の場合は、1分間のトークン数上限に引っかかりづらくなることが3つ目のメリットと言えそうだなと思いました。