Applied AI School
v0 · 規劃中
Anthropic

Claude prompt caching 教學:長對話省錢的關鍵

把長 system prompt、tool schema、文件部分快取起來——首次寫入貴 1.25 倍,命中讀取只要 0.1 倍。長對話省錢的關鍵手法。

TL;DR

  • Cache 寫入比正常 input 貴一點點(1.25×)、命中讀取便宜十倍0.1×),算盤要打對才會賺
  • cache_control: {"type": "ephemeral"} 標記 break point,最多 4 個;只快取「break point 以前」的內容
  • TTL 預設 5 分鐘、可延長到 1 小時;最小可快取單位約 1024 tokens(Sonnet/Opus),太短不會被快取

一個情境:對同一份 100 頁 PDF 反覆問問題

你做了一個內部工具,user 上傳一份 100 頁的合約 PDF,然後一直問「這份合約的違約金條款?」「保密期限多長?」「有沒有自動續約?」⋯⋯

每問一題,你都要把 整份 PDF + system prompt + 對話歷史 重傳一次。100 頁 PDF 約 30K input tokens——問 10 題就燒 300K input tokens,每次還得等 Claude 重新做一遍 tokenize、embed、attention 那一整套前處理。

Prompt caching 就是為了這種場景:第一次處理完之後把計算結果存起來,後面的 request 如果前綴 identical,就跳過重算直接讀 cache

為什麼會有這個 feature

每次 Claude 處理 input 都要做一大堆事:tokenize、生 embedding、跑 attention 把 context 處理完,然後才開始生 output。沒 cache 的時候,這些計算結果回完訊息就丟掉。下一個 request 即使前面 90% 內容一樣,也得從頭再做一遍。

Cache 把這些「前處理結果」存到一個臨時 store。下次同樣前綴進來,直接撈出來用,省時間也省錢

價格怎麼算

操作相對於 base input price
Cache 寫入(首次處理 + 寫到 cache)1.25×
Cache 讀取(命中後重用)0.1×
正常 input(沒開 cache)1.0×

直覺判讀:

  • 一段內容只用一次 → 沒必要開 cache,反而貴 25%
  • 一段內容會重用 ≥ 2 次 → 開 cache 開始划算
  • 一段內容會重用 10 次以上 → 大省(從 10× 變成 0.1× × 10 + 1.25× = 2.25×,等於原本的 22.5%)

怎麼開:cache breakpoint

Cache 不是自動開的——你要手動標一個 break point,告訴 API「這之前的內容我要 cache」。

要用「長手寫法」的 content block(不能用 string shorthand,因為 string 沒地方放 cache_control):

# system prompt 寫成 list of blocks,最後一塊掛 cache_control
system = [
    {
        "type": "text",
        "text": LONG_SYSTEM_PROMPT,  # 6K tokens 的編輯助理 system
        "cache_control": {"type": "ephemeral"},
    }
]

res = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=system,
    messages=messages,
)

第一次跑:response 的 usage.cache_creation_input_tokens 會是 system prompt 的 token 數,代表寫入成功。第二次跑(system 一字不差):usage.cache_read_input_tokens 會是同一個數字——命中。

4 個 break point 怎麼配置

Claude 處理 request 時內部順序是固定的:tools → system → messages。Break point 沿著這個順序放,break point 以前的所有東西都會被 cache。你最多能放 4 個。

Prompt cache break points 配置示意圖——token bar 從左到右依序是 tools schemas、system prompt、對話歷史、新訊息;BP1 BP2 BP3 三個 break point 沿著順序放,每個 BP 會 cache 從頭到該點的整段前綴
  • BP1 蓋住 tool schemas(很少改)
  • BP2 蓋住 tools + system(system 也很少改)
  • BP3 蓋住 tools + system + 前段對話(這段的「前段」會逐步加長)

只要前面內容字面上 identical,每段都各自命中。改了哪段,後面所有 cache 全部失效,因為 cache 是「前綴匹配」。

Lookback:每個 breakpoint 只往回看 20 個 block

寫入時要前綴 identical 才命中——但 API 真正去比對的範圍是 breakpoint 往前數 20 個 content block。對話超過 20 個 block 後,更早的內容就算字面 identical 也認不出來。

對 multi-turn 影響特別大:累積到第 11 輪(user / assistant 交替已經 22 個 block)只放一個 breakpoint,前面內容就會落在窗外。解法是多放幾個 breakpoint——例如每 4-5 輪追加一個——讓窗口跟著對話往後滾。

命中規則:identical to the byte

cache_control 的命中極度敏感——多一個空格、字母大小寫不同、JSON key 順序變了都會 miss。

# 第一次
system = [{"type": "text", "text": "You are a helpful assistant.",
           "cache_control": {"type": "ephemeral"}}]
# → cache write

# 第二次:多一個 "please",整段 cache 失效
system = [{"type": "text", "text": "You are a helpful assistant. Please.",
           "cache_control": {"type": "ephemeral"}}]
# → cache miss,從頭再寫一次(被收 1.25× 寫入費)

實作建議:把要 cache 的部分當常數,不要動態組字串塞進去。debug 變數放在 break point 之後

還有哪些東西會讓 cache 失效

字面內容之外,request 層級的開關也會 invalidate 上游的 cache。production「prompt 沒改怎麼一直 miss」的真兇常常在這:

你改了什麼toolssystemmessages
Tool 定義
web_search / citations 開關
Fast mode(speed setting)
tool_choice
Messages 裡 image 增減

✓ 表示該層 cache 還活著、✘ 表示失效。模式很清楚:哪一層被動到,那層加下游全部一起沖掉

所以監測 cache_read_input_tokens / cache_creation_input_tokens 的命中率比對 prompt 字串是不是 identical 重要——程式碼明明沒動但命中率掉了,通常是某個 request 多帶了一張 image、或某次調用切了 tool_choice

最小可 cache 大小

太短的內容不會被 cache(避免 cache 抖動),門檻依模型版本不同

模型最小 cacheable tokens
Opus 4.7 / 4.6 / 4.5、Haiku 4.54096
Sonnet 4.6、Haiku 3.52048
Sonnet 4.5 / 4、Opus 4.1 / 4、Sonnet 3.71024

加總是「break point 以前的全部 token」,不是單個 block。例如用 Sonnet 4.6(門檻 2048)、system 800 tokens + tools 500 tokens = 1300 < 2048,標 cache_control 也不會生效——你不會被收寫入費,但也沒省到,而且 API 不會回錯誤。永遠用 cache_creation_input_tokens / cache_read_input_tokens 兩個欄位驗證。

TTL:5 分鐘 vs 1 小時

預設 cache 活 5 分鐘——這刻意設短,假設你是「user 連續問同一份文件」這類 burst 場景。

需要更長可以設 1 小時版(cache_control: {"type": "ephemeral", "ttl": "1h"},可用性視帳號等級)。1 小時版寫入費 base input(5 分鐘版 1.25×),讀取一樣 0.1×。適合「同一份 system prompt 服務一整個工作天」這種連續使用。

跟 multi-turn 的搭配

Multi-turn 那一篇 提過:API stateless,每輪都重傳整段歷史,token 線性成長。Prompt caching 就是這個問題的主要解藥:把舊對話 cache 起來,只付 0.1× 的讀取費,新一輪只算最新那段 user message。

# turn 5:把前 4 輪 cache 起來
messages = [
    {"role": "user", "content": [
        {"type": "text", "text": prior_turns_text,
         "cache_control": {"type": "ephemeral"}}
    ]},
    {"role": "assistant", "content": "..."},
    {"role": "user", "content": "新問題"},  # ← 這段不 cache
]

什麼時候不要 cache

場景為什麼不適合
每次 input 內容都不一樣(一次性 prompt)永遠 miss,反而貴 25%
內容 < 1024 tokens達不到最小門檻,標了沒用
Burst 之間隔超過 1 小時過期就失效,重寫一次又一次
內容含時間戳、user id 變動字段在前面每次都不 identical

接下來

下一篇看 extended thinking——讓 Claude 在生 visible response 之前先輸出一段 thinking block。Token 多但答案更穩,難題、debug、長 reasoning 用得到。