Claude プロンプトキャッシング完全ガイド — 5分 vs 1時間TTL選択戦略とコスト最適化の実践
プロンプトキャッシングとは何か — 仕組みと料金体系
キャッシュの基本メカニズム(プレフィックスマッチング)
Claude のプロンプトキャッシングは、リクエスト間で共通するプロンプトの先頭部分をサーバー側にキャッシュし、再利用することで入力コストを大幅に削減する仕組みだ。
重要なのは「プレフィックスマッチング」という点にある。キャッシュはプロンプトの先頭から最長一致で判定される。つまり、system プロンプト → tools → messages の順に評価され、途中で1トークンでも変わればそれ以降はキャッシュミスになる。
キャッシュ可能な最小単位はモデルによって異なる。
- Opus 4.7 / 4.6 / 4.5: 4096トークン以上
- Sonnet 4.6: 2048トークン以上
- Sonnet 4.5 / Opus 4.1 / Opus 4 / Sonnet 4: 1024トークン以上
- Haiku 4.5: 4096トークン以上
- Haiku 3.5: 2048トークン以上
- Haiku 3: 4096トークン以上
この閾値未満のプロンプトはキャッシュの対象にならない。
料金構造:書き込み・読み取り・通常の3段階
キャッシュの料金は3段階に分かれる。
| 種別 | 5分TTL | 1時間TTL |
|---|---|---|
| 通常入力(キャッシュなし) | 1.0倍 | 1.0倍 |
| キャッシュ書き込み | 1.25倍 | 2.0倍 |
| キャッシュ読み取り | 0.1倍 | 0.1倍 |
読み取り時の90%削減は両TTLで共通だ。違いは書き込みコストにある。5分TTLなら25%増、1時間TTLなら100%増(2倍)となる。
# Messages APIでのcache_control設定例(デフォルト5分TTL)
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system=[
{
"type": "text",
"text": "あなたは技術文書のレビュアーです。...(長いシステムプロンプト)...",
"cache_control": {"type": "ephemeral"} # 5分TTL(デフォルト)
}
],
messages=[{"role": "user", "content": "このコードをレビューしてください"}]
)
# 1時間TTLを指定する場合
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system=[
{
"type": "text",
"text": "あなたは技術文書のレビュアーです。...(長いシステムプロンプト)...",
"cache_control": {"type": "ephemeral", "ttl": "1h"} # 1時間TTL
}
],
messages=[{"role": "user", "content": "このコードをレビューしてください"}]
)
cache_control: {"type": "ephemeral"} を付与した位置までがキャッシュ対象となる。現在サポートされている type は ephemeral のみだ。TTLはデフォルトで5分間だが、"ttl": "1h" を追加することで1時間に延長できる。
5分 vs 1時間TTL — ブレークイーブン計算で選ぶ
TTLごとの書き込み・読み取りコスト比較表
TTL選択の判断には、書き込みコスト増分を読み取りコスト削減で何回のリクエストで回収できるかが鍵になる。
Claude Sonnet(入力 $3/MTok)で10万トークンのシステムプロンプトを例に計算してみよう。
5分TTL の場合:
通常コスト(キャッシュなし): $0.30 / リクエスト
書き込みコスト: $0.30 × 1.25 = $0.375(初回のみ)
読み取りコスト: $0.30 × 0.1 = $0.03(2回目以降)
→ 2回目で累計 $0.405(通常2回 $0.60)→ 黒字化
1時間TTL の場合:
書き込みコスト: $0.30 × 2.0 = $0.60(初回のみ)
読み取りコスト: $0.30 × 0.1 = $0.03(2回目以降)
→ 3回目で累計 $0.66(通常3回 $0.90)→ 黒字化
ブレークイーブンの判断フローチャート
選択基準はシンプルだ。
- 同一プロンプトを5分以内に再利用するか? → Yes なら 5分TTL で十分
- 5分を超えるが1時間以内に再利用するか? → Yes なら 1時間TTL が有利
- 1時間以上間隔が空くか? → キャッシュ効果は限定的。プロンプト構造の見直しを優先
月間の試算例として、1日100回・10万トークンのシステムプロンプトを使うケースを考える。
| 条件 | 月間コスト(キャッシュなし) | 5分TTL | 1時間TTL |
|---|---|---|---|
| 5分以内に連続利用 | $900 | 約$105 | — |
| 30分間隔で利用 | $900 | $900(TTL切れ) | 約$120 |
正直、この差を初めて計算したときは驚いた。適切なTTLを選ぶだけで月間コストが1/7以下になるケースもある。
Claude Code CLIでのキャッシュ設定
環境変数の設定方法と挙動
2026年2月初旬、Claude Code のプロンプトキャッシュはデフォルトで1時間TTLに変更された。しかし約1ヶ月後の3月上旬にサイレントに5分TTLへ戻され、多くのユーザーが突然のコスト増に直面した。現在は以下の環境変数で明示的に制御できる。
# 1時間TTLを有効化(長時間セッション向き)
export ENABLE_PROMPT_CACHING_1H=true
claude
# 5分TTLを明示指定(短いタスク向き)
export FORCE_PROMPT_CACHING_5M=true
claude
CLAUDE.md やシステムプロンプトが大きいプロジェクト(数千トークン以上)ほどキャッシュの恩恵は大きい。逆に、小さなプロジェクトでは最小キャッシュ単位に満たず効果がないこともある(最小トークン数はモデルにより1024〜4096)。
実際のコスト削減効果の確認方法
キャッシュの動作状況は --verbose フラグで確認できる。
claude --verbose -p "このプロジェクトの構造を説明して"
レスポンスに含まれる以下のフィールドに注目する。
cache_creation_input_tokens: キャッシュに書き込まれたトークン数cache_read_input_tokens: キャッシュから読み取られたトークン数
cache_read_input_tokens が大きいほどコスト削減が効いている。初回は cache_creation_input_tokens のみが表示され、2回目以降で cache_read_input_tokens が出現すれば正常にキャッシュが機能している。
API直接利用でのキャッシュ制御
cache_controlパラメータの正しい配置
API直接利用では、キャッシュブレークポイントの配置が効果を左右する。最大4つまで設定可能で、配置順序が重要だ。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// 5分TTL(デフォルト)の例
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
system: [
{
type: "text",
text: "あなたはコードレビューの専門家です。...(長い指示)...",
cache_control: { type: "ephemeral" }, // ブレークポイント1: system(5分TTL)
},
],
tools: [
{
name: "analyze_code",
description: "コードを静的解析する",
input_schema: {
type: "object" as const,
properties: { code: { type: "string" } },
required: ["code"],
},
cache_control: { type: "ephemeral" }, // ブレークポイント2: tools(5分TTL)
},
],
messages: [
{
role: "user",
content: [
{
type: "text",
text: "以下のファイルをレビューしてください...(長いコード)...",
cache_control: { type: "ephemeral" }, // ブレークポイント3: messages(5分TTL)
},
],
},
],
});
// 1時間TTLを使う場合は ttl パラメータを追加
// cache_control: { type: "ephemeral", ttl: "1h" }
マルチターン会話でのキャッシュ戦略
マルチターン会話では、過去のメッセージは変わらないため自然にプレフィックスが一致する。効果的な戦略は以下の通りだ。
- system プロンプト末尾にブレークポイントを置く(最も効果的)
- tools リスト末尾にブレークポイントを置く(ツール定義が大きい場合)
- 直近の長いユーザーメッセージ末尾にブレークポイントを置く
レスポンスヘッダから効果を計測できる。
console.log("書き込み:", response.usage.cache_creation_input_tokens);
console.log("読み取り:", response.usage.cache_read_input_tokens);
console.log("通常入力:", response.usage.input_tokens);
// キャッシュヒット率の計算
const total =
(response.usage.cache_read_input_tokens ?? 0) +
(response.usage.cache_creation_input_tokens ?? 0) +
response.usage.input_tokens;
const hitRate = ((response.usage.cache_read_input_tokens ?? 0) / total) * 100;
console.log(`キャッシュヒット率: ${hitRate.toFixed(1)}%`);
Bedrock・Vertex AI でのキャッシュ挙動の違い
プラットフォームによってキャッシュの挙動と設定方法が異なる。これは個人的に最もハマりやすいポイントだと思う。
| 項目 | Anthropic API直接 | Amazon Bedrock | Google Vertex AI | Claude Code CLI |
|---|---|---|---|---|
| TTL選択 | 5分/1時間(明示指定) | 自動適用 | 対応(設定方法が異なる) | 環境変数で統一制御 |
| cache_control指定 | 必須(手動) | 必要 | 必要 | 内部で自動処理 |
| 最小トークン数 | モデル世代により1024〜4096 | プラットフォーム依存 | モデル世代により異なる | プロバイダに準拠 |
| 料金体系 | 上記の通り | Bedrock独自の料金 | Vertex AI料金に準拠 | 接続先プロバイダに準拠 |
移行時の注意点:
- Anthropic API → Bedrock:
cache_controlの指定は引き続き必要。TTL制御の環境変数は非対応 - Anthropic API → Vertex AI: cache_control の指定方法がAPI直接とは異なるため、SDKドキュメントを確認すること
- Claude Code CLI経由の場合: 環境変数(
ENABLE_PROMPT_CACHING_1H/FORCE_PROMPT_CACHING_5M)がプラットフォームを問わず使える
なお、cache_control の明示的な指定が不要な自動キャッシュは、Anthropic API直接利用時のみ対応している。
よくあるハマりポイントと対処法
キャッシュが効かない3大原因
1. 最小トークン数未満
モデルごとの最小トークン数(Opus 4.7/4.6/4.5・Haiku 4.5・Haiku 3は4096、Sonnet 4.6・Haiku 3.5は2048、Sonnet 4.5/Opus 4.1/Opus 4/Sonnet 4は1024)に満たない短いプロンプトはキャッシュ対象外だ。system プロンプトが短い場合は、tools 定義と合わせて閾値を超えるよう構成する。
2. プロンプト先頭の動的要素
タイムスタンプや日付、ランダムIDをプロンプトの先頭付近に埋め込むと、毎回プレフィックスが変わりキャッシュミスになる。動的要素はプロンプトの末尾側に配置すること。
# NG: 先頭に日時があるとキャッシュが効かない
system_prompt = f"現在時刻: {datetime.now()}\nあなたはコードレビューの専門家です..."
# OK: 静的な部分を先頭に、動的な部分を後ろに
system_prompt = "あなたはコードレビューの専門家です...\n" + f"現在時刻: {datetime.now()}"
3. TTL切れの見落とし
5分TTLの場合、少し作業を中断しただけでキャッシュが消える。再開時の初回リクエストで書き込みコストが再発生することを忘れがちだ。
デバッグの手順
キャッシュが期待通りに動いているか確認する簡易モニタリングの例を示す。
import anthropic
client = anthropic.Anthropic()
def monitored_request(system_text: str, user_text: str):
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system=[{
"type": "text",
"text": system_text,
"cache_control": {"type": "ephemeral"}
}],
messages=[{"role": "user", "content": user_text}]
)
usage = response.usage
created = getattr(usage, "cache_creation_input_tokens", 0) or 0
read = getattr(usage, "cache_read_input_tokens", 0) or 0
normal = usage.input_tokens
print(f"通常: {normal} | 書込: {created} | 読取: {read}")
if created > 0 and read == 0:
print("→ キャッシュ新規作成(初回 or TTL切れ後)")
elif read > 0:
print(f"→ キャッシュヒット(削減率: {read / (read + normal) * 100:.0f}%)")
else:
print("→ キャッシュ未使用(最小トークン数未満の可能性)")
return response
また、画像などのマルチモーダル入力もキャッシュ対象になる。ただしトークン換算量が大きいため、キャッシュの書き込みコストも比例して増える点に注意が必要だ。ストリーミング利用時もキャッシュは正常に動作する。
まとめ
プロンプトキャッシングは「設定するだけでコストが下がる魔法」ではない。TTL・利用頻度・プロンプト構造の3要素で効果が決まる。
- 5分TTL: 短いインタラクティブセッション、頻繁にリクエストを送るチャット型アプリに最適
- 1時間TTL: 長時間稼働するエージェント、バッチ処理、大規模なコードベースでの Claude Code 利用に最適
まずは自分のユースケースでキャッシュヒット率を計測し、ブレークイーブンを超えているか確認することから始めよう。プラットフォームごとの挙動差もあるため、本番環境では必ず cache_creation_input_tokens と cache_read_input_tokens をモニタリングすることを推奨する。
