LLM 提示快取 #3:可執行的 Python 教學

目錄
  1. 0. 前置設定
  2. 1. 感知快取的呼叫(每個廠商都一樣)
  3. 2. Anthropic Claude —— 顯式 cache_control 標記
  4. 3. OpenAI GPT-5.x —— 自動快取
  5. 4. Google Gemini —— 隱式快取
  6. 5. DeepSeek-v4-flash —— 磁碟支撐的自動快取
  7. 6. 阿里 Qwen —— 回報命中,折扣不穩定
  8. 7. 跨廠商基準測試(2026-05-25 實測)
  9. 8. 上線前檢查清單
  10. 9. 感知 TTL 的模式
  11. 8.1 工作階段綁定的工作負載(聊天、IDE 助理)
  12. 8.2 批次 / Cron 的心跳
  13. 8.3 冷儲存文件
  14. 10. 閘道究竟帶來了什麼
  15. 常見問題

太長不看 — 一套 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-5claude-sonnet-4-5 / 4-6claude-opus-4-5 / 4-6 / 4-7gpt-5.4-minigpt-5.4-nanogpt-5.2gpt-5.5-progemini-2.5-flashgemini-2.5-progemini-3.1-pro-previewdeepseek-v4-flashqwen3-maxqwen3.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)—— 無需在本地維護依廠商劃分的費率表。

由架構推導而來、適用於所有廠商的兩條規則:

  1. 穩定內容在前,易變內容在後。 前綴從第 0 個 token 開始比對;開頭處哪怕一個位元組的改動都會使整個前綴失效。
  2. 不要把動態資料放進系統提示。 目前的時間戳記、工作階段 ID、請求 UUID 都會破壞快取。

下面的內容只是同一模式在各廠商上的範例而已。


2. Anthropic Claude —— 顯式 cache_control 標記

Claude 屬於顯式標記家族 —— Anthropic 的 API 不會自動快取。要取得快取命中,需要在 systemmessages 陣列中標註最多四個 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-5claude-sonnet-4-5 / 4-6claude-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-mini0.73 sgpt-5.4-nano1.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 s1.48 s1.00 s5,888 / 6,887 (85%)
gpt-5.4-mini$0.00267$0.00257−4%*3.63 s1.23 s0.73 s6,400 / 6,887 (93%)
gemini-2.5-flash$0.00198$0.00024†−88%2.49 s1.37 sn/a‡7,140 / 7,322 (97%)
gemini-2.5-pro$0.00824$0.00205†−75%2.99 s1.76 sn/a‡6,120 / 7,328 (84%)
deepseek-v4-flash$0.00091$0.00023−74%4.02 s3.71 s2.93 s6,784 / 7,101 (96%)
qwen3-max$0.00553$0.00549−1%§4.80 s2.37 s1.53 s7,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. 上線前檢查清單

在發布一個感知快取的提示之前:

  1. 穩定內容在前 —— 把系統提示、知識庫、工具 schema 放在 messages 頂部。
  2. 易變內容在後 —— 把使用者輸入、檢索文件、時間戳記放在底部。
  3. system 中不放動態變數 —— 目前的時間、使用者 ID、隨機種子都會摧毀你的前綴。
  4. 每次呼叫都記錄 cached_tokens 如果生產中命中率低於 50%,代表你的前綴其實並不穩定。檢查那些未命中的提示。
  5. 不要相信單次命中。 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,它確實帶來的,是這三點:

  1. 一個 base_url、一個驗證標頭、所有模型。 切換 model 欄位,呼叫形式不變。相同的 messages 陣列、相同的 usage 欄位結構。你不必為五個廠商背上五套 SDK。
  2. 每次呼叫的 usage.cost(USD)。 閘道用目前上游費率計算美元成本,並將其包含在每個回應中。你不必在程式碼裡維護定價矩陣,也不必訂閱各廠商的價格變更通知。
  3. 統一的 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-flashdeepseek-v4-flashgpt-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.

← 返回部落格