はじめに
特に2026年6月以降、GitHub Copilotの課金が使用量に連動する方向へ変わったこともあり、トークン使用量を以前より意識するようになりました。 LLM APIやCopilotの利用料金は、多くの場合、入力トークン、出力トークン、キャッシュ済み入力トークンなどの種別ごとに計算されます。 キャッシュ済み入力トークンは通常の入力トークンより低い単価で扱われることが多いため、キャッシュヒット率を上げることはコスト削減につながります。
今回は、LLMにおけるプロンプトキャッシュの仕組みと、キャッシュヒット率を上げるための考え方をまとめます。
本記事は、2026年6月28日時点の公式ドキュメントと公開情報をもとにしています。 サービスごとの料金や仕様は変わるため、具体的な金額ではなく「どういう構造にするとキャッシュが効きやすいか」に絞って整理します。
参考にした情報は以下です。
- https://platform.openai.com/docs/guides/prompt-caching
- https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
なぜキャッシュを意識するのか
LLMの利用料金は、多くの場合 input tokens と output tokens をもとに計算されます。 コーディングエージェントでは、ユーザーの指示だけでなく、システムプロンプト、ツール定義、リポジトリ情報、会話履歴、差分、テスト結果なども入力側のトークンになります。
短いチャットであれば入力は小さいですが、エージェント的な使い方では入力がどんどん増えます。 たとえば、同じリポジトリで「調査」「実装」「テスト修正」「レビュー反映」を続けると、毎回似たような前提情報が送られます。 この重複部分を毎回フルに処理すると、コストも待ち時間も増えます。
そこで重要になるのがプロンプトキャッシュです。 OpenAIの公式ドキュメントでは、同じプロンプトを最近処理したサーバーにリクエストをルーティングすることで、入力処理のコストとレイテンシを下げる仕組みとして説明されています。 Anthropicのドキュメントでも、繰り返し使うプロンプトのprefixから再開することで処理時間とコストを削減できると説明されています。
代替案として、アプリ側でレスポンスを丸ごとキャッシュする方法もあります。 ただし、コーディングエージェントでは同じ質問に同じ回答を返せばよい場面ばかりではありません。 リポジトリの状態や直前の実行結果が変わるため、回答そのものではなく「入力の共通部分」を再利用するほうが相性がよい場面があります。
LLMのキャッシュはレスポンスキャッシュとは違う
最初に混同しやすい点として、プロンプトキャッシュは「前回と同じ回答をそのまま返す仕組み」ではありません。 一般的なWebアプリのキャッシュでは、同じURLや同じクエリに対して保存済みのレスポンスを返すことがあります。 LLMのプロンプトキャッシュは、それとは少し違います。
LLMの推論では、大きく分けて入力を読み込む処理と、出力を1トークンずつ生成する処理があります。 入力を読み込む段階では、プロンプト内の各トークンから注意機構で使う中間表現が作られます。 この中間表現を再利用できると、同じ長い前提を毎回最初から処理しなくて済みます。
つまり、キャッシュされるのは「回答」ではなく「入力prefixを処理した結果」です。 そのため、同じキャッシュにヒットしても、最後に付けるユーザー質問や現在の差分が違えば、出力は毎回新しく生成されます。 OpenAIのドキュメントでも、プロンプトキャッシュは最終的な出力トークン生成には影響せず、同じ入力であればキャッシュの有無によって回答内容が変わるものではないと説明されています。
ざっくり図にすると以下のようになります。
静的な前提情報 動的な依頼
-------------------- ----------------------
システム指示 今回の質問
ツール定義 今回の差分
コーディング規約 今回のテスト結果
共通の参考資料
↑ここまでが一致するとキャッシュが効きやすいキャッシュヒット率を上げるには、この「静的な前提情報」をできるだけ同じ順序、同じ内容で先頭に置くことが重要です。 逆に、日時、ランダムID、最新ログ、ユーザーごとの入力などを先頭に混ぜると、共通部分が崩れます。
プロンプトキャッシュでよく出てくる用語
プロンプトキャッシュを読むときは、以下の用語を押さえると理解しやすくなります。
| 用語 | 意味 | 見るポイント |
|---|---|---|
| prefix | プロンプトの先頭から続く共通部分 | ここが完全一致するとヒットしやすい |
| cache hit | 既存のキャッシュを再利用できた状態 | 入力コストや待ち時間が下がる |
| cache write | 新しいprefixをキャッシュへ書き込むこと | 初回や変更後はここが発生する |
| cached tokens | 入力トークンのうちキャッシュにヒットした部分 | 使用量ログで確認する |
| TTL | キャッシュが有効な時間 | サービスや設定によって異なる |
| breakpoint | どこまでをキャッシュ対象にするかの区切り | Anthropicでは明示指定できる |
OpenAIの場合、最近のモデルではプロンプトキャッシュが自動で有効になります。 公式ドキュメントによると、キャッシュは1024トークン以上のプロンプトで利用でき、usage.prompt_tokens_details.cached_tokens にヒットしたトークン数が表示されます。 1024トークン未満のリクエストでもフィールド自体は返りますが、cached_tokens は0になります。
たとえば、以下のような使用量が返った場合、入力2006トークンのうち1920トークンがキャッシュにヒットしています。
{
"usage": {
"prompt_tokens": 2006,
"completion_tokens": 300,
"total_tokens": 2306,
"prompt_tokens_details": {
"cached_tokens": 1920
}
}
}キャッシュヒット率を計算するなら、まずは以下のように見ます。
キャッシュヒット率 = cached_tokens / prompt_tokens上の例では 1920 / 2006 なので、約95.7%がキャッシュにヒットしています。 出力トークンは新しく生成されるため、ここでは入力側だけを見ます。
キャッシュが効きやすいプロンプト構造
キャッシュが効きやすい構造は、静的な情報を前に置き、動的な情報を後ろに置く形です。 これはOpenAIとAnthropicのドキュメントで共通している考え方です。
1. システム指示
2. 固定のルール
3. ツール定義
4. 変わりにくい参考資料
5. ユーザーごと、リクエストごとに変わる情報
6. 今回の質問コーディングエージェントの場合は、以下のように分けると考えやすいです。
| 種類 | 例 | 配置 |
|---|---|---|
| 変わりにくい情報 | コーディング規約、レビュー観点、利用できるツール定義 | 先頭 |
| たまに変わる情報 | リポジトリ概要、主要ディレクトリ構成、設計メモ | 先頭寄り |
| 毎回変わる情報 | Issue本文、今回の差分、テストログ、現在時刻 | 末尾 |
| 出力指示 | 今回やってほしい作業、回答形式 | 末尾 |
悪い例は、先頭に毎回変わる情報を入れてしまう構造です。
現在時刻: 2026-06-28 22:10:35
今回の作業ID: 7f9a1c
あなたはコードレビュー担当です。
以下のレビュー観点に従ってください。
...この形では、時刻や作業IDが変わるたびに先頭から一致しなくなります。 静的なレビュー観点が同じでも、prefixとしては別物になりやすくなります。
良い例は、固定情報を先に置き、変動情報を後ろへ寄せる構造です。
あなたはコードレビュー担当です。
以下のレビュー観点に従ってください。
- セキュリティ
- テスト不足
- 破壊的変更
- 運用時のログ確認
今回の作業情報:
- 現在時刻: 2026-06-28 22:10:35
- 作業ID: 7f9a1c同じレビュー観点を何度も使う場合、前半が一致し続けるため、キャッシュに乗りやすくなります。 実際にAPIを直接使っている場合は、cached_tokens をログに出して、構造変更の前後で比較すると効果が見えます。
Anthropicのcache_controlから学べること
OpenAIは自動キャッシュの色が強い一方で、Anthropicは cache_control を使ってキャッシュの区切りを明示できます。 この違いを見ると、どこを安定させるべきかが分かりやすくなります。
Anthropicのドキュメントでは、プロンプトは tools、system、messages の順序でprefixを作ると説明されています。 明示的なキャッシュでは、再利用したい静的コンテンツの末尾に cache_control を置きます。
イメージとしては以下です。
{
"system": [
{
"type": "text",
"text": "あなたはレビュー担当です。固定のレビュー観点に従ってください。",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [
{
"role": "user",
"content": "今回の差分をレビューしてください。"
}
]
}ここで重要なのは、キャッシュしたい区切りより前に動的な値を置かないことです。 ドキュメントでは、timestampを含むブロックをキャッシュbreakpointにしてしまうと、毎回異なるhashになり、キャッシュヒットしない例が紹介されています。 これはAPIの実装に関わらず、プロンプトキャッシュ全般で使える考え方です。
また、Anthropicではデフォルトのキャッシュ寿命が5分で、1時間のTTLも用意されています。 料金も、書き込みと読み込みで単価が違います。 2026年6月時点のドキュメントでは、5分のキャッシュ書き込みは通常入力の1.25倍、キャッシュ読み込みは通常入力の0.1倍という考え方が示されています。
このように、プロバイダーによって操作方法は異なります。 しかし、設計の要点は同じです。 「再利用したいものを前に置く」「毎回変わるものを後ろに置く」「区切りより前を不用意に変えない」の3点です。
コーディングエージェントで意識したいこと
GitHub CopilotやCodex、Claude Codeのようなツールでは、ユーザーが内部プロンプトをすべて制御できるわけではありません。 そのため、APIを直接使うときのように cached_tokens を必ず確認できるとは限りません。 それでも、ユーザー側の使い方でキャッシュ効率に影響しそうな部分はあります。
まず、巨大な依頼を毎回少しずつ言い換えないことです。 同じ目的であれば、固定の作業ルールはファイルやリポジトリのガイドに寄せ、毎回のチャットでは今回変わった点だけを伝えるほうが安定します。 たとえば、レビュー観点やテスト方針を毎回チャットに貼るより、AGENTS.md やプロジェクトの開発ドキュメントとして固定しておくほうが、先頭側の共通情報になりやすくなります。
次に、作業単位を無理に大きくしすぎないことです。 コンテキストを詰め込みすぎると、入力トークンが増えるだけでなく、動的なログや差分も増えます。 大量のテストログやビルドログを毎回全文貼るより、失敗箇所の要約と必要な抜粋に絞るほうが扱いやすいです。
さらに、時刻や一時IDの扱いにも注意が必要です。 「毎回の依頼文の冒頭に現在時刻を書く」「ランダムなセッションIDを固定指示より前に置く」といった習慣は、prefix一致の観点では不利です。 必要な場合でも、固定指示の後ろに置くほうが無難です。
実際に筆者がAIコーディング支援を使っていて効果を感じるのは、以下のような分け方です。
| やりたいこと | キャッシュを意識した置き場所 |
|---|---|
| コーディング規約を守らせる | リポジトリ内の固定ドキュメントに置く |
| 今回だけの制約を伝える | チャットの末尾で伝える |
| 長いログを読ませる | 必要な範囲だけを抜粋する |
| 同じレビュー観点を使う | 毎回同じ文面・同じ順序にする |
| 設計資料を参照させる | 変わりにくいファイルとして管理する |
キャッシュだけを狙いすぎると、今度は文脈不足になります。 重要なのは、必要な情報を削ることではありません。 変わらない情報と変わる情報を分け、変わらない情報を安定して渡すことです。
キャッシュヒット率を上げるチェックリスト
APIを直接使う場合でも、コーディングエージェントを使う場合でも、以下を確認するとキャッシュが効きやすくなります。
- 固定のシステム指示を先頭に置く
- ツール定義やJSON Schemaの順序を不用意に変えない
- 例示や参考資料は毎回同じ文面にする
- ユーザー入力、日時、ID、ログ、差分は後ろに置く
- 長い会話では、毎回必要な履歴だけを残す
- 使用量ログで
cached_tokensを確認する - キャッシュのTTLを意識して、同じ種類の処理をまとめて流す
- キャッシュされて困る機密情報を前提情報として長く残さない
特にAPIでは、cached_tokens をアプリケーションログに出しておくと便利です。 プロンプトを少し整理しただけでヒット率が変わることがあります。 ヒット率が低い場合は、プロンプトの先頭に毎回変わる値が混ざっていないかを確認します。
確認するログの例:
- prompt_tokens
- cached_tokens
- completion_tokens
- モデル名
- プロンプトテンプレートのバージョンプロンプトテンプレートのバージョンを一緒に記録しておくと、テンプレート変更後にキャッシュヒット率が落ちたかどうかを追いやすくなります。 これは性能劣化の調査にも使えます。
注意点
プロンプトキャッシュは便利ですが、万能ではありません。 まず、完全一致のprefixが重要です。 同じ意味の文章でも、順序や表記が違えば別の入力として扱われます。 「少しだけ言い換えた同じ指示」は、人間には同じでもキャッシュには同じとは限りません。
次に、キャッシュには寿命があります。 OpenAIのドキュメントでは、使われなくなったキャッシュは通常5〜10分程度で削除され、混雑していない時間帯でも最大1時間程度と説明されています。 Anthropicでも、基本のTTLは5分です。 そのため、一度キャッシュされたからずっと安くなるわけではありません。
また、プロバイダーごとにデータ保持の考え方が異なります。 OpenAIのドキュメントでは、プロンプトキャッシュは組織間では共有されず、Extended Prompt Cachingでは保持期間の上限が24時間と説明されています。 AnthropicもZero Data Retentionとの関係を説明しています。 機密情報を扱う場合は、キャッシュの有無だけでなく、契約、データ保持設定、ログ出力、社内ルールを確認する必要があります。
注意:キャッシュヒット率を上げるために、機密情報を固定プロンプトへ寄せるのは避けるべきです。再利用したい情報と長く残してよい情報は別物として扱う必要があります。
最後に、キャッシュは出力トークンを減らすものではありません。 回答が長ければ出力側のコストは発生します。 そのため、コストを下げたい場合は、入力のキャッシュだけでなく、回答形式を指定して不要に長い出力を避けることも重要です。
まとめ
LLMのプロンプトキャッシュは、同じ回答を返すレスポンスキャッシュではなく、入力prefixの処理結果を再利用する仕組みです。 キャッシュヒット率を上げるには、固定の指示やツール定義を先頭に置き、ユーザー入力やログのような動的な情報を後ろに置くことが基本になります。
実際にAI開発ツールを使っていると、トークン削減というより「プロンプトの構造化」が大事だと感じます。 変わらないものと変わるものを分けておくと、キャッシュにも効きますし、エージェントへの指示も読みやすくなります。
今後は、GitHub CopilotやCodexのようなマネージドなコーディングエージェントでも、利用者がコストを把握しやすいメトリクスが増えていくはずです。 まずはAPIで確認できる cached_tokens の考え方を押さえ、自分のプロンプトや作業依頼のどこが再利用されるべきかを整理しておくのがよさそうです。


コメント