目錄
2 分鐘閱讀

將 Claude Code API 成本削減九成的 Cache 設計思路

生產環境的 cache 突然失效,那一個小時的 API 費用比過去三日加起來還要高。偏偏同一晚,Anthropic 工程師發文解釋了箇中原因。

昨日要處理緊急的生產環境問題,做到一半,prompt cache 突然失效。就那一個小時產生的 API 費用,比之前三日加起來還要多。

時機真的很諷刺。同一個晚上,在 Anthropic 負責開發 Claude Code 的 Thariq,以及同樣來自 Anthropic 的 Lance Martin,先後發文談及 prompt caching 的設計。讀完他們的說明,我才明白自己的 cache 之所以脆弱,根本是設計上的問題,而非偶然。

以下是我從兩篇文章整理出來的重點,配合自己剛親歷的生產事故,過濾了一遍。

Prefix 匹配,順序就是一切

Anthropic API 的 prompt caching 原理是從請求的開頭逐個 token 作匹配。只要有一個字符與已快取的版本不同,之後的內容全部視為 cache miss,沒有局部匹配,也不能跳過。

Claude Code 團隊把 prompt 的排列順序當成基礎設施來處理。靜態的 system prompt 放最前,然後是 CLAUDE.md,再來是 session context,對話訊息放最後,因為它每個回合都會改變。這個排列確保昂貴而穩定的 prefix 能夠被快取,並在整個 session 的每次請求中重複使用。

已快取的 token 只需支付正常輸入 token 費用的一成。這個差距解釋了為何 cache 失效感覺像是費用暴漲十倍。

我的錯誤在於把時間戳記嵌入 system prompt。每次請求都會產生新的時間戳記,意味著最開頭的 token 每次都不一樣,下游的內容完全無法被快取。一行放錯位置的 debug log,就讓我每次請求都要為超過十萬個 token 支付全額費用。

Claude Code 團隊亦提到,tool definition 的序列化順序不固定也會導致 cache miss。假如 tool 在不同請求之間的序列化順序有所不同,即使 tool 本身沒有任何改動,cache 也會在那個位置斷掉。

透過訊息傳遞更新,而非修改 system prompt

當 session 進行中有 context 發生變化,例如某個檔案被修改、時間更新、模式切換,直覺反應是去改 system prompt。但千萬不要這樣做。每次修改 system prompt 都會令整個已快取的 prefix 失效。

Claude Code 的做法是在第一次請求之後就不再動 system prompt。有變更的 context 會放進下一條用戶訊息,用 system-reminder 標籤包起來。模型讀取的方式一樣,但 cache prefix 維持完整。

Plan Mode 是個好例子。切換到 Plan Mode 本來可以意味著要替換 tool definition,那會破壞 cache。Claude Code 改為將其實作成一個 tool call (EnterPlanMode),讓模型自行調用。tool 集合從不改變。當模型判斷問題較為複雜,就能自行進入 Plan Mode,完全不需要修改 system prompt。

同樣的邏輯也適用於切換模型。在對話中途換模型會令 cache 完全失效。Claude Code 的做法是把不同模型當作 subagent,放在獨立的 context 中運行,讓主對話的 cache 維持完整。

隱藏 tool 而非移除它

MCP server 可以載入幾十個 tool。把所有 tool 都加進每次請求既昂貴,但在請求之間移除 tool 又會破壞 cache,因為 tool definition 是已快取 prefix 的一部分。

Claude Code 團隊的解決方案是 defer_loading。他們不把完整的 tool schema 放進去,而是插入輕量的 stub,只包含 tool 名稱和一個 defer_loading: true 標記。這些 stub 每次都以相同順序出現,令 cache prefix 保持一致。當模型真正需要某個 tool 的完整 schema 時,才調用 ToolSearch tool 按需載入。

這個模式在 Anthropic API 現在已經可以使用。你可以在自己的 agent 中實作同樣的 stub 加搜尋方式。

Manus 的 peakji 說過,cache hit rate 是生產環境 agent 最關鍵的單一指標。經歷昨日之後,我完全認同。

Context 壓縮暗藏的 cache 陷阱

當對話填滿了 context window,就需要壓縮:把歷史記錄摘要,然後以精簡後的形式繼續。最直接的做法是用一個摘要 prompt 調用 API。但如果那次摘要調用使用了不同的 system prompt 或不同的 tool definition,就無法匹配現有的 cache。你會在費用最高的時刻,用全額費用處理超過十萬個 token 的整段對話,完全沒有任何 cache 幫助。

Claude Code 的解決方法是在壓縮調用中重用主對話完全相同的 system prompt 和 tool definition。唯一改變的是最後一條用戶訊息,換成壓縮指令。主對話的 cache prefix 仍然匹配,所以只需為新訊息和摘要輸出支付全額費用。

Anthropic 後來已將這個模式整合進 API,作為 compaction 功能推出。他們亦發布了自動快取功能,只需在請求 body 中設定一次 cache_control,便能自動處理 cache breakpoint。

把 cache hit rate 當成營運指標

Claude Code 團隊監控 cache hit rate 的方式,就像運維團隊監控系統可用性一樣。數字一旦下跌,就當成事故處理。

這個思維框架改變了我對 prompt 設計的看法。每次修改 system prompt、每次調整 tool 順序、每次在 session 中途換模型,都是潛在的事故。命中 cache 的 token 成本最低,而昨日我切切實實地體驗到了另一種選擇有多貴。

訂閱通訊

獲取關於我最新項目、文章同埋 AI 和 Web 開發實驗嘅更新。