Python で実装する LLM プロンプトキャッシュ:動作するコード付きチュートリアル
目次
- 0. セットアップ
- 1. キャッシュを確認できる呼び出し方(全プロバイダー共通)
- 2. Anthropic Claude — 明示的な cache_control marker
- 3. OpenAI GPT-5.x — 自動キャッシュ
- 4. Google Gemini — 暗黙的なキャッシュ
- 5. DeepSeek-v4-flash — disk-backed の自動キャッシュ
- 6. Alibaba Qwen — hit は記録されるが割引は一定しない
- 7. プロバイダー横断 benchmark(2026-05-25 実測)
- 8. リリース前のチェックリスト
- 9. TTL を考慮したパターン
- 8.1 session 単位の workload(chat、IDE assistant)
- 8.2 batch / cron 向けの heartbeat
- 8.3 cold storage の文書
- 10. ゲートウェイが実際に提供するもの
- FAQ
TL;DR — 1 つの OpenAI SDK と 1 つの base_url で、主要な LLM をすべて利用できます。この記事の数値は、約 7,300 token の固定 system prompt を使い、2026-05-25 に稼働中の Synthorai ゲートウェイで実測したものです。ゲートウェイの役割はシンプルです。endpoint と認証 header を 1 つにまとめ、ベンダーごとの料金表を管理せずに済む usage.cost フィールドを返します。キャッシュの仕組みを支える Transformer の数理については Part 1:キャッシュの原理、プロバイダーごとの設計の違いについては Part 2:プロバイダー比較 で解説しています。
シリーズ:全 5 回の Part 3 · 前回:Part 1 — キャッシュの原理 · Part 2 — プロバイダーの比較と評価 · 次回:Part 4 — ユースケース別の最適な LLM · Part 5 — LangChain との統合
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 の wire format で呼び出せます。SDK を切り替える必要はなく、model フィールドだけを変更します。認証には Authorization: Bearer <key> を使います。
公開ゲートウェイでプロンプトキャッシュを利用できる model 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. キャッシュを確認できる呼び出し方(全プロバイダー共通)
明示的に有効化する必要はありません。上流でプロンプトキャッシュに対応しているモデルなら、ゲートウェイが response metadata をそのまま返します。結果は 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 は、上流の prefix cache に hit した input token 数です。usage.cost は、ゲートウェイが算出した 1 回の呼び出し料金を USD で示します。プロバイダーごとの料金表をローカルで管理する必要はありません。
アーキテクチャ上、すべてのプロバイダーに共通するルールは 2 つです。
- 固定部分を先に、変化する部分を後に置く。 prefix は token 0 から照合されます。先頭付近で 1 byte でも変わると、prefix 全体が無効になります。
- 動的なデータを system prompt に入れない。 現在時刻、session ID、request UUID は、いずれもキャッシュを無効にします。
以降は、同じパターンをベンダー別のコードで示します。
2. Anthropic Claude — 明示的な cache_control marker
Claude は 明示的な marker を使う方式です。Anthropic の API は自動でキャッシュしません。cache hit を得るには、system または messages 配列内に最大 4 つの cache_control breakpoint を指定します。cache read の料金は input 単価の約 10%、cache write は 125%(25%の割増)です。
ゲートウェイ経由で cache_control を使う最も簡単な方法は、公式の anthropic SDK からゲートウェイの Anthropic native endpoint を呼び出すことです。OpenAI 互換の /chat/completions では、現時点で cache_control marker が引き継がれません。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 分間の sliding TTL です。hit するたびに有効期限が延長されます。5 分を超える待機時間がある workload では、同じ marker に 1 時間の TTL を指定します。
"cache_control": {"type": "ephemeral", "ttl": "1h"}
階層化した breakpoint。 marker を最大 4 つ使えるため、「変更されない部分」「まれに変更される部分」「タスクごとに変更される部分」を個別にキャッシュできます。prompt の各 section が異なる頻度で変化する agent や RAG workload に最適です。末尾の層(取得した文書など)が呼び出しごとに変わっても、それより前の層は引き続き hit します。
モデルの選び方。 2026-05 時点でゲートウェイから利用できる Claude ID は、claude-haiku-4-5、claude-sonnet-4-5 / 4-6、claude-opus-4-5 / 4-6 / 4-7 です。低コストの chat には Haiku、汎用用途や agent でのキャッシュ活用には Sonnet、最も難しい推論タスクには Opus が向いています。
cache hit、write、キャッシュなしの実測値(2026-05-25、約 7,976 token の system prompt、max_tokens=64)。
| モデル | Cache write | Cache read | キャッシュなし | Read 割引率 | Hit 時の TTFT(stream) |
|---|---|---|---|---|---|
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 |
割引率は、すべてのモデルでほぼ同じです。write の割増はキャッシュなしの場合と比べて約 25%で、Anthropic の公開料金どおりです。cache hit が 1 回あれば元が取れます。
3. OpenAI GPT-5.x — 自動キャッシュ
OpenAI は、十分に長い共通 prefix を持つ request を自動でキャッシュします。コードの変更も marker も不要です。
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 token の prompt を 2 回送っています。2 回目は system prompt の 93%が cache hit し、全体の latency は 3.6 s から 1.2 s に短縮されました。この例では、初回の completion が長く、その料金がキャッシュ割引を相殺しているため、合計料金はほとんど変わりません。プロバイダー間で条件をそろえた数値は §7 に掲載しています。
gpt-5.4-nano では割引効果がより明確で、hit 時の料金は 44%下がりました。chat UI で time-to-first-token だけが重要なら、見るべきなのは streaming の数値です。
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 token の system prompt を gemini-2.5-flash に送った実測では、7,140 token(97%)が cache hit しました。料金は $0.00198 から $0.00024 に下がり、この呼び出しでは 88%削減 されています。
把握しておくべき注意点は 2 つあります。
- Gemini の
*-provariant は reasoning model です。max_tokensが小さいと、token の割り当てが内部の思考で使い切られ、completion_tokens=0になることがあります。ユーザー向けの用途では、max_tokensを 256 以上にしてください。 - 暗黙的なキャッシュの TTL は短く、公式には具体的な値が公開されていません。今回のテストでは、5 s 間隔の 2 回目は hit しましたが、さらに約 10 s 後の 3 回目は miss することがありました。必ず hit する前提でロジックを組まず、
cached_tokensを確認し、miss しても正常に動作するよう設計してください。
5. DeepSeek-v4-flash — disk-backed の自動キャッシュ
DeepSeek の自動キャッシュは、他ベンダーの GPU memory 上のキャッシュより長く保持されます。呼び出し方は同じです。
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
キャッシュ済みの呼び出しにおける streaming TTFT は 2.93 s でした。今回比較したモデルの中で、DeepSeek は latency が最小ではありません。強みは低コストであることと、数時間単位の間隔が空いてもキャッシュが warm な状態を維持できることです。
6. Alibaba Qwen — hit は記録されるが割引は一定しない
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 には hit が記録されています(7,234 token 中 7,040 token、97%)が、キャッシュ済みの呼び出しでも usage.cost は下がらず、約 $0.0055 のままでした。上流では cache hit しており、TTFT は cold 時の 3.03 s から 1.53 s に短縮されています。ただし、この時点ではゲートウェイが返すこのプロバイダーの料金に、キャッシュ割引が反映されていませんでした。Qwen のコストを重視する場合は、cached_tokens を監視し、この状態が解消されるまでは上流の料金ページを参照してください。
7. プロバイダー横断 benchmark(2026-05-25 実測)
1 回の連続したテストで計測しています。固定 system prompt は 7,284 文字で、tokenizer により約 6,900~7,300 token です。max_tokens=64 とし、miss する呼び出しの直後に hit する呼び出しを実行しました。
marker が不要な自動キャッシュ対応プロバイダーの結果です。
| モデル | Miss 料金 | Hit 料金 | 料金差 | Miss 合計時間 | Hit 合計時間 | Hit 時の TTFT(stream) | Cache hit 率 |
|---|---|---|---|---|---|---|---|
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 | 該当なし‡ | 7,140 / 7,322(97%) |
gemini-2.5-pro | $0.00824 | $0.00205† | −75% | 2.99 s | 1.76 s | 該当なし‡ | 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 の completion は、miss 時が 44 token、hit 時が 19 token でした。料金差にはキャッシュ割引だけでなく、completion の長さの違いも含まれています。ここでは latency の短縮(3.63 → 1.23 s)のほうが明確な指標です。
† cached_tokens が記録された streaming 時の料金です。Gemini では、非 streaming の呼び出しで cached_tokens=null が返り、料金も下がらない場合がありました。現時点では、Gemini の gateway metadata に一貫性がありません。cached_tokens が存在する場合は、その値を使ってください。
‡ Gemini の *-pro / *-flash reasoning model は、max_tokens が小さいと content token を 1 つも返さないことがあります。この条件では TTFT に意味がありません。本番環境で計測する場合は max_tokens を増やしてください。
§ §6 を参照してください。上流では cache hit して latency も短縮されましたが、この時点の qwen3-max では、ゲートウェイの usage.cost フィールドに割引が反映されませんでした。
Anthropic Claude は明示的な marker を使います。cache_control で opt-in する方式なので、結果を別の表にまとめました。実装方法は §2 を参照してください。同じ prompt を使い、cache write と cache read を計測した結果です。
| モデル | Write 料金 | Read 料金 | Read 割引率 | Hit 時の TTFT(stream) |
|---|---|---|---|---|
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 |
実際の数値は、region、時間帯、ほかの tenant が同じ prefix を使っているかによって変わります。特定の日に 1 回だけ実行した結果なので、決定的な benchmark として引用しないでください。
8. リリース前のチェックリスト
キャッシュを考慮した prompt を本番投入する前に、次を確認してください。
- 固定部分を先に置く — system prompt、knowledge base、tool schema を
messagesの先頭に配置します。 - 変化する部分を後に置く — user input、取得した文書、timestamp を末尾に配置します。
systemに動的な変数を入れない — 現在時刻、user ID、random seed は prefix を無効にします。- すべての呼び出しで
cached_tokensを log に記録する。 本番環境で hit 率が 50%未満なら、prefix は実際には固定されていません。miss した prompt を調査してください。 - 1 回の hit だけで判断しない。 TTL は短いため、「常に hit する」のではなく、
hit_rate ∈ [0, 1)を前提に設計してください。
9. TTL を考慮したパターン
本番環境で最も多い失敗は、キャッシュの有効化を忘れることではありません。request が TTL 内に到着せず、hit 率が 12%にとどまることです。
8.1 session 単位の workload(chat、IDE assistant)
通常の呼び出し間隔は TTL より十分に短くなります。prompt を適切に構成すれば、キャッシュは自動的に warm な状態を維持します。それ以外の仕組みは不要です。
8.2 batch / cron 向けの heartbeat
毎日 09:00 に 3 分間で 50 回モデルを呼び出す report job では、最初の cache write が無駄になります。前日のキャッシュが overnight で cold になっているためです。08:55 以降、キャッシュ対象の prefix と 1 token の「ping」を TTL/2 ごとに送り、warm な状態を維持します。
def keepalive():
oai.chat.completions.create(
model="gpt-5.4-mini",
max_tokens=1,
messages=[
{"role": "system", "content": LONG_STABLE_PROMPT},
{"role": "user", "content": "."},
],
)
1 回の ping にかかる料金は、input token 数にキャッシュ単価を掛けたものです。gpt-5.4-mini で 7K token の prefix を使う今回の条件では、約 $0.0026 です。batch job の最初の 50 回の本番呼び出しで、すべて full prefill の料金を払うより大幅に安くなります。
8.3 cold storage の文書
日中に 1 時間に 1 回など、参照頻度が低い文書では、in-memory cache はほとんどの時間で cold になります。執筆時点で、ゲートウェイは hosted explicit-cache の作成 endpoint を公開していません。長い TTL が必要なら、実運用で数時間の間隔が空いても保持される disk-backed の deepseek-v4-flash を使うか、ゲートウェイを経由せず Google native の cachedContent API を直接呼び出してください。
10. ゲートウェイが実際に提供するもの
ゲートウェイがキャッシュ処理を代行すると説明するのは正確ではありません。キャッシュは model layer で行われ、ゲートウェイはその情報を公開するだけです。各ベンダーの native SDK を直接使う場合と比較して、ゲートウェイが提供する機能は 3 つです。
- 1 つの base_url と 1 つの auth header ですべてのモデルを呼び出せる。
modelフィールドを切り替えても、呼び出し形式は変わりません。同じmessages配列と同じusageフィールド構造を使えます。5 社のプロバイダーに 5 種類の SDK を用意する必要はありません。 - 呼び出しごとの USD 建て
usage.cost。 ゲートウェイが現在の上流料金から USD 建てのコストを計算し、すべての response に含めます。コード内で料金表を管理する必要がなく、ベンダーごとの料金改定通知を購読する必要もありません。 - 統一された
cached_tokensフィールド。 Anthropic は cache hit をcache_read_input_tokens、OpenAI はprompt_tokens_details.cached_tokens、DeepSeek はprompt_cache_hit_tokensとして返します。ゲートウェイは OpenAI 形式に統一するため、observability のコードをプロバイダーごとに分岐させる必要がありません。
ゲートウェイの役割はこれだけです。いつキャッシュするか、prompt をどう構成するか、どのモデルを選ぶかについては、次の記事で扱います。
次回:Part 4 — ユースケース別に最適な LLM を選ぶ方法:chat、API、AI agent — workload の種類と最適なモデル、キャッシュ戦略を対応付けた decision matrix を、コスト計算とともに紹介します。
FAQ
OpenAI 以外のモデルに OpenAI SDK を使う理由は何ですか?
ゲートウェイは、扱うすべてのプロバイダーに対して OpenAI の wire format を使用します。公式の openai SDK なら、型付き response、自動 retry、streaming helper を利用できます。5 種類の HTTP client を個別に実装する理由はありません。
streaming response でもキャッシュは機能しますか?
はい。stream_options={"include_usage": True} を渡すと、最後の chunk に含まれる usage object から cache hit 数を確認できます。ユーザーが体感するのは TTFT なので、latency の改善は streaming で最も明確に表れます。
自分の workload でキャッシュ割引が最も大きいプロバイダーはどれですか?
2026-05 時点の料金で hit 率が 70%以上なら、§7 の表では gemini-2.5-flash と deepseek-v4-flash が最も安価です。TTFT では gpt-5.4-mini が最速です。Claude で公開どおりの 90%割引を受けるには、最大 4 つの cache_control breakpoint を指定してください(§2 を参照)。実際の prompt で同じ benchmark を実行してください。1 日で完了する作業であり、数週間かかる移行ではありません。
cache_control marker が必要なのはいつですか?
Anthropic Claude を呼び出す場合だけです。§2 を参照してください。OpenAI、Gemini、DeepSeek、Qwen は、十分に長い prefix を上流で自動的にキャッシュするため、marker は不要です。これらのプロバイダーに対して指定しても、そのフィールドは無視されます。
この数値はいつ計測したものですか? 公開ゲートウェイ上で 2026-05-25 に計測しました。あくまで 1 つのデータポイントです。料金と latency は release cycle ごとに変化します。
Anthropic Claude はどうですか?
Claude は、明示的な cache_control marker を使ってゲートウェイから利用できます。anthropic SDK に base_url="https://synthorai.io/" を指定してください。SDK が /v1/messages を追加します。現時点では、OpenAI 互換の /chat/completions で marker が引き継がれません。Claude のキャッシュには、§2 で示した Anthropic native の path を使ってください。
出典と検証方法:すべての数値は、openai SDK 2.38.0 を使い、2026-05-25 に https://synthorai.io/v1 で実測しました。各ベンダーの料金ページ:Anthropic のプロンプトキャッシュ · OpenAI のプロンプトキャッシュ · Google Gemini のコンテキストキャッシュ · DeepSeek KV キャッシュガイド · Alibaba Bailian のコンテキストキャッシュ。