コスト管理

Claudeプロンプトキャッシュの料金とコスト削減を理解する

キャッシュの書き込み・読み取り料金、TTL、ヒット率、ルーティングの影響を整理。損益分岐点とPythonによる検証手順を紹介します。

固定プレフィックスの再利用を測る

Claudeのプロンプトキャッシュは、処理済みの入力プレフィックスを再利用します。回答そのものの保存ではなく、各リクエストで生成する出力には引き続き料金がかかります。固定の指示、ツール定義、参照資料を変化する入力より前に置き、有効期間内の再利用頻度で利用を判断します。

ここではSonnet 4.6と20,000トークンのプレフィックスを使って計算します。実際のヒット率を予測するものではありません。導入先は料金比較、クライアント接続はClaude Code設定ガイドを参照してください。

仕様と外部価格は2026年10月17日に公式キャッシュ資料で確認しました。単価や最小長をほかのClaudeモデルにそのまま当てはめないでください。

書き込み・読み取り・通常入力を分ける

Anthropic形式の input_tokens は未キャッシュ入力、cache_creation_input_tokens は新規書き込み、cache_read_input_tokens は再利用分です。それぞれ別に計算します。cache_creation.ephemeral_5m_input_tokens と cache_creation.ephemeral_1h_input_tokens があれば、書き込み合計のTTL別内訳です。合計と内訳を重ねて加算しないでください。

Sonnet 4.6公式グローバルAPI:米ドル/100万トークン
区分単価費用を考える際の意味
通常入力$3.00キャッシュからの読み取り・書き込み以外の入力
5分書き込み$3.75通常入力より初回コストが高い
1時間書き込み$6.00保持時間を延ばす分、書き込みが高い
読み取り$0.30ヒット分も読み取り単価で課金
出力$15.00入力をキャッシュしても出力料金は必要

出典は公式標準料金です。API Routeでは現在のモデル・グループ料金と両方の書き込み期間を確認します。上流の倍率ではなく、利用中のサービスの実際の単価で計算してください。

リクエスト間隔に応じてTTLを選ぶ

ephemeralキャッシュの標準TTLは5分で、ヒットすると保持期間が更新されます。対応していれば cache_control: {"type":"ephemeral","ttl":"1h"} で1時間を指定できます。Sonnet 4.6の最小キャッシュ可能プレフィックスは1,024トークンです。内容と長さが条件を満たしても、すべてのゲートウェイでヒットする保証にはなりません。

実際のリクエスト間隔を記録しましょう。20分空くワークフローでは5分キャッシュの再書き込みが続く一方、対話が続く場合は短いTTLで足りる可能性があります。長いTTLは追加の書き込み料金を回収できるときに選びます。期限内でもプレフィックスが変わればコールドになる場合があります。

可能なら日時、リクエストID、利用者ごとの変更を固定部分より後に配置し、ツール定義と順序をそろえます。本番で閾値を超えるためだけに不要な入力を増やさないでください。下の生成テキストは検証用です。

損益分岐点とトークン基準の読み取り比率

Pをプレフィックスのトークン数、Nを利用回数、Wを書き込み単価、Rを読み取り単価、Iを通常入力単価とします。単価の単位は米ドル/100万トークンです。1回書き込み、N−1回ヒットする費用は P × (W + (N−1)R) / 1,000,000、キャッシュなしでは N × P × I / 1,000,000 です。実際の総額には固有の入力と出力を加えます。

20,000-token prefix, ten uses, Sonnet 4.6 direct rates:
Uncached: 10 * 0.02 * 3 = $0.6000
5m: 0.02 * (3.75 + 9 * 0.30) = $0.1290
1h: 0.02 * (6.00 + 9 * 0.30) = $0.1740

5m, two uses: $0.0810 vs $0.1200 uncached
1h, two uses: $0.1260 vs $0.1200 uncached
1h, three uses: $0.1320 vs $0.1800 uncached

長さが違う処理ではリクエスト数よりトークンで測ります。読み取り比率 = read_tokens / (uncached_input_tokens + write_tokens + read_tokens) は入力全体のうちキャッシュから供給された割合です。キャッシュ対象プレフィックスのヒット率も測る場合は、分母を別に明示してください。

追加の未キャッシュ末尾がなく、同じ長さのプレフィックスで、ミスが毎回書き込みになると仮定すると平均単価は hR + (1−h)W です。ここでの公式単価では、5分キャッシュはhが21.74%超、1時間キャッシュは52.63%超で通常入力より安くなります。実測ヒット率ではなく計算上の条件であり、単価と課金動作が変われば再計算します。

同じリクエストを2回送って検証する

Python 3の標準ライブラリだけを使います。以下を cache_probe.py に保存してください。固定のsystemプレフィックスに明示的なキャッシュ境界を置き、同一のMessagesリクエストを順番に2回送ります。両方に費用が生じる可能性があるため、最初は機密情報を使わずに試します。

ANTHROPIC_BASE_URL と ANTHROPIC_MODEL を設定します。API Routeでは https://global.api-route.com、利用可能なClaudeモデル、非公開の ANTHROPIC_AUTH_TOKEN を使います。公式へ直接送る場合は https://api.anthropic.com と ANTHROPIC_API_KEY です。認証変数は一つだけ設定してください。入力を隠す方法はシェル設定例にあります。

import json
import os
import urllib.request
import urllib.error

base = os.environ.get("ANTHROPIC_BASE_URL", "https://global.api-route.com").rstrip("/")
model = os.environ.get("ANTHROPIC_MODEL", "claude-sonnet-4-6")
token = os.environ.get("ANTHROPIC_AUTH_TOKEN")
api_key = os.environ.get("ANTHROPIC_API_KEY")
if bool(token) == bool(api_key):
    raise SystemExit("Set exactly one of ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY")

# Fixed, non-sensitive prefix, comfortably above Sonnet 4.6's minimum.
# Use the same bytes on both requests; no timestamps or random IDs.
prefix = "Follow the project rules below.\n" + "\n".join(
    f"Rule {i}: Validate inputs, document assumptions, and keep errors actionable."
    for i in range(400)
)
payload = {
    "model": model,
    "max_tokens": 32,
    "system": [{"type": "text", "text": prefix,
                "cache_control": {"type": "ephemeral"}}],
    "messages": [{"role": "user", "content": "Reply with OK."}],
}
headers = {"Content-Type": "application/json", "anthropic-version": "2023-06-01"}
headers.update({"Authorization": f"Bearer {token}"} if token else {"x-api-key": api_key})
for attempt in (1, 2):
    req = urllib.request.Request(base + "/v1/messages",
        data=json.dumps(payload).encode(), headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=120) as res:
            result = json.load(res)
    except urllib.error.HTTPError as exc:
        # Error bodies can contain provider details; inspect them privately.
        raise SystemExit(f"HTTP {exc.code}; inspect provider logs privately") from None
    usage = result.get("usage", {})
    print(json.dumps({"attempt": attempt, "model": result.get("model"), "usage": usage}))
    if "cache_read_input_tokens" not in usage or "cache_creation_input_tokens" not in usage:
        print("Cache fields absent: result is inconclusive; check provider billing logs.")
python cache_probe.py

実際のusageを比べ、1回目の書き込みと2回目の読み取りが正であれば、そのルート、その時点で再利用が発生した証拠になります。前の実行で温まっていれば1回目から読み取ることもあります。決まったトークン数や結果を想定しないでください。

応答のカウントと確定料金を照合する

  1. モデル、ルート・グループ、時刻、トークン内訳、取得可能なリクエストIDを記録し、認証情報は残しません。
  2. 利用ログで各リクエストを見つけ、区分ごとの単価を掛けて確定料金と比較します。明記された丸めも考慮してください。
  3. 後でTTLを超える間隔を置き、再実行して新規書き込みを観察します。スクリプト自体は待機や無限ループをしません。
  4. systemプレフィックスを変えてコールド時も試します。比較中はモデルとルートを固定します。
  5. キャッシュなしの基準を作るならcache_controlを外します。ただしゲートウェイが独自に有効化する場合があるため、usageで確認してから基準に採用します。

キャッシュフィールドがない結果は判定不能です。読み取りゼロには、短すぎる入力、失効、変更、ルート切り替え、制御非対応、変換時のフィールド欠落などが考えられます。無料入力や機能障害と決めつけず、具体的なリクエストをプロバイダーに照合してもらいましょう。

ルート変更で再利用が減る理由

フォールバックすると、次のリクエストが別の上流キャッシュへ送られる可能性があります。プロバイダー、アカウント、エンドポイントをまたいでキャッシュが共有されるとは限りません。可用性のための切り替えでもコールド処理が増える場合があるので、再試行とフォールバックを含む費用全体を測ります。

OpenRouterはキャッシュを考慮したスティッキールーティングと、フォールバックや順序指定の注意点を説明しています。他社にも同じ動作を想定しないでください。API Routeでは同じキー、モデル、選択ルートで繰り返し送信し、実際のキャッシュ課金を確認します。本記事ではキャッシュ維持やヒット率を約束していません。

本番の判断には、通常の会話長とアイドル時間を含むサンプルを使います。通常入力、読み取り、書き込み、出力、課金された失敗分を合計し、条件をそろえた基準と比較します。読み取り比率が高くても、出力中心の処理は高額になり得ます。

API Routeに登録し、代表的な入力を試して現在の料金と照合しましょう。初回接続はクイックスタートで確認し、期待どおりの費用がログに出てから継続利用を始めてください。