打造 Claude Code 的經驗談:Prompt Caching 是關鍵所在

@trq212
英語5 個月前 · 2026年2月19日
2.3M
5.6K
542
166
14.5K

TL;DR

深入了解 Claude Code 如何透過前綴匹配 (prefix matching)、穩定的工具集以及快取安全壓縮 (cache-safe compaction) 來優化效能,進而降低長時間運行的 Agent 會話中的延遲與營運成本。

工程界常說「快取主宰一切」,這個法則同樣適用於 Agent。

像 Claude Code 這類長時間運行的 Agent 產品,之所以能實現,靠的是提示快取——它能讓我們重複利用前一次往返的運算結果,大幅降低延遲和成本。

什麼是提示快取?它如何運作?又該如何從技術上實現?進一步了解 @RLanceMartin 關於提示快取及我們全新自動快取功能的文章。

在 Claude Code 中,我們整個運作框架都建立在提示快取之上。較高的提示快取命中率能降低成本,也有助於我們為訂閱方案提供更寬裕的速率限制;因此我們會監控提示快取命中率,一旦過低便會啟動 SEV 機制。

以下是在大規模優化提示快取時,我們學到的(往往違反直覺的)教訓。

為快取設計提示順序

Thariq - inline image

提示快取的運作原理是前綴匹配——API 會快取從請求開頭到每個 cache_control 斷點之間的所有內容。這意味著內容的排列順序至關重要,你要盡可能讓多個請求共享相同的前綴。

最佳做法是:靜態內容放前面,動態內容放最後。以 Claude Code 為例,順序如下:

  1. 靜態系統提示與工具(全域快取)
  2. Claude.MD(在專案內快取)
  3. 工作階段上下文(在工作階段內快取)
  4. 對話訊息

這樣我們就能最大化共享快取的工作階段數量。

但這個做法出乎意料地脆弱!我們曾因下列原因破壞過這個順序:在靜態系統提示中放入詳細時間戳、非確定性地打亂工具順序定義、更新工具參數(例如 AgentTool 可以呼叫哪些 Agent)等。

利用訊息進行更新

有時提示中的資訊會過時,例如時間變了,或使用者修改了檔案。你可能會想直接更新提示,但這樣會導致快取未命中,對使用者來說可能相當昂貴。

試著考慮是否能在下一輪透過訊息傳入這些資訊。在 Claude Code 中,我們在下一個使用者訊息或工具結果中加入 <system-reminder> 標籤,提供更新後的資訊給模型(例如「現在是星期三」),這樣有助於保留快取。

不要在工作階段中切換模型

提示快取是模型特有的,這使得提示快取的計算變得相當違反直覺。

如果你與 Opus 對話到 10 萬個 token,然後想問一個相當簡單的問題,切換到 Haiku 反而會更昂貴,因為需要為 Haiku 重新建立提示快取。

如果你需要切換模型,最好的方法是透過子 Agent——讓 Opus 準備一條「交接」訊息給另一個模型,告知它需要完成的任務。我們在 Claude Code 的 Explore Agent 中經常這樣做,這些 Agent 使用 Haiku。

不要在工作階段中新增或移除工具

在對話中途變更工具集是最常見的破壞提示快取的方式之一。直覺上,你只應該給模型它當下需要的工具。但由於工具是快取前綴的一部分,新增或移除工具會使整個對話的快取失效。

Plan Mode(規劃模式)——圍繞快取設計功能

Plan Mode 是一個很好的例子,說明如何圍繞快取限制來設計功能。直覺做法是:當使用者進入 Plan Mode 時,切換工具集,只保留唯讀工具。但這會破壞快取。

相反,我們始終在請求中保留所有工具,並將 EnterPlanMode 和 ExitPlanMode 本身也作為工具。當使用者切換到 Plan Mode 時,Agent 會收到一條系統訊息,說明它處於 Plan Mode 以及相關指令——探索程式碼庫、不編輯檔案、完成計劃後呼叫 ExitPlanMode。工具定義從不改變。

這樣做還有一個額外好處:因為 EnterPlanMode 是模型可以自行呼叫的工具,所以當模型偵測到困難問題時,它可以自主進入 Plan Mode,而不破壞快取。

Tool Search(工具搜尋)——延遲載入而非移除

同樣的原則也適用於工具搜尋功能。Claude Code 可能載入數十個 MCP 工具,如果每個請求都包含所有工具,成本會很高。但在對話中途移除它們又會破壞快取。

我們的解決方案是:defer_loading(延遲載入)。我們不移除工具,而是發送輕量的佔位符——僅包含工具名稱,加上 defer_loading: true——當模型需要時,可以透過 ToolSearch 工具來「發現」它們。完整的工具架構只在模型選取時才載入。這樣就能保持快取前綴的穩定:同樣的佔位符始終以相同順序存在。

幸運的是,你可以透過我們的 API 直接使用工具搜尋來簡化這個過程。

分支上下文——壓縮

Thariq - inline image

壓縮(Compaction)是指當上下文視窗耗盡時,我們將目前對話總結,然後以該摘要開始新的工作階段。

出乎意料的是,壓縮在提示快取中存在許多邊際情況,往往違反直覺。

特別是,進行壓縮時,我們需要將整個對話傳送給模型以產生摘要。如果這是一個獨立的 API 呼叫,使用不同的系統提示且沒有工具(簡單的實作方式),那麼主要對話的快取前綴就完全不匹配。你需要為所有輸入 token 支付全額費用,大幅增加使用者的成本。

解決方案——快取安全的 Forking(分支)

當我們執行壓縮時,使用與父對話完全相同的系統提示、使用者上下文、系統上下文和工具定義。我們先附上父對話的對話訊息,然後在末尾附加壓縮提示作為新的使用者訊息。

從 API 的角度來看,這個請求與父對話的最後一個請求幾乎完全相同——相同的前綴、相同的工具、相同的歷史——因此快取前綴得以重複使用。唯一新的 token 只有壓縮提示本身。

不過這也意味著我們需要保留一個「壓縮緩衝區」,以便在上下文視窗中留出足夠空間來容納壓縮訊息和摘要輸出 token。

壓縮雖然棘手,但幸運的是,你不需要自己摸索這些教訓——根據我們從 Claude Code 中學到的經驗,我們直接將壓縮功能內建到 API 中,讓你能在自己的應用程式中套用這些模式。

經驗教訓

  1. 提示快取是前綴匹配。 前綴中任何變更都會使之後的所有內容失效。圍繞這個限制設計你的整個系統。把順序排對,大部分快取就能自動生效。
  2. 使用訊息而非修改系統提示。 你可能會想編輯系統提示來做像是進入 Plan Mode、更新日期等事情,但更好的做法是在對話過程中將這些資訊插入到訊息中。
  3. 不要在工作階段中變更工具或模型。 使用工具來模擬狀態轉換(例如 Plan Mode),而不是切換工具集。使用延遲載入而非移除工具。
  4. 像監控正常運行時間一樣監控快取命中率。 我們對快取中斷發出警報,並將其視為事故。幾個百分點的快取未命中率就可能對成本和延遲產生巨大影響。
  5. 分支操作需要共享父前綴。 如果你需要執行側邊計算(壓縮、摘要、技能執行),使用相同的快取安全參數,以確保能命中父前綴的快取。

Claude Code 從第一天起就以提示快取為核心來建構,如果你正在建構 Agent,也應該這麼做。

一鍵儲存

使用 YouMind AI 深度閱讀爆款文章

保存原文、追問細節、總結觀點,並在一個 AI 工作空間裡把爆款文章沉澱成可複用筆記。

了解 YouMind
寫給創作者

把你的 Markdown 變成乾淨的 𝕏 文章

圖片上傳、表格、程式碼區塊,往 𝕏 上手動重排太痛苦。YouMind 把整篇 Markdown 一鍵轉成乾淨、可直接發佈的 𝕏 文章草稿。

試試 Markdown 轉 𝕏

更多可拆解樣本

近期爆款文章

探索更多爆款文章