LLM プロンプトキャッシュ #3:動く Python チュートリアル
目次
- 0. セットアップ
- 1. キャッシュを意識した呼び出し(どのプロバイダーでも同じ)
- 2. Anthropic Claude —— 明示的な cache_control マーカー
- 3. OpenAI GPT-5.x —— 自動キャッシュ
- 4. Google Gemini —— 暗黙的キャッシュ
- 5. DeepSeek-v4-flash —— ディスク裏付けの自動キャッシュ
- 6. Alibaba Qwen —— ヒットは報告されるが割引は不安定
- 7. クロスプロバイダーのベンチマーク(2026-05-25 実測)
- 8. ローンチ前チェックリスト
- 9. TTL を意識したパターン
- 8.1 セッションに紐づくワークロード(チャット、IDE アシスタント)
- 8.2 バッチ / Cron のためのハートビート
- 8.3 コールドストレージの文書
- 10. ゲートウェイが実際に付け加えるもの
- FAQ
要約 — OpenAI SDK 一つ、base_url 一つで、主要な LLM すべてに対応。本記事の数値は、約 7,300 トークンの安定したシステムプロンプトを使い、2026-05-25 に稼働中の Synthorai ゲートウェイに対して実測したものです。ここでのゲートウェイの役割は控えめで誠実です。単一のエンドポイント、単一の認証ヘッダー、そしてベンダーごとの価格マトリクスを維持しなくて済む usage.cost フィールド、これだけです。キャッシュの背後にある Transformer の理論は 第 1 部:キャッシュの原理 で扱っています。プロバイダーごとの設計上の選択は 第 2 部:プロバイダー比較 にあります。
シリーズ:全 4 部中の第 3 部 · 前回:第 1 部 — キャッシュの原理 · 第 2 部 — プロバイダー比較と評価 · 次回:第 4 部 — ユースケース別の最適な LLM
0. セットアップ
pip install openai
# common.py — reused across every example
import os, time
from openai import OpenAI
oai = OpenAI(
api_key=os.environ["SYNTHORAI_KEY"],
base_url="https://synthorai.io/v1",
)
ゲートウェイは、フロントに立つすべてのモデル(GPT、Claude、Gemini、DeepSeek、Qwen)に対して OpenAI のワイヤフォーマットを話します。変更するのは model フィールドであって、SDK ではありません。認証は Authorization: Bearer <key> を使います。
公開ゲートウェイで利用できるキャッシュ対応モデル ID(2026-05 時点のスナップショット):claude-haiku-4-5、claude-sonnet-4-5 / 4-6、claude-opus-4-5 / 4-6 / 4-7、gpt-5.4-mini、gpt-5.4-nano、gpt-5.2、gpt-5.5-pro、gemini-2.5-flash、gemini-2.5-pro、gemini-3.1-pro-preview、deepseek-v4-flash、qwen3-max、qwen3.5-flash。完全な最新リストは GET /v1/models にあります。
1. キャッシュを意識した呼び出し(どのプロバイダーでも同じ)
オプトインする必要はありません。上流でプロンプトキャッシュをサポートするモデルであれば、ゲートウェイはレスポンスのメタデータをそのまま透過させるだけです。何が起きたかは 2 つのフィールドが教えてくれます:
resp = oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=128,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT}, # ~7K tokens
{"role": "user", "content": "First question"},
],
)
print(resp.usage.prompt_tokens_details.cached_tokens) # cache hit count
print(resp.usage.cost) # USD, gateway-computed
cached_tokens は、上流のプレフィックスキャッシュにヒットした入力トークンの数です。usage.cost は、この 1 回の呼び出しに対してゲートウェイが計算した価格(USD)です。プロバイダーごとのレート表をローカルで保持する必要はありません。
アーキテクチャから導かれ、すべてのプロバイダーに当てはまる 2 つのルール:
- 安定した内容を先に、変動する内容を後に。 プレフィックスはトークン 0 からマッチングされます。先頭で 1 バイトでも変わると、プレフィックス全体が無効になります。
- 動的データをシステムプロンプトに入れない。 現在のタイムスタンプ、セッション ID、リクエスト UUID はすべてキャッシュを壊します。
以下はすべて、同じパターンをベンダーごとに例示したものにすぎません。
2. Anthropic Claude —— 明示的な cache_control マーカー
Claude は明示マーカーファミリーです。Anthropic の API は自動キャッシュしません。キャッシュヒットを得るには、system または messages 配列に最大 4 つの cache_control ブレークポイントをマークします。キャッシュ読み取りは入力レートの約 10%、キャッシュ書き込みは 125%(25% の割増)です。
ゲートウェイ経由で cache_control を使う最もきれいな方法は、公式の anthropic SDK をゲートウェイの Anthropic ネイティブエンドポイントに向けることです(OpenAI 互換の /chat/completions パスは現在 cache_control マーカーを伝播しません。Claude のキャッシュには /v1/messages を使ってください)。
import os
from anthropic import Anthropic
anth = Anthropic(
api_key=os.environ["SYNTHORAI_KEY"],
base_url="https://synthorai.io/", # SDK appends /v1/messages
)
msg = anth.messages.create(
model="claude-sonnet-4-5",
max_tokens=512,
system=[
{"type": "text", "text": SYSTEM_INSTRUCTIONS,
"cache_control": {"type": "ephemeral"}}, # BP 1: never changes
{"type": "text", "text": TOOL_DESCRIPTIONS,
"cache_control": {"type": "ephemeral"}}, # BP 2: rarely changes
{"type": "text", "text": RETRIEVED_DOCUMENTS}, # changes per call — not cached
],
messages=[{"role": "user", "content": question}],
)
print(msg.usage)
# Usage(input_tokens=18, output_tokens=64,
# cache_creation_input_tokens=0, cache_read_input_tokens=8123,
# cost=...)
TTL オプション。 {"type": "ephemeral"} はデフォルトで 5 分のスライディング TTL(ヒットするたびに有効期限が先に延びる)になります。アイドル間隔が 5 分を超えるワークロードでは、同じマーカーに 1 時間の TTL を要求します:
"cache_control": {"type": "ephemeral", "ttl": "1h"}
階層化したブレークポイント。 最大 4 つのマーカーにより、「決して変わらない」+「めったに変わらない」+「タスクごとに変わる」内容を独立してキャッシュできます。プロンプトの各セクションが異なる頻度で変化するエージェントや RAG のワークロードにとって、これは同種で最良の機能です。末尾のレイヤー(例:検索した文書)が呼び出しごとに変わっても、前段のレイヤーは依然としてヒットします。
モデルの選択。 2026-05 時点でゲートウェイ上で利用できる Claude ID:claude-haiku-4-5、claude-sonnet-4-5 / 4-6、claude-opus-4-5 / 4-6 / 4-7。Haiku は安価なチャット向け、Sonnet は最も強力なエージェントキャッシュパターンを持つ汎用向け、Opus は最も難しい推論タスク向けです。
実測のキャッシュヒット / 書き込み / キャッシュなしの基準値(2026-05-25、約 7,976 トークンのシステムプロンプト、max_tokens=64):
| モデル | キャッシュ書き込み | キャッシュ読み取り | キャッシュなし基準 | 読み取り割引 | ヒット TTFT(ストリーミング) |
|---|---|---|---|---|---|
claude-haiku-4-5 | $0.00916 | $0.00086 | $0.00725 | −88% | 1.31 s |
claude-sonnet-4-5 | $0.02713 | $0.00247 | $0.02175 | −89% | 1.76 s |
claude-sonnet-4-6 | $0.02736 | $0.00253 | $0.02198 | −88% | 1.81 s |
claude-opus-4-5 | $0.04522 | $0.00409 | $0.03624 | −89% | 2.08 s |
claude-opus-4-6 | $0.04522 | $0.00411 | $0.03625 | −89% | 2.55 s |
claude-opus-4-7 | $0.06545 | $0.00609 | $0.05259 | −88% | 2.30 s |
割引はファミリー全体で一様に保たれます。書き込みの割増はキャッシュなしより約 25%(Anthropic が文書化しているレート)。損益分岐点はキャッシュヒット 1 回です。
3. OpenAI GPT-5.x —— 自動キャッシュ
OpenAI は、プレフィックスが十分に長いリクエストを自動的にキャッシュします。コード変更もマーカーも不要です。
def ask_gpt(question: str):
t0 = time.perf_counter()
resp = oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=64,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": question},
],
)
return resp, time.perf_counter() - t0
r1, t1 = ask_gpt("Which export formats are supported?")
r2, t2 = ask_gpt("How long is the refund window for annual plans?")
print(t1, r1.usage.prompt_tokens_details.cached_tokens, r1.usage.cost)
# 3.63 0 0.00267
print(t2, r2.usage.prompt_tokens_details.cached_tokens, r2.usage.cost)
# 1.23 6400 0.00257
同じ 6,887 トークンのプロンプトを 2 回。2 回目の呼び出し:システムプロンプトの 93% がキャッシュにヒットし、総レイテンシは 3.6 s から 1.2 s に低下します。ここでコストがほとんど変わらないのは、キャッシュ割引が初回呼び出しのより長い補完によって相殺されるためです。よりきれいなクロスプロバイダーの数値は §7 を参照してください。
gpt-5.4-nano は割引をより明確に示します(ヒット時にコスト 44% 減)。time-to-first-token だけを気にするチャット UI では、ストリーミングの数値こそが重要です:
def ttft(model, question):
t0 = time.perf_counter()
stream = oai.chat.completions.create(
model=model, max_tokens=64,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": question},
],
stream=True, stream_options={"include_usage": True},
)
for ev in stream:
if ev.choices and ev.choices[0].delta and ev.choices[0].delta.content:
return time.perf_counter() - t0 # first content token
キャッシュヒット時に実測した TTFT:gpt-5.4-mini で 0.73 s、gpt-5.4-nano で 1.00 s。
4. Google Gemini —— 暗黙的キャッシュ
ゲートウェイ経由でアクセスする場合、Gemini のキャッシュも自動です。実行が必要な cachedContent の作成ステップはありません。
r = oai.chat.completions.create(
model="gemini-2.5-flash",
max_tokens=128,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Summarize section 6 in two bullets."},
],
)
print(r.usage.prompt_tokens_details.cached_tokens, r.usage.cost)
約 7,300 トークンのシステムプロンプトに対する gemini-2.5-flash での実測ヒット:7,140 キャッシュトークン(97%)、コストは $0.00198 から $0.00024 に低下 —— その回は 88% 割引。
知っておく価値のある 2 つの落とし穴:
- Gemini の
*-pro系は推論モデルです。max_tokensが小さいと、予算が隠れた思考に消費されるため、completion_tokens=0がよく見られます。ユーザー向けのものではmax_tokensを ≥256 に上げてください。 - 暗黙的キャッシュの TTL は短く、公式には明示されていません。私たちのテストでは、5 s 間隔の 2 回の呼び出し間ではヒットが成功しましたが、約 10 s 後の 3 回目の呼び出しは時々ミスしました。ヒットを前提とするロジックを組まないでください。
cached_tokensを確認し、優雅にフォールバックしてください。
5. DeepSeek-v4-flash —— ディスク裏付けの自動キャッシュ
DeepSeek の自動キャッシュは、他ベンダーの GPU メモリ常駐キャッシュより長く生き残ります。呼び出しの形は同じです:
r1 = oai.chat.completions.create(
model="deepseek-v4-flash", max_tokens=128,
messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Q1"}],
)
# r1.usage.cost = $0.00091, cached_tokens = 0
r2 = oai.chat.completions.create(
model="deepseek-v4-flash", max_tokens=128,
messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Q2"}],
)
# r2.usage.cost = $0.00023, cached_tokens = 6784 → 74% saved
キャッシュヒット時のストリーミング TTFT:2.93 s。このセットの中で DeepSeek は最も低レイテンシな選択肢ではありません。利点はコスト、そしてキャッシュが時間単位のギャップを跨いで温かいまま保たれるという点にあります。
6. Alibaba Qwen —— ヒットは報告されるが割引は不安定
r = oai.chat.completions.create(
model="qwen3-max", max_tokens=128,
messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "Q1"}],
)
print(r.usage.prompt_tokens_details.cached_tokens, r.usage.cost)
# 7040 0.00549
私たちのテスト実行で見られた注意点:cached_tokens はヒットを報告していますが(7,234 のうち 7,040 = 97%)、usage.cost はキャッシュヒット時に下がりませんでした(依然として約 $0.0055)。これは、上流のキャッシュヒットは起きた(TTFT が速い、1.53 s 対コールド 3.03 s)ものの、このプロバイダーに対するゲートウェイのコストフィールドが、この日付ではまだキャッシュレートの割引を反映していなかったことを意味します。Qwen でコストにシビアなら、cached_tokens を注視し、これが正常化するまでは上流の価格ページを信頼してください。
7. クロスプロバイダーのベンチマーク(2026-05-25 実測)
単一の逐次実行。7,284 文字(トークナイザーにより約 6,900–7,300 トークン)の安定したシステムプロンプト。max_tokens=64。ミス呼び出し 1 回の直後にヒット呼び出し 1 回。
自動キャッシュのプロバイダー(マーカー不要):
| モデル | ミスコスト | ヒットコスト | コスト Δ | ミス総時間 | ヒット総時間 | ヒット TTFT(ストリーミング) | キャッシュヒット率 |
|---|---|---|---|---|---|---|---|
gpt-5.4-nano | $0.00131 | $0.00074 | −44% | 2.18 s | 1.48 s | 1.00 s | 5,888 / 6,887 (85%) |
gpt-5.4-mini | $0.00267 | $0.00257 | −4%* | 3.63 s | 1.23 s | 0.73 s | 6,400 / 6,887 (93%) |
gemini-2.5-flash | $0.00198 | $0.00024† | −88% | 2.49 s | 1.37 s | n/a‡ | 7,140 / 7,322 (97%) |
gemini-2.5-pro | $0.00824 | $0.00205† | −75% | 2.99 s | 1.76 s | n/a‡ | 6,120 / 7,328 (84%) |
deepseek-v4-flash | $0.00091 | $0.00023 | −74% | 4.02 s | 3.71 s | 2.93 s | 6,784 / 7,101 (96%) |
qwen3-max | $0.00553 | $0.00549 | −1%§ | 4.80 s | 2.37 s | 1.53 s | 7,040 / 7,234 (97%) |
* gpt-5.4-mini のミス呼び出しの補完は 44 トークン、ヒット呼び出しは 19 トークンでした。コスト差はキャッシュ割引と補完長の差が混ざっています。ここでよりきれいな信号はレイテンシの低下(3.63 → 1.23 s)です。
† ストリーミング側のコスト(cached_tokens が報告された方)。非ストリーミング側は Gemini に対して時々 cached_tokens=null を返し、コストが下がりませんでした。Gemini に対するゲートウェイのメタデータは現在一貫していません。cached_tokens が存在する場合はそれを信頼してください。
‡ Gemini の *-pro / *-flash 推論モデルは、小さな max_tokens ではしばしばコンテンツトークンをゼロしか出さないため、その予算では TTFT は無意味です。本番で測定するなら max_tokens を上げてください。
§ §6 を参照 —— 上流のキャッシュヒットは起きた(レイテンシは下がった)ものの、ゲートウェイの usage.cost フィールドはこの日付で qwen3-max の割引を反映しませんでした。
Anthropic Claude は明示マーカー駆動です。割引が cache_control でオプトインされるため、数値は別の表に分けています(パターンは §2 を参照)。同じプロンプトで、実測のキャッシュ書き込み対キャッシュ読み取り:
| モデル | 書き込みコスト | 読み取りコスト | 読み取り割引 | ヒット TTFT(ストリーミング) |
|---|---|---|---|---|
claude-haiku-4-5 | $0.00916 | $0.00086 | −88% | 1.31 s |
claude-sonnet-4-5 | $0.02713 | $0.00247 | −89% | 1.76 s |
claude-sonnet-4-6 | $0.02736 | $0.00253 | −88% | 1.81 s |
claude-opus-4-5 | $0.04522 | $0.00409 | −89% | 2.08 s |
claude-opus-4-6 | $0.04522 | $0.00411 | −89% | 2.55 s |
claude-opus-4-7 | $0.06545 | $0.00609 | −88% | 2.30 s |
あなたの数値は、リージョン、時間帯、そして他テナントのプレフィックスの温かさによって異なります。単一実行・単一日付 —— これらをベンチマークの絶対的真理として引用しないでください。
8. ローンチ前チェックリスト
キャッシュを意識したプロンプトを出荷する前に:
- 安定した内容を先に —— システムプロンプト、ナレッジベース、ツールスキーマを
messagesの先頭に。 - 変動する内容を後に —— ユーザー入力、検索した文書、タイムスタンプを末尾に。
systemに動的変数を入れない —— 現在時刻、ユーザー ID、ランダムシードはプレフィックスを破壊します。- 毎回の呼び出しで
cached_tokensをログに残す。 本番でヒット率が 50% を下回るなら、プレフィックスは実際には安定していません。ミスするプロンプトを調査してください。 - 単一のヒット試行を信じない。 TTL は短いです。「常にヒット」ではなく
hit_rate ∈ [0, 1)を前提に設計してください。
9. TTL を意識したパターン
本番で最も多い失敗モードは「キャッシュを有効にし忘れた」ではなく、「リクエストが実際には TTL ウィンドウ内に到着しないため、ヒット率が 12% しかない」です。
8.1 セッションに紐づくワークロード(チャット、IDE アシスタント)
自然なペースは TTL を十分に下回ります。プロンプトを正しく構成すれば、キャッシュは自分で温かいまま保たれます。他に何も作り込まないでください。
8.2 バッチ / Cron のためのハートビート
09:00 に日次レポートを実行し、3 分間のバーストでモデルを 50 回呼ぶ場合、キャッシュは夜間にコールドになっているため、09:00 の最初のキャッシュ書き込みは無駄になります。08:55 から、TTL/2 ごとにキャッシュ済みプレフィックスとともに 1 トークンの「ping」を送り、温かく保ちます:
def keepalive():
oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=1,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "."},
],
)
ping 1 回あたりのコストは入力トークン × キャッシュレートで、7K トークンのプレフィックスを gpt-5.4-mini で使う場合は約 $0.0026 です。バッチジョブに最初の 50 回の実呼び出しでフルの prefill を支払わせるより、はるかに安く済みます。
8.3 コールドストレージの文書
散発的に(一日を通して 1 時間に 1 回)クエリされる文書では、インメモリキャッシュはほとんどの時間コールドです。本記事執筆時点で、ゲートウェイはホスト型の明示キャッシュ作成エンドポイントを公開していません。長 TTL のニーズには deepseek-v4-flash(ディスク裏付け。実運用で時間単位のギャップを生き延びる)を使うか、ゲートウェイの外で Google ネイティブの cachedContent API を直接呼び出してください。
10. ゲートウェイが実際に付け加えるもの
ゲートウェイが「あなたの代わりにキャッシュをやってくれる」と主張するのは不誠実です。キャッシュはモデル層で起こり、ゲートウェイはそこにあるものを公開します。各ベンダーのネイティブ SDK を直接使う場合と比較して、それが実際に付け加えるのは次の 3 つです:
- 一つの base_url、一つの認証ヘッダー、すべてのモデル。
modelフィールドを差し替えても呼び出しの形は変わりません。同じmessages配列、同じusageフィールド構造です。5 プロバイダーに対して 5 つの SDK を抱える必要はありません。 - 呼び出しごとの
usage.cost(USD)。 ゲートウェイは現在の上流レートを使ってドルコストを計算し、すべてのレスポンスに含めます。コードの中に価格マトリクスを維持する必要も、ベンダーごとの価格変更通知を購読する必要もありません。 - 統一された
cached_tokensフィールド。 Anthropic はキャッシュヒットをcache_read_input_tokens、OpenAI はprompt_tokens_details.cached_tokens、DeepSeek はprompt_cache_hit_tokensとして報告します。ゲートウェイはこれらを OpenAI の形に正規化するので、あなたの可観測性コードはプロバイダーで分岐する必要がありません。
これが訴求のすべてです。残りすべて —— いつキャッシュするか、プロンプトをどう構成するか、どのモデルを選ぶか —— は次回の記事の仕事です。
次回:第 4 部 — ユースケース別の最適な LLM の選び方:チャット、API、AI エージェント —— ワークロードのタイプを最適なモデル + キャッシュ戦略に対応づける決定マトリクスを、コスト計算付きで。
FAQ
なぜ OpenAI 以外のモデルに OpenAI SDK を使うのですか?
ゲートウェイは、フロントに立つすべてのプロバイダーに対して OpenAI のワイヤフォーマットを話します。公式 openai SDK は型付きレスポンス、自動リトライ、ストリーミングヘルパーを提供します。5 つの HTTP クライアントを手書きする理由はありません。
キャッシュはストリーミングレスポンスでも機能しますか?
機能します。最終チャンクの usage オブジェクトがキャッシュヒット数を報告します(stream_options={"include_usage": True} を渡したとき)。レイテンシのメリットはストリーミングで最も顕著です。ユーザーが見るのは TTFT だからです。
私のワークロードでは、どのプロバイダーのキャッシュ割引が最も深いですか?
2026-05 の価格と 70%+ のヒット率では、§7 の表で最も安いのは gemini-2.5-flash と deepseek-v4-flash です。TTFT では gpt-5.4-mini が勝ちます。Claude の文書化された 90% のキャッシュ割引を得るには、最大 4 つの cache_control ブレークポイントをマークします(§2 を参照)。あなた自身のプロンプトに対して同じベンチマークを実行してください。それは数週間の移行ではなく、一日の作業です。
cache_control マーカーはいつ必要ですか?
Anthropic Claude を呼ぶときだけです —— §2 を参照。OpenAI/Gemini/DeepSeek/Qwen では、上流が十分に長いプレフィックスを自動キャッシュするのでマーカーは不要です。これらのプロバイダーに対してはこのフィールドは静かに無視されます。
これらの数値はどれくらい新しいですか? 2026-05-25 に公開ゲートウェイで実測しました。単一のデータポイントとして扱ってください。価格とレイテンシはリリースサイクルごとに変わります。
Anthropic Claude についてはどうですか?
Claude は明示的な cache_control マーカーを使ってゲートウェイ経由でサポートされます —— base_url="https://synthorai.io/" を指定した anthropic SDK を使ってください(SDK が /v1/messages を付加します)。OpenAI 互換の /chat/completions パスは今のところマーカーを伝播しません。Claude のキャッシュに特化する場合は、§2 に示した Anthropic ネイティブのパスを使ってください。
出典と検証:すべての数値は openai SDK 2.38.0 を使い、2026-05-25 に https://synthorai.io/v1 に対して実測しました。ベンダーの価格ページ:Anthropic Prompt Caching · OpenAI Prompt Caching · Google Gemini Context Caching · DeepSeek KV Cache Guide · Alibaba Bailian Context Cache.