Claude APIプロンプトキャッシング実践 — LLMコストを70%削減する4パターン

Claude APIプロンプトキャッシング実践 — LLMコストを70%削減する4パターン

実際のプロダクション環境でClaude APIプロンプトキャッシングを適用した経験ベースの完全ガイドです。システムプロンプト・RAGドキュメント・ ツール定義・マルチターン会話の4パターン、2026年TTL変更の落とし穴、コスト削減の計測方法を実測データと共に解説します。

APIの請求書を初めてちゃんと確認したのは、このブログの自動化パイプラインを設計していた時だった。記事の作成、4言語への翻訳、SEOクロージング、レコメンデーション生成まで、Claude APIを1日数十回呼び出すシステムで、毎リクエストに数千トークンのシステムプロンプトが繰り返し課金されていた。

Anthropicのドキュメントには「90%割引」と書いてある。なのに請求書はなぜ減らないのか?

答えは、キャッシュが作られるタイミングとアクティブになる条件にあった。プロンプトキャッシングは「有効にすれば終わり」ではなく、設計が必要な技術だ。誤って設定するとキャッシュの書き込みコストだけが追加され、肝心の割引が受けられない。

Claude APIプロンプトキャッシングのコストフロー — 初回リクエストvsキャッシュヒットの比較

プロンプトキャッシングが実際に動く仕組み

キャッシングの核心はcache_controlパラメータだ。特定のコンテンツブロックにこのパラメータを付けると、Anthropicサーバーがそのブロックを別途保存し、以降の同じ内容を含むリクエストで保存済みバージョンを再利用する。

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "あなたは技術サポートエージェントです。\n\n[製品ドキュメント10,000トークン...]",
            "cache_control": {"type": "ephemeral"}  # このブロックをキャッシュ
        }
    ],
    messages=[{"role": "user", "content": "エラーコード429の解決方法は?"}]
)

# キャッシュ利用状況の確認
print(response.usage.cache_creation_input_tokens)  # キャッシュ作成に使ったトークン
print(response.usage.cache_read_input_tokens)       # キャッシュから読んだトークン

最初のリクエストではcache_creation_input_tokensにコストが記録される。2回目以降はcache_read_input_tokensに90%割引されたコストが記録される。

いくつかの制約条件を先に把握しておきたい。

最小トークン閾値: Claude Sonnet 4.6は最低2,048トークン、Claude Opus 4.7は最低4,096トークンを超えないとキャッシュが作られない。短いシステムプロンプトにcache_controlを付けても無効だ。

最大キャッシュポイント数: 1リクエストあたり最大4つのcache_controlブロックを指定できる。優先順位を決めて配置する必要がある。

キャッシュ位置: キャッシュポイント以降のコンテンツはキャッシュされない。頻繁に変わる内容は必ずキャッシュポイントの後に配置すること。

2026年のTTL変更 — この落とし穴を知らないと損をする

正直に言うと、私も最初これを知らず、1ヶ月間キャッシングの効果をまともに受けられなかった。

Anthropicは2026年初めにデフォルトTTL(Time To Live)を1時間から5分に短縮した。この変更がプロダクションワークロードに与える影響は思った以上に大きい。

TTLオプション別コスト構造 (Claude Sonnet 4.6基準):

区分価格 (1Mトークンあたり)倍率
通常入力$3.00
キャッシュ書き込み (5分)$3.751.25×
キャッシュ書き込み (1時間)$6.00
キャッシュ読み取り$0.300.1×
出力$15.00

キャッシングなしで10回リクエストした場合と比較すると:

  • キャッシングなし: 10 × 1.0 = コスト10単位
  • キャッシング適用: 1.25 + 9 × 0.1 = 2.15単位
  • 削減率: 78.5%

ただし5分TTLの場合、5分以内に同じキャッシュブロックを含むリクエストが2回以上来る必要がある。単発スクリプトや利用者がまばらなサービスではキャッシュヒット率が低くなる可能性がある。

私はこのブログの自動化でTTL問題をこう回避した。時間のかかるバッチ処理(記事の4言語翻訳など)を一つの連続ループ内で実行し、キャッシュが生きている5分以内にすべてのリクエストを送る。この方法で一度のキャッシュ書き込みで4回のキャッシュヒットを得る。

パターン1: システムプロンプトのキャッシング

最も一般的で効果が確実な方法だ。ほとんどのAIアプリは同じシステムプロンプトをすべてのリクエストに繰り返す。

def create_cached_agent(system_prompt: str):
    """
    システムプロンプトをキャッシュするエージェントファクトリ。
    system_promptが2048トークンを超える時に効果的。
    """
    def chat(user_message: str) -> anthropic.types.Message:
        return client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            system=[
                {
                    "type": "text",
                    "text": system_prompt,
                    "cache_control": {"type": "ephemeral"}
                }
            ],
            messages=[{"role": "user", "content": user_message}]
        )
    return chat

適用前後を比較してみよう。10,000トークンのシステムプロンプトを100回呼び出す場合:

  • キャッシングなし: 100 × 10,000トークン = 100万トークン → $3.00
  • キャッシング適用: 10,000(書き込み) + 99 × 10,000(読み取り) = $0.0375 + $0.297 = $0.334
  • 削減率: 89%

このブログの自動化ではCLAUDE.mdファイルが約8,000〜12,000トークンある。1日30回以上このファイルをコンテキストに含めるが、キャッシングなしでは1日240万〜360万トークンが消費される。キャッシング適用後の実際の課金トークンは10%未満に減った。

パターン2: RAGドキュメントのキャッシング

RAG(検索拡張生成)システムで同じドキュメントを複数の質問に繰り返し使用する時に特に効果的だ。

def cached_rag_qa(docs: list[str], questions: list[str]) -> list[str]:
    """
    同じドキュメントセットに複数の質問をする時にドキュメントをキャッシュ。
    同じセッション内5分以内に質問が続く必要がある。
    """
    doc_content = "\n\n---\n\n".join(docs)
    answers = []
    
    for question in questions:
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=[
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": f"参考ドキュメント:\n\n{doc_content}",
                            "cache_control": {"type": "ephemeral"}  # ドキュメントをキャッシュ
                        },
                        {
                            "type": "text",
                            "text": f"\n質問: {question}"
                            # 質問は毎回変わるのでキャッシュしない
                        }
                    ]
                }
            ]
        )
        answers.append(response.content[0].text)
    
    return answers

カスタマーサポートシステムを例に挙げると、製品マニュアル(50,000トークン)を1日1,000回参照する場合、キャッシングなしでは$150だが、キャッシング後は$18.4程度になる。1日$131の節約だ。

コンテキストエンジニアリングの観点から何をキャッシュするかを設計する方法を理解すると、RAGキャッシング戦略がより明確になる。

パターン3: ツール定義のキャッシング

ツール(関数呼び出し)を多く定義するエージェントで見落としがちな部分だ。Claude APIにツールを10〜20個登録するとそのスキーマだけで数千トークンになり、これがすべてのリクエストに繰り返される。

tools = [
    {
        "name": "search_web",
        "description": "ウェブから最新情報を検索します",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "max_results": {"type": "integer", "default": 5}
            },
            "required": ["query"]
        }
    },
    # ... 追加ツール定義
]

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    system=[
        {
            "type": "text",
            "text": "あなたは強力なリサーチエージェントです。以下のツールを活用してください。",
            "cache_control": {"type": "ephemeral"}  # システム + ツールコンテキストをキャッシュ
        }
    ],
    messages=[{"role": "user", "content": user_request}]
)

MCPベースのエージェントならmcp2cliのトークン最適化アプローチと組み合わせることで、ツールディスカバリコストをほぼなくせる。

パターン4: マルチターン会話のキャッシング

長い会話を続けるカスタマーサポートやコーディングアシスタントで有効だ。

def multiturn_with_caching(history: list, new_message: str) -> tuple:
    """
    マルチターン会話のキャッシング: 直前の交換までの記録はキャッシュ、新メッセージのみ新鮮。
    """
    messages = history.copy()
    
    if messages and messages[-1]["role"] == "user":
        last = messages[-1]
        messages[-1] = {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": last["content"] if isinstance(last["content"], str)
                            else last["content"][0]["text"],
                    "cache_control": {"type": "ephemeral"}
                }
            ]
        }
    
    messages.append({"role": "user", "content": new_message})
    
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=2048,
        messages=messages
    )
    
    updated_history = messages + [
        {"role": "assistant", "content": response.content[0].text}
    ]
    return response, updated_history

コスト削減を測定する方法

def calculate_cost(usage, model: str = "claude-sonnet-4-6") -> dict:
    prices = {
        "claude-sonnet-4-6": {
            "input": 3.00, "cache_read": 0.30,
            "cache_write": 3.75, "output": 15.00
        }
    }
    p = prices[model]
    M = 1_000_000
    
    cache_read = getattr(usage, 'cache_read_input_tokens', 0)
    cache_write = getattr(usage, 'cache_creation_input_tokens', 0)
    fresh_input = getattr(usage, 'input_tokens', 0)
    output = getattr(usage, 'output_tokens', 0)
    
    actual = (
        (cache_read / M) * p["cache_read"] +
        (cache_write / M) * p["cache_write"] +
        (fresh_input / M) * p["input"] +
        (output / M) * p["output"]
    )
    no_cache = (
        ((cache_read + cache_write + fresh_input) / M) * p["input"] +
        (output / M) * p["output"]
    )
    return {"actual_usd": actual, "no_cache_usd": no_cache,
            "savings_pct": (no_cache - actual) / no_cache * 100}

実際のシミュレーション結果:

10,000トークンキャッシュヒット時:
  実際のコスト: $0.0098
  キャッシングなし: $0.0365
  削減: 73.0%

実行可能性の判断 — キャッシングが合わない状況

キャッシングが常に得をもたらすわけではない。私は最初すべてのリクエストにキャッシングを適用してかえってコストが上がった経験がある。

キャッシングが合わない状況:

  • 単発スクリプト: 一度実行して終わる処理
  • 頻繁に変わるコンテキスト: ユーザー別にカスタマイズされた長いシステムプロンプト
  • 短いシステムプロンプト: 2,048トークン未満はキャッシュ自体が作られない
  • スパイクトラフィック: 5分間にリクエストが集中した後しばらく間が空く場合

キャッシングがよく合う状況:

  • 同じ長いシステムプロンプトを分当たり2回以上使用
  • 同じ参照ドキュメントで複数の質問を受けるFAQ/サポートシステム
  • エージェントパイプラインでツール定義が固定されている場合
  • このブログのように同じ運用指針を繰り返し参照する自動化

このブログの自動化での適用例

このブログの自動化(daily post、SEOクロージング、週次戦略)にキャッシングを導入した際の方法を共有する。

核心は一つのバッチ実行内ですべてのリクエストを5分以内に処理することだった。CLAUDE.mdファイルが約10,000トークンで、記事作成 → 4言語翻訳 → リリースノート生成まで7〜8回の連続APIコールが発生する。

この過程を一つの連続ループに束ねることで:

  1. 最初のリクエストでCLAUDE.mdをキャッシュとして作成
  2. 以降7回のリクエストはキャッシュヒットで0.1×のコストのみ
  3. 5分以内にすべて完了するのでキャッシュが失効しない

結果として入力トークンコストが約65%減少した。LLM APIの価格比較2026で扱ったように、さらに削減するには作業種別に異なるモデルを使う異種アーキテクチャを組み合わせる必要がある。

最後に正直に一言。プロンプトキャッシングは「設定すれば自動的に節約できる」感覚の機能ではない。どのブロックをキャッシュするか、リクエストパターンがTTLと合っているか、キャッシュヒット率をどう測定するかを設計しなければならない。最初は面倒に見えるが、一度きちんと設定すればAPIコストが目に見えて変わる。私はその差を直接見た。

他の言語で読む

この記事は役に立ちましたか?

より良いコンテンツを作成するための力になります。コーヒー一杯で応援してください。

著者について

jw

Kim Jangwook

AI/LLM専門フルスタック開発者

10年以上のWeb開発経験を活かし、AIエージェントシステム、LLMアプリケーション、自動化ソリューションを構築しています。Claude Code、MCP、RAGシステムの実践的な知見を共有します。

ブログリストへ