LLM 提示快取 #3:可執行的 Python 教學
目錄
太長不看 — 一套 OpenAI SDK、一個 base_url,涵蓋所有主流 LLM。本文中的數據於 2026-05-25 針對線上 Synthorai 閘道、使用約 7,300 token 的穩定系統提示實測得出。閘道在這裡的作用是樸實而誠實的:一個端點、一個驗證標頭,以及一個 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. 感知快取的呼叫(每個廠商都一樣)
你不必主動啟用。對於任何上游支援提示快取的模型,閘道只是把回應的中繼資料透傳過來。有兩個欄位告訴你發生了什麼:
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 是命中上游前綴快取的輸入 token 數量。usage.cost 是閘道為這一次呼叫計算出的價格(USD)—— 無需在本地維護依廠商劃分的費率表。
由架構推導而來、適用於所有廠商的兩條規則:
- 穩定內容在前,易變內容在後。 前綴從第 0 個 token 開始比對;開頭處哪怕一個位元組的改動都會使整個前綴失效。
- 不要把動態資料放進系統提示。 目前的時間戳記、工作階段 ID、請求 UUID 都會破壞快取。
下面的內容只是同一模式在各廠商上的範例而已。
2. Anthropic Claude —— 顯式 cache_control 標記
Claude 屬於顯式標記家族 —— Anthropic 的 API 不會自動快取。要取得快取命中,需要在 system 或 messages 陣列中標註最多四個 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"}
分層斷點。 最多四個標記讓你可以獨立快取「從不改變」+「很少改變」+「每次任務改變」的內容 —— 對於提示各部分以不同頻率變化的代理人與 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 token 系統提示,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 文件所述的費率);只需一次快取命中即可回本。
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 token 的提示呼叫兩次。第二次呼叫:系統提示的 93% 命中快取,總延遲從 3.6 s 降到 1.2 s。這裡成本幾乎沒變,因為快取折扣被一次更長的首呼叫補全所抵銷 —— 更乾淨的跨廠商數據見 §7。
gpt-5.4-nano 更清楚地展現了折扣(命中時成本降低 44%)。對於只在意首 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)
gemini-2.5-flash 在約 7,300 token 系統提示上的一次實測命中:7,140 個快取 token(97%),成本從 $0.00198 降到 $0.00024 —— 那一次便宜了 88%。
兩個值得了解的坑:
- Gemini 的
*-pro變體是推理模型。當max_tokens很小時,你經常會看到completion_tokens=0,因為預算被隱藏的思考消耗掉了。對任何面向使用者的情境,把max_tokens調到 ≥256。 - 隱式快取的 TTL 很短,且官方未明確說明。在我們的測試中,相隔 5 s 的兩次呼叫之間命中成功;而約 10 s 後的第三次呼叫有時會未命中。不要設計假定一定會命中的邏輯;請檢查
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. 阿里 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 vs 冷啟動 3.03 s),但閘道對該廠商的成本欄位在這一日期尚未反映出快取費率的折扣。如果你在 Qwen 上對成本敏感,請關注 cached_tokens,並在這一問題正常化之前以上游定價頁為準。
7. 跨廠商基準測試(2026-05-25 實測)
單次循序執行。7,284 字元(約 6,900–7,300 token,取決於斷詞器)的穩定系統提示。max_tokens=64。一次未命中呼叫後緊接一次命中呼叫。
自動快取的廠商(無需標記):
| 模型 | 未命中成本 | 命中成本 | 成本 Δ | 未命中總延遲 | 命中總延遲 | 命中 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 token,而命中呼叫為 19 token —— 成本差額混合了快取折扣與補全長度差異。這裡更乾淨的訊號是延遲下降(3.63 → 1.23 s)。
† 串流那一次的成本(其中回報了 cached_tokens);非串流那一次偶爾會對 Gemini 回傳 cached_tokens=null 且成本未下降。閘道針對 Gemini 的中繼資料目前不一致 —— 當 cached_tokens 存在時以它為準。
‡ Gemini *-pro / *-flash 推理模型在較小的 max_tokens 下經常輸出零個內容 token,因此在該預算下 TTFT 沒有意義。若在生產中測量,請把 max_tokens 調大。
§ 見 §6 —— 上游快取確實命中(延遲下降),但閘道的 usage.cost 欄位在這一日期沒有反映 qwen3-max 的折扣。
Anthropic Claude 由顯式標記驅動;其數據放在獨立的表中,因為折扣是透過 cache_control 主動啟用的(模式見 §2)。相同提示,實測快取寫入 vs 快取讀取:
| 模型 | 寫入成本 | 讀取成本 | 讀取折扣 | 命中 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. 上線前檢查清單
在發布一個感知快取的提示之前:
- 穩定內容在前 —— 把系統提示、知識庫、工具 schema 放在
messages頂部。 - 易變內容在後 —— 把使用者輸入、檢索文件、時間戳記放在底部。
system中不放動態變數 —— 目前的時間、使用者 ID、隨機種子都會摧毀你的前綴。- 每次呼叫都記錄
cached_tokens。 如果生產中命中率低於 50%,代表你的前綴其實並不穩定。檢查那些未命中的提示。 - 不要相信單次命中。 TTL 很短;依
hit_rate ∈ [0, 1)來設計,而不是「總會命中」。
9. 感知 TTL 的模式
生產中最常見的失敗模式不是「我忘了啟用快取」 —— 而是「我的命中率只有 12%,因為我的請求實際上沒有落在 TTL 視窗內」。
8.1 工作階段綁定的工作負載(聊天、IDE 助理)
其自然節奏遠低於 TTL。把提示結構組織好,快取會自己保持溫熱 —— 不要額外搞別的工程。
8.2 批次 / Cron 的心跳
如果你在 09:00 跑一個每日報表,在 3 分鐘內突發呼叫模型 50 次,那麼 09:00 的首次快取寫入是浪費的,因為快取隔夜已經冷卻。從 08:55 開始,每隔 TTL/2 用快取前綴傳送一個 1 token 的「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 的成本是輸入 token × 快取費率,對於我們 7K token 前綴在 gpt-5.4-mini 上約為 $0.0026 —— 遠低於讓批次工作在前 50 次真實呼叫上支付完整 prefill 的代價。
8.3 冷儲存文件
對於零星查詢的文件(一整天裡每小時一次),記憶體內快取大部分時間都是冷的。截至本文撰寫時,閘道尚未公開託管的顯式快取建立端點 —— 對於長 TTL 需求,請使用 deepseek-v4-flash(磁碟支撐;實務中能存活小時級間隔),或在閘道之外直接呼叫 Google 原生的 cachedContent API。
10. 閘道究竟帶來了什麼
聲稱閘道「替你做了快取」是不誠實的。快取發生在模型層 —— 閘道只是公開既有的能力。相比直接使用各廠商的原生 SDK,它確實帶來的,是這三點:
- 一個 base_url、一個驗證標頭、所有模型。 切換
model欄位,呼叫形式不變。相同的messages陣列、相同的usage欄位結構。你不必為五個廠商背上五套 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 代理人 —— 一個把工作負載類型對應到最佳模型 + 快取策略的決策矩陣,附成本計算。
常見問題
為什麼對非 OpenAI 的模型也用 OpenAI SDK?
閘道對其代理的每個廠商都使用 OpenAI 的傳輸格式。官方 openai SDK 為你提供具型別的回應、自動重試與串流輔助 —— 沒有理由手寫五個 HTTP 用戶端。
快取對串流回應有效嗎?
有效。最後一個資料區塊中的 usage 物件會回報快取命中數(當你傳入 stream_options={"include_usage": True} 時)。延遲收益在串流上最明顯,因為 TTFT 才是使用者看到的。
對我的工作負載,哪個廠商的快取折扣最大?
依 2026-05 的價格和 70%+ 的命中率,§7 表中最便宜的是 gemini-2.5-flash 與 deepseek-v4-flash。gpt-5.4-mini 在 TTFT 上勝出。要拿到 Claude 文件所述的 90% 快取折扣,需標註最多四個 cache_control 斷點(見 §2)。用你自己的提示跑一遍同樣的基準 —— 那是一天的工作量,而不是數週的遷移。
我什麼時候需要 cache_control 標記?
只有在呼叫 Anthropic Claude 時才需要 —— 見 §2。對於 OpenAI/Gemini/DeepSeek/Qwen,上游會對任何足夠長的前綴自動快取,因此無需標記;該欄位在這些廠商上會被靜默忽略。
這些數據有多新? 於 2026-05-25 在公開閘道上實測。請把它們當作單一資料點 —— 定價與延遲每個發布週期都會變化。
Anthropic Claude 的情況如何?
Claude 透過閘道以顯式 cache_control 標記的方式受支援 —— 使用 anthropic SDK,設定 base_url="https://synthorai.io/"(SDK 會附加 /v1/messages)。OpenAI 相容的 /chat/completions 路徑目前不會傳遞這些標記;針對 Claude 快取,請使用 §2 中展示的 Anthropic 原生路徑。
來源與驗證:所有數據於 2026-05-25 使用 openai SDK 2.38.0 針對 https://synthorai.io/v1 實測。廠商定價頁:Anthropic Prompt Caching · OpenAI Prompt Caching · Google Gemini Context Caching · DeepSeek KV Cache Guide · Alibaba Bailian Context Cache.