# 策展 · X (Twitter) 🔥

> 📖 本站完整內容索引（documentation index）：[llms.txt](/llms.txt)

> 作者：Avi Chawla (@_avichawla) · 平台：X (Twitter) · 日期：2026-04-18

> 原始來源：https://x.com/_avichawla/status/2044670188998803855

## 中文摘要

# LLM 中的 Prompt Caching：清晰解析

這是一份關於 Claude 如何達成 92% 快取命中率的案例研究

---

每當 AI Agent 採取一個步驟時，它都會將整個對話歷史紀錄傳送回 LLM。

這包含了系統指令、工具定義，以及它在三個回合前就已經處理過的專案背景資訊。所有這些內容在每一個回合中都會被重新讀取、重新處理並重新計費。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447377-iaHGAbt3ObkAAd1p4jpg.jpg)

對於長時間運行的 Agent 工作流程而言，這種冗餘的運算通常是你整個 AI 基礎設施中最昂貴的項目。

一個包含 20,000 個 token 的系統提示詞（System Prompt）在運行 50 個回合後，意味著有 100 萬個 token 的冗餘運算以全價計費，卻沒有產生任何新的價值。而且這種成本會隨著每一位使用者和每一次對話而疊加。

解決方案就是 Prompt Caching（提示詞快取）。但要妥善運用它，你需要了解底層實際發生了什麼。

## 靜態與動態 Context

在優化提示詞之前，你需要先了解哪些部分會變動，哪些不會。

每個 Agent 的請求都包含兩個截然不同的部分：

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447341-iaHGAbx5qawAAzLuXjpg.jpg)

- **靜態前綴（Static prefix）**：在各個回合中保持不變的部分，例如系統指令、工具定義、專案背景資訊和行為準則。

- **動態後綴（Dynamic suffix）**：隨著每個回合不斷增長的部分，例如使用者訊息、助理回應、工具輸出和終端觀察結果。

這種拆分方式使得 Prompt Caching 成為可能。基礎設施會儲存靜態前綴的數學狀態，以便後續共享完全相同前綴的請求可以完全跳過運算，直接從記憶中讀取。

一旦你理解了這一點，本文中提到的每一項架構決策都會變得顯而易見。

---

## KV Cache 是如何運作的？

要理解為什麼快取如此有效，你需要知道 Transformer 在處理你的提示詞時實際做了什麼。

每個 LLM 推論請求都有兩個階段：

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447367-iaHGAcKJha0AAh1G1jpg.jpg)

- **預填充階段（Prefill phase）**：處理整個輸入提示詞。它會對 Context 中的所有 token 執行密集的矩陣乘法，以建立模型的內部表示。這個階段受限於運算能力且成本高昂。

- **解碼階段（Decode phase）**：一次生成一個 token。每個新生成的 token 都會被加入序列中，模型再預測下一個 token。這個階段受限於記憶，因為它主要是在讀取歷史狀態，而不是進行繁重的運算。

在預填充階段，Transformer 會為每個 token 計算三個向量：Query（查詢）、Key（鍵）和 Value（值）。注意力機制（Attention mechanism）利用這些向量來決定每個 token 與其他所有 token 之間的關聯。任何給定 token 的 Key 和 Value 向量僅取決於它之前的 token，一旦計算完成，它們就永遠不會改變。

如果沒有快取，這些 Key 和 Value 張量（Tensors）會在每次請求後被丟棄，下一次請求時又會從頭開始重新計算。對於一個 20,000 個 token 的前綴來說，這意味著有 20,000 個 token 的注意力運算本來是不需要重複進行的。

KV Cache 透過將這些張量持久化在推論伺服器上來解決這個問題，並透過 token 序列的加密雜湊值（Cryptographic hash）進行索引。當一個帶有相同前綴的新請求進來時，雜湊值匹配成功，張量會直接從記憶中載入，這些 token 的預填充運算便完全被跳過。

這將運算複雜度從每個生成 token 的 O(n²) 降低到了 O(n)。對於重複 50 個回合的 20,000 個 token 前綴來說，這是一個巨大的縮減。

## 經濟效益

定價結構使得這項架構決策變得至關重要。

快取讀取（Cache reads）的成本是基礎輸入價格的 0.1 倍，這意味著每個快取的 token 都有 90% 的折扣。快取寫入（Cache writes）的成本則是 1.25 倍，即儲存 KV 張量需要支付 25% 的溢價。延長一小時的快取則需要 2.0 倍的成本。

以下是 Anthropic 的 Claude 模型在價格上的表現：

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447351-iaHGAcWsnbMAAjZ3Rpng.png)

這套數學邏輯只有在快取命中率保持在高水準時才成立。目前生產環境中最好的例子就是 Claude Code。

## 使用 Claude Code 進行 30 分鐘的程式開發

Claude Code 的設計完全圍繞著一個目標：保持快取處於熱門狀態（Keep the cache hot）。

從計費的角度來看，一次 30 分鐘的程式開發過程如下：

第 0 分鐘：Claude Code 載入其系統提示詞、工具定義以及專案的 `CLAUDE.md` 檔案。這個負載超過了 20,000 個 token，由於每個 token 都是新的，這是整個過程中成本最高的一刻。但你只需要支付一次這筆費用。

第 1 到 5 分鐘：你開始給出指令，Claude Code 指派其 Explore Subagent 來瀏覽程式庫、開啟檔案並執行 grep 指令。所有這些動作都會附加到動態後綴中。但現在那 20,000 個 token 的靜態前綴是從快取中讀取的，價格為每百萬 token $0.30，而不是 $3.00。

第 6 到 15 分鐘：Plan Subagent 接收到的是摘要後的簡報，而不是原始結果，因為傳遞原始輸出會不必要地增加動態後綴的負擔。它產生了一個實作計畫，你批准後，Claude Code 開始進行變更。每個回合都從快取中讀取靜態前綴，命中率攀升至 90% 以上，且每次存取都會重置 TTL（存活時間）以保持快取熱度。

第 16 到 25 分鐘：你要求變更，這意味著更多的工具呼叫、更多的終端輸出，以及更多累積在動態後綴中的 Context。到目前為止，該對話已經處理了數十萬個 token，但每一個回合都從快取中讀取了那 20,000 個 token 的基礎內容。

第 28 分鐘：你在終端機執行 `/cost`。如果沒有快取，以 Sonnet 4.5 的費率計算 200 萬個 token 將花費 $6.00。而在快取效率達到 92% 的情況下，有 184 萬個 token 是透過快取讀取的，總成本降至 $1.15。這意味著單一任務的成本降低了 81%。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447400-iaHGAcY0MbMAA0wYNjpg.jpg)

這就是熱門快取的樣子。你只需要為靜態基礎內容支付一次費用，之後就可以免費讀取它。只有動態尾部（Dynamic tail）的部分才會被計費。

## 基於雜湊（Hash-based）快取的脆弱性

關於 Prompt Caching，最反直覺的一點是：

「1 + 2 = 3」可以運作，但「2 + 1」會導致快取未命中（Cache miss）。

基礎設施會對從開頭開始的完整 token 序列進行雜湊處理。如果該序列中的任何內容發生變化，哪怕只是兩個元素的順序改變，雜湊值就會改變，整個前綴就會以全價重新計算。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447404-iaHGAcaq1bwAAbUQ5jpg.jpg)

這不是一個微小的實作細節，而是 Claude Code 中每一項工程決策所圍繞的核心限制。

以下是生產環境中導致快取失效的真實案例：

- 注入到系統提示詞中的時間戳記（Timestamp）導致每次請求都產生唯一的雜湊值。

- JSON 序列化器在不同請求之間對工具 Schema 的鍵進行了不同的排序，導致前綴失效。

- 一個在對話中途更新了參數的 AgentTool 抹除了整個 20,000 個 token 的快取。

由此得出三條規則：

1. **不要在對話期間修改工具**。工具定義是快取前綴的一部分，因此新增或移除工具會導致後續所有內容失效。

1. **永遠不要在中途切換模型**。快取是針對特定模型的，這意味著在中途切換到更便宜的模型需要從頭開始重建整個快取。

1. **永遠不要為了更新狀態而變更前綴**。與其編輯系統提示詞，不如在下一個使用者訊息中附加一個提醒標籤，這樣前綴就能保持不變。

## 將此應用於你自己的 Agent

無論你是使用 Claude Code 還是從頭開始建構自己的 Agent，同樣的規則都適用。

請依照以下順序建構你的提示詞：

1. **系統指令和行為準則放在最上方**。不要在中途變更它們。

1. **預先載入所有工具定義**。不要新增或移除它們。

1. **接著是檢索到的 Context 和參考文件**。在對話期間保持它們穩定。

1. **對話歷史和工具輸出放在最下方**。這是你的動態後綴。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447408-iaHGAccolagAAztC1jpg.jpg)

在 Anthropic API 上啟用自動快取後，快取斷點會隨著對話的增長自動推進。如果沒有自動快取，你需要手動追蹤 token 的邊界，而錯誤的邊界意味著完全錯失快取。

當你接近 Context 上限需要進行 Context 壓縮時，請使用「快取安全的分叉」（Cache-safe forking）。保持相同的系統提示詞、工具和對話歷史，然後將壓縮指令作為新訊息附加在後面。這樣快取的前綴會被重複使用，唯一會被計費的新 token 只有壓縮指令本身。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1776543447373-iaHGAcefoa0AAq71ijpg.jpg)

要驗證你的快取是否正常運作，請監控每次 API 回應中的這三個欄位：

- `cache_creation_input_tokens`：寫入快取的 token 數量。

- `cache_read_input_tokens`：從快取中讀取的 token 數量。

- `input_tokens`：未經快取處理的 token 數量。

你的快取效率計算公式為：`cache_read_input_tokens / (cache_read_input_tokens + cache_creation_input_tokens)`。請像追蹤系統正常運行時間（Uptime）一樣追蹤這個指標。

## 重點總結

Prompt Caching 不是一個你可以隨意開關的功能，而是一種你需要圍繞它進行設計的架構準則。

核心概念很簡單：建構你的提示詞，讓靜態內容位於上方，動態內容在下方增長。基礎設施會對前綴進行雜湊處理，儲存 KV 張量，並為你隨後的每次讀取提供 90% 的折扣。

但準則在於細節。不要將時間戳記注入系統提示詞中，不要打亂工具定義，不要在中途切換模型，也不要變更快取斷點之前的任何內容。

Claude Code 展示了這在大規模應用下的效果：92% 的快取命中率和 81% 的成本降低。如果你正在建構 Agent 卻沒有圍繞 Prompt Caching 進行設計，那麼你等於放棄了大部分的利潤空間。

---

以上就是本次分享！

如果你喜歡這篇教學：

找到我 → @_avichawla

我每天都會分享關於 DS、ML、LLM 和 RAG 的教學與見解。

## 標籤

LLM, 教學資源, Agent, Anthropic, Claude
