cd ../back to blog
$Guide//June 4, 2026//8 min read

提示快取深入解析:把輸入成本砍掉 90%

用 Anthropic 的 cache_control 與 OpenAI 自動快取,把長系統提示的輸入費率降到 10%,並學會驗證命中率、避開讓快取失效的陷阱。

如果你正在送出一段很長的系統提示 — RAG 情境、工具 目錄、代理規則、範例 — 那你很可能每次呼叫都在支付全額的輸入 費用。Anthropic 的提示快取能把已快取部分的費用砍到 原費率的 10%。OpenAI 也以隱含的方式做了同樣的事。 多數團隊都覺得這 30 分鐘的功夫很值得,因為它能可靠地把輸入 成本那一行砍掉 60~90%。

Brievio 把這兩種風格原封不動地轉送過去,對應的是真正的 模型。Anthropic 風格的 cache_control 適用於 Messages API;OpenAI 風格的 自動快取則適用於 Chat Completions API。這篇文章會走過兩者、那些 會悄悄讓快取失效的陷阱,以及該怎麼驗證你的命中率。

對照前後

一個天真的迴圈,把同一段 18K 權杖的系統提示送了十次:

naive.py
# 多數人一開始的寫法:每一次呼叫都得重新為整段提示付費。
import anthropic

client = anthropic.Anthropic(
    api_key="sk-brievio-...",
    base_url="https://api.brievio.com",
)

SYSTEM = open("system-prompt.md").read()        # 18,000 個權杖的規則 + 範例

# 一次工作階段裡有 10 個使用者問題。每次呼叫都送出這 18K 權杖的系統區塊。
for question in questions:
    resp = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=600,
        system=SYSTEM,
        messages=[{"role": "user", "content": question}],
    )

# 每次呼叫的成本(僅輸入):18,000 × $3 / 1M = $0.054
# 10 次呼叫:光是輸入就要 $0.54。

現在把系統區塊標記成可快取 — 只多一個欄位:

cached.py
# 解法:把靜態前綴標記成可快取。第一次呼叫之後,約 5 分鐘內的
# 後續呼叫,對已快取的部分只需支付 10% 的輸入費率。同樣的答案,便宜 89%。
resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=600,
    system=[
        {
            "type": "text",
            "text": SYSTEM,
            "cache_control": {"type": "ephemeral"},  # 標記為可快取
        }
    ],
    messages=[{"role": "user", "content": question}],
)

# 第一次呼叫(寫入快取):  18,000 × $3   / 1M = $0.054
# 第 2~10 次(命中快取):  18,000 × $0.30 / 1M = $0.0054 每次
# 合計:$0.054 + 9 × $0.0054 = $0.103 (原本 $0.54 — 省了 81%)

你剛剛在這次工作階段上省下了 81% 的輸入成本。第一次呼叫其實比 天真版本稍微貴一點(約 1.25 倍輸入費率以寫入 快取)。第 2 到第 10 次呼叫只需支付 10% 的費率。損益平衡點在 第 2 次呼叫 — 到了第 3 次你就已經划算了。到第 10 次,那已是 壓倒性的勝利。

OpenAI 風格:什麼都不用做

如果你用的是 OpenAI SDK,Chat Completions 會自動快取 任何超過 1,024 個權杖之提示的前綴。沒有旗標、沒有設定。Brievio 背後的同一個模型,無論你走的是 Anthropic 還是 OpenAI 路線,都會 在以下情況拿到折扣:

openai_style.py
# OpenAI Chat Completions 風格 — 對 ≥1024 個權杖的提示會自動快取。
# 沒有旗標要設。「usage」物件會告訴你哪些被快取了。
from openai import OpenAI

client = OpenAI(
    api_key="sk-brievio-...",
    base_url="https://api.brievio.com/v1",
)

resp = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[
        {"role": "system", "content": LONG_SYSTEM_PROMPT},  # >1024 個權杖
        {"role": "user", "content": "Latest question…"},
    ],
)

# 在回應裡:
#   resp.usage.prompt_tokens_details.cached_tokens  →  17,800
#   resp.usage.prompt_tokens                        →  18,200
# 17.8K/18.2K = 98% 的輸入來自快取。帳單會自動反映這一點。

讀取 usage.prompt_tokens_details.cached_tokens 就能看到 有多少是從快取提供的。固定前綴越大 = 省得越多。經驗法則是: 如果你的系統提示比你的變動使用者內容還短,快取就發揮不了 多少作用。請把提示重新塑形,讓靜態部分既大又放在最前面。

多層快取 — 最多 4 個中斷點

對於某些層級變動得比其他層級快的代理迴圈,請設定多個 cache_control 中斷點。每一個都是到該點為止 所有內容的快照:

breakpoints.py
# Anthropic 每個請求最多支援 4 個快取中斷點 — 善用它們,
# 即使後面的層級有變動,也能讓快取保持熱度。
client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=600,
    system=[
        {"type": "text",
         "text": ROLE_AND_RULES,                      # 約 3,000 個權杖
         "cache_control": {"type": "ephemeral"}},     # 中斷點 1
        {"type": "text",
         "text": LARGE_KNOWLEDGE_BASE,                # 約 15,000 個權杖,很少變動
         "cache_control": {"type": "ephemeral"}},     # 中斷點 2
    ],
    messages=[
        {"role": "user",
         "content": [
             {"type": "text",
              "text": CONVERSATION_HISTORY,           # 每一輪都在增長
              "cache_control": {"type": "ephemeral"}}, # 中斷點 3
             {"type": "text", "text": new_question},
         ]},
    ],
)

# 當 CONVERSATION_HISTORY 變動時,中斷點 1+2 仍會命中快取。
# 只有中斷點 3 + 新問題需要支付全額輸入費率。

快取鍵是整段前綴。在位置 N 加進一個權杖,位於 N 或其後的 每一個中斷點都會失效。順序很重要: 最穩定的內容放最前面。規則層應該很少變動;知識庫 每週更新;對話則每一輪都在增長。

會悄悄破壞快取的常見做法

  • 把目前的日期或 request_id 放進提示。 每次呼叫都是一段新前綴,快取命中率是 0%。請對你的提示 輸入做雜湊,並跨呼叫做比較。
  • 不具確定性的系統提示組裝方式。如果你 從一個 dict 來建構系統提示,在某些 Python 版本中 dict 的 迭代順序是會有影響的。請明確地對鍵排序。
  • 快取生命週期約為 5 分鐘。稀疏的流量 模式(每 10 分鐘才一次呼叫)會得到零命中。要嘛把呼叫 批次化,要嘛接受這個損失。
  • 1,024 個權杖的最低門檻。低於 1K 權杖, OpenAI 風格的快取不會啟動。請把零碎的靜態片段合併成 一段較長的前綴。
  • 工具/函式定義是前綴的一部分。 往目錄裡新增一個工具,會讓所有人的快取都失效。請保持 工具目錄穩定;並為它做版本控管。

驗證命中率

看不見的快取不是工程 — 那只是在碰運氣。請在每一次呼叫上 記錄 usage

observe.py
# 永遠要讀取 usage。如果你預期命中快取,cached_tokens 卻是 0,
# 表示哪裡出了問題 — 通常是前綴不具確定性。
resp = client.messages.create(...)
u = resp.usage
print({
    "input_uncached":  u.input_tokens,
    "input_cache_read": u.cache_read_input_tokens,
    "input_cache_write": u.cache_creation_input_tokens,
    "output": u.output_tokens,
})

# 常見的陷阱:把今天的日期或 request_id 放進系統提示,
# 會悄悄讓快取失效。請對你的輸入做雜湊;並驗證第二次發送相同呼叫時,
# cache_read_input_tokens 不為零。

在 Brievio 儀表板裡, 用量頁面會逐模型、逐日顯示 快取的拆分。如果你看到 cache_read_input_tokens 佔 總輸入的百分比逐漸增長,代表快取正在運作。如果它一直卡在 0 或大幅波動,請逐項走過上面那份陷阱清單。

在 Brievio 上實際要花多少

每個模型的快取費率都公布在 定價頁面上:

  • Anthropic 模型:快取讀取是輸入費率的 10%。快取寫入按輸入費率計費 — 沒有上游附加費。
  • OpenAI/Gemini 模型:快取讀取是輸入費率 的 20%(供應商公布的比例)。
  • 所有快取定價都反映 Brievio 的牌價 — 大約比 供應商的官方費率低 15%。所以在 Brievio 上一次 Sonnet 4.6 的快取讀取是 $3 × 0.95 × 0.10 = $0.285 per 1M tokens。比 未快取的輸入費率便宜約 10 倍。

什麼時候快取不是答案

有幾種情況,這份功夫不值得做:

  • 短提示(總計 <1K 權杖)。額外開銷會 蓋過效益;就別費這個事了。
  • 一次性任務,沒有重複流量。第一次呼叫 會稍微貴一點 — 快取只在第 2 次以後的呼叫才回本。
  • 高輸出、低輸入的任務(創意寫作、 程式碼生成)。輸入本來就只佔帳單的一小部分。請改為 把重心放在輸出預算上限上。

至於其他所有情況 — RAG 聊天機器人、有固定工具目錄的代理、 在靜態評分標準上運行的分類器、few-shot 一致的結構化抽取流水線 — 快取都是你能在一個下午內就交付、投資報酬率最高的最佳化。 把它和 我們成本最佳化指南裡的另外四項技巧 搭配起來,在輸出品質完全不必妥協的前提下,降低 70% 的成本 是很實際的。

已經在用 Brievio 了嗎?打開 /app/usage,去看看你最大那個 模型的快取欄位。如果它是零,那你就是把錢留在桌上沒拿。 完整指南: /docs/caching