はじめに
AIアプリを本番運用していると、こんな状況に気づきます。
「毎回同じシステムプロンプトを送っているのに、毎回フルの入力コストがかかっている」
プロンプトキャッシュを正しく使うだけで、入力トークンのコストを最大90%削減できます。本記事では、ClaudeとGPT-4oそれぞれのキャッシュの仕組みと、実装上の注意点を解説します。
プロンプトキャッシュとは
LLMへのリクエストは、毎回すべてのトークンを処理します。しかし同じ内容を繰り返し送る場合、プロバイダー側でキャッシュしておくことで処理コストを下げる仕組みがプロンプトキャッシュです。
特に以下のような場面で効果が大きいです:
- 長いシステムプロンプト(製品仕様・ルール・ペルソナ定義)
- 大量のドキュメントをコンテキストに含めるRAGシステム
- 繰り返し参照するコードベース・ナレッジベース
- 複数ターンの会話で固定されたコンテキスト
Claudeのプロンプトキャッシュ
料金
| トークン種別 | 通常価格(Sonnet 4.5) | キャッシュ書き込み | キャッシュ読み取り |
|---|---|---|---|
| 入力 | $3.00/1M | $3.75/1M(+25%) | $0.30/1M(−90%) |
キャッシュ書き込み時は通常より25%高くなりますが、2回目以降のキャッシュ読み取りは90%オフになります。同じコンテキストを2回以上使えばすぐに元が取れます。
仕組み
Claudeのキャッシュはプレフィックス単位で動作します。メッセージの先頭から一致している部分がキャッシュとして使われます。
つまり、固定コンテンツを先頭に、変動コンテンツを末尾に配置することがキャッシュ効率を上げる基本原則です。
実装方法
import anthropic
client = anthropic.Anthropic(api_key="sk-...")
# 長いシステムプロンプトをキャッシュする
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": "あなたはプロのPythonエンジニアです。",
},
{
"type": "text",
"text": open("large_codebase_context.txt").read(), # 大きなコンテキスト
"cache_control": {"type": "ephemeral"} # ここをキャッシュ
}
],
messages=[
{"role": "user", "content": "このコードのバグを見つけてください"}
]
)
# レスポンスでキャッシュヒット状況を確認
usage = response.usage
print(f"入力トークン: {usage.input_tokens}")
print(f"キャッシュ書き込み: {usage.cache_creation_input_tokens}")
print(f"キャッシュ読み取り: {usage.cache_read_input_tokens}")
RAGでのキャッシュ活用
# 固定ナレッジベースをキャッシュに乗せる
KNOWLEDGE_BASE = open("product_manual.txt").read() # 10万トークン相当
def ask_with_cache(question: str):
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": "製品マニュアルに基づいて回答してください。\n\n" + KNOWLEDGE_BASE,
"cache_control": {"type": "ephemeral"}
# ↑ 2回目以降は90%オフで読み取られる
}
],
messages=[{"role": "user", "content": question}]
)
return response.content[0].text
# 1回目:キャッシュ書き込み(通常+25%)
answer1 = ask_with_cache("返品ポリシーを教えてください")
# 2回目以降:キャッシュ読み取り(通常-90%)
answer2 = ask_with_cache("保証期間はどのくらいですか")
キャッシュが効く条件
- 最低1,024トークン以上のコンテンツが対象(短すぎるとキャッシュされない)
- キャッシュの有効期限は5分間(リクエストがあるたびにリセット)
- プレフィックスが完全一致している必要がある
GPT-4oのプロンプトキャッシュ
料金
| トークン種別 | 通常価格(GPT-4o) | キャッシュ読み取り |
|---|---|---|
| 入力 | $2.50/1M | $1.25/1M(−50%) |
Claudeと異なり、GPT-4oのキャッシュは自動的に適用されます。cache_control のような明示的な指定は不要です。
仕組み
OpenAIのキャッシュもプレフィックスマッチングで動作します。
- 最低1,024トークンから適用
- 128トークン単位でキャッシュされる
- 有効期限は5〜10分(自動管理)
実装方法
from openai import OpenAI
client = OpenAI(api_key="sk-...")
# 特別な設定不要 — 自動的にキャッシュが適用される
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
# ここに長い固定コンテンツを置くとキャッシュされやすい
"content": LONG_SYSTEM_PROMPT + FIXED_CONTEXT
},
{
"role": "user",
"content": user_question # ここだけが毎回変わる
}
]
)
# キャッシュヒット状況の確認
usage = response.usage
print(f"入力トークン: {usage.prompt_tokens}")
print(f"キャッシュヒット: {usage.prompt_tokens_details.cached_tokens}")
ClaudeとGPTのキャッシュ比較
| 項目 | Claude | GPT-4o |
|---|---|---|
| 設定方法 |
cache_control を明示 |
自動適用 |
| 削減率 | 最大90%オフ | 50%オフ |
| 最低トークン数 | 1,024 | 1,024 |
| 有効期限 | 5分 | 5〜10分 |
| 書き込みコスト | +25% | なし |
コスト削減率はClaudeの方が大きいですが、設定が必要です。GPT-4oは設定不要で自動的に適用されます。
キャッシュ効率を最大化するメッセージ構造
【キャッシュされやすい:先頭に固定】
┌─────────────────────────────┐
│ システムプロンプト │ ← 変わらない
│ 製品仕様・ルール・ペルソナ │ ← 変わらない
│ ナレッジベース・ドキュメント │ ← 変わらない(cache_control)
├─────────────────────────────┤
│ 会話履歴(古い部分) │ ← あまり変わらない
├─────────────────────────────┤
│ 最新のユーザーメッセージ │ ← 毎回変わる
└─────────────────────────────┘
【キャッシュされにくい:末尾に変動コンテンツ】
やりがちなNG:
# NG: 変動コンテンツを先頭に置く
messages = [
{
"role": "user",
# ← タイムスタンプや変動データが先頭にある
"content": f"現在時刻: {datetime.now()}\n\n{FIXED_INSTRUCTIONS}\n\n{question}"
}
]
# → キャッシュが効かない
# OK: 固定コンテンツを先頭に置く
messages = [
{
"role": "system",
"content": FIXED_INSTRUCTIONS # ← 固定コンテンツを先頭に
},
{
"role": "user",
"content": f"{question}\n\n現在時刻: {datetime.now()}" # ← 変動部分は末尾
}
]
コスト削減の試算
月間10万リクエスト、システムプロンプト5,000トークン・ユーザー入力500トークンのアプリの場合:
| 構成 | 月額入力コスト(Claude Sonnet) |
|---|---|
| キャッシュなし | $1,650 |
| キャッシュあり(キャッシュヒット率80%) | 約$390 |
キャッシュヒット率80%で約76%のコスト削減になります。
マルチプロバイダー環境でのキャッシュ管理
ClaudeとGPTを両方使うアプリでは、それぞれのキャッシュ仕様の違いを意識する必要があります。
OpenAI互換のAPIゲートウェイを使うと、同一のエンドポイントでClaudeとGPTを切り替えられるため、キャッシュ状況もまとめて管理できます。
from openai import OpenAI
# OpenAI互換ゲートウェイ経由
client = OpenAI(
api_key="sk-あなたのキー",
base_url="https://router.flatkey.ai/v1"
)
# モデルを変えるだけでClaude/GPTを切り替え
# キャッシュはそれぞれのプロバイダーの仕様で自動適用
for model in ["anthropic/claude-sonnet-4-5", "openai/gpt-4o"]:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": FIXED_SYSTEM_PROMPT},
{"role": "user", "content": question}
]
)
print(f"{model}: {response.choices[0].message.content}")
まとめ
プロンプトキャッシュで重要なポイント:
- 固定コンテンツを先頭に、変動コンテンツを末尾に配置する
-
Claudeは
cache_controlを明示して最大90%オフを狙う - GPT-4oは自動適用なので意識するのはメッセージ構造だけ
- 最低1,024トークン以上のコンテンツでないとキャッシュされない
- キャッシュの有効期限(5分)内にリクエストが来るようなワークロードに最も効果的
RAGや繰り返し同じコンテキストを使うアプリでは、キャッシュの有無でコストが数倍変わることがあります。まず自分のアプリのリクエストパターンを分析して、キャッシュ効率を確認してみてください。