Re:ゼロから始めるML生活

どちらかといえばエミリア派です

OpenAI, Claude, Geminiのプロンプトキャッシュについて調べる

プロンプトキャッシングについて調査してみた記録です。

生成AI系のAPIはたくさんあると思うんですが、そのコスト削減策について調べていました。 少し調べてみるとわかったこととして、2024年ごろからプロンプトのキャッシュを効かせる機能が登場したようで、このキャッシュを上手に使うとコストを下げられるようでした。

今回はその仕様について調べてみたのでそのメモです。

プロンプトキャッシュ

プロンプトキャッシュを調べてみると、こんな感じの紹介があります。

簡単に言うとプロンプトの先頭から指定の位置までをキャッシュしてくれて、キャッシュを利用できた場合はAPI使用料金と、APIでかかる処理時間が大幅に改善するというものです。 Claudeのprompt cachingを活用する - Algomatic Tech Blog

要するに先頭からある部分までプロンプトをキャッシュしてくれ、2回目以降の同じプロンプトが入力された場合にはキャッシュが利用されてキャッシュされた分だけ低コストになるというものです。

OpenAI

具体的に各社のドキュメントで確認してみます。

OpenAI routes API requests to servers that recently processed the same prompt, making it cheaper and faster than processing a prompt from scratch. This can reduce latency by up to 80% and cost by 50% for long prompts. OpenAI Platform

この図が説明としてはわかりやすいですね。

https://platform.openai.com/docs/guides/prompt-caching より引用

過去に入力されたプロンプトがあるときに、先頭からプロンプトが共通していた場合にその部分までの入力を低コスト・高レイテンシで応答できるといった内容です。

Gemini

geminiにもcontext cacheという名前ですが、同様の機能が提供されています。

暗黙的キャッシングは、すべての Gemini 2.5 モデルでデフォルトで有効になっています。リクエストがキャッシュにヒットすると、費用の削減が自動的に反映されます

コンテキストのキャッシュ保存  |  Gemini API  |  Google AI for Developers

Geminiについては、以前は明示的なコンテキストキャッシュしか使えなかった(明示的にキャッシュするプロンプトを指定しないといけなかった)んですが、Gemini 2.5から暗黙的にキャッシュしてくれるようになったようで、他社と機能的にはほとんど横並びになった形です。

Claude

claudeにも同様にプロンプトキャッシュの機能が提供されています。

開発者がAPI呼び出しの間に頻繁に使用されるコンテキストをキャッシュすることを可能にするプロンプトキャッシングが、Anthropic APIで利用可能になりました。 Prompt caching with Claude \ Anthropic

当然Claudeからも同様の機能を提供されています。

微妙な仕様の差分

各社おおよそ似たような仕様になっているものの微妙に違う点もあるので、それらをnotebooklmにまとめてもらうとこんな感じらしいです。

特徴 Azure OpenAI Service (OpenAI モデル) Gemini API (Google AI モデル) Anthropic Claude
実装方法 既定で有効、追加設定不要。キャッシュヒットにプロンプト構造の工夫が必要。 暗黙的 (デフォルト有効、操作不要) と 明示的 (手動設定必要) の2種類。明示的はAPIでの操作が必要。 APIリクエストに cache_control パラメータを含めて明示的に有効化。プロンプト構造の工夫が必要。
コード上の手間 最小限 (プロンプト構造の工夫は必要) 暗黙的は不要、明示的は必要 必要 (APIパラメータ設定、プロンプト構造)
TTL (有効期間) 非アクティブ後 5-10分以内クリア、最終使用から1時間以内削除。 明示的は選択可、デフォルト1時間。暗黙的の明確な記述はなし。 最小5分。使用で更新。手動クリア不可。
価格 キャッシュトークンに割引適用 (標準デプロイ)、最大100%割引 (プロビジョニング済)。 暗黙的は自動費用削減。明示的は有料機能、キャッシュトークンは割引。TTLに基づく課金あり。 新価格体系。キャッシュ書き込みは高価 (+25%)キャッシュ読み取りは非常に安価 (-90%)
最小プロンプト長 1,024トークン。 2.5 Flash: 1,024、2.5 Pro: 2,048。 Claude 3.7/3.5 Sonnet, Opus: 1024。Claude 3.5/3 Haiku: 2048。

ざっくりとはディスカウントされる価格やTTL、最小プロンプト長などが異なる感じですね。

価格比較はこんな感じですかね

プロバイダー モデル 入力トークン割引 出力トークン割引 備考
OpenAI 全モデル共通 50% 割引 割引なし 出力トークンは定価のまま
Anthropic Claude 3.5 Sonnet 90% 割引 75% 割引
Claude 3 Opus 90% 割引 75% 割引
Claude 3 Haiku 88% 割引 76% 割引
Google Gemini モデルに依存(不明確) キャッシュ使用時:75% 割引 明記なし(通常価格の可能性) キャッシュミス時は通常料金。キャッシュ保存にコストが発生。

使ってみる

あとは適当に使ってみようと思います。

OpenAI

こんなコードを書いてみました。

初回はこんな感じでキャッシュは使われていません。

📊 使用トークン情報:
{
  "prompt_tokens": 1203,
  "completion_tokens": 246,
  "total_tokens": 1449,
  "prompt_tokens_details": {
    "cached_tokens": 0,
    "audio_tokens": 0
  },
  "completion_tokens_details": {
    "reasoning_tokens": 0,
    "audio_tokens": 0,
    "accepted_prediction_tokens": 0,
    "rejected_prediction_tokens": 0
  }
}

一方2回目はキャッシュがきちんと効いている事がわかりますね。

📊 使用トークン情報:
{
  "prompt_tokens": 1203,
  "completion_tokens": 158,
  "total_tokens": 1361,
  "prompt_tokens_details": {
    "cached_tokens": 1152,
    "audio_tokens": 0
  },
  "completion_tokens_details": {
    "reasoning_tokens": 0,
    "audio_tokens": 0,
    "accepted_prediction_tokens": 0,
    "rejected_prediction_tokens": 0
  }
}

Claude

claudeの方も書いてみました。

1回目。

Usage(cache_creation_input_tokens=1389, cache_read_input_tokens=0, input_tokens=16, output_tokens=385, server_tool_use=None)

入力がキャッシュされていることがわかります。

2回目。

=== Cache Info ===
Usage(cache_creation_input_tokens=0, cache_read_input_tokens=1389, input_tokens=16, output_tokens=337, server_tool_use=None)

今度は先程キャッシュされたものが使われていることがわかります。

Gemini

こちらも書いてみました。

ただ、何度やってもcacheが使われませんでした。

GenerateContentResponse(candidates=[Candidate(content=Content(parts=[Part(video_metadata=None, thought=None, inline_data=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=None, text='はい、承知いたしました。提供された文章の要約です。\n\n---\n\n**Astral社が新しいPython Type Checker「ty」を公開**\n\nPythonのType Checker(静的な型チェックツール)として、mypyやPyrightなどが既存ツールとしてありますが、今回Astral社からRust製の新しいType Checker「ty」がプレリリース版として公開されました。\n\n**「ty」の主な特徴**\n\n*   **高速性**: 圧倒的な速度が最大の特徴で、大規模コードやCIでの実行時間を大幅に短縮できます。既存ツールとの比較テストでは、mypyの約12倍、Pyrightの約110倍の速度を記録しました。\n*   **Rust製&シングルバイナリ**: Rustで開発されており、単一のバイナリで提供されるため、CIなどでのセットアップが容易です。Ruffと同じ共通基盤(パーサーなど)を利用しています。\n*   **インクリメンタル分析**: 編集中のファイルやその影響範囲のみを効率的に再チェックします。\n*   **開発者体験**: 言語サーバー機能(LSP)にも力を入れており、IDE連携による開発効率向上を目指しています。\n*   **標準仕様重視**: mypyなどとは異なる設計思想を持ち、標準仕様への準拠を重視しています。\n\n**現状と今後**\n\n現在はプレリリース段階ですが、その速度は既に高く評価されています。年内秋頃の安定版リリースを目指しており、今後の発展が期待されています。インストールはuvを利用して行えます。\n\n**まとめ**\n\n「ty」は、特に速度面で既存のType Checkerを凌駕する可能性を秘めた、Astral社が開発する注目の新しいPython Type Checkerです。')], role='model'), citation_metadata=None, finish_message=None, token_count=None, finish_reason=<FinishReason.STOP: 'STOP'>, avg_logprobs=None, grounding_metadata=None, index=0, logprobs_result=None, safety_ratings=None)], create_time=None, response_id=None, model_version='models/gemini-2.5-flash-preview-04-17', prompt_feedback=None, usage_metadata=GenerateContentResponseUsageMetadata(cache_tokens_details=None, cached_content_token_count=None, candidates_token_count=365, candidates_tokens_details=None, prompt_token_count=1052, prompt_tokens_details=[ModalityTokenCount(modality=<MediaModality.TEXT: 'TEXT'>, token_count=1052)], thoughts_token_count=444, tool_use_prompt_token_count=None, tool_use_prompt_tokens_details=None, total_token_count=1861, traffic_type=None), automatic_function_calling_history=[], parsed=None)

同じことをやっている方を見かけたので記事を置いておきますが、やっぱりどういう条件でキャッシュが効くのかはあまり良くわからない感じですね。

zenn.dev

はっきりとキャッシュを使いたかったら明示的な方を使えってことなんでしょうね。

参考文献

下記の文献を参考にさせていただきました。

感想

以上、ちょっとどうやってキャッシュを使えばよいのか調査してみた次第です。 プロンプトの順番は意識する必要がありますが、基本的には既存のコードをほぼそのまま使うだけでやすくなるので良いですね。 使う場面で使ってみようと思います。