作者注:Claude 提示詞緩存命中率突然掉到 0,或者賬單一直降不下來,可以用 diagnostics 三步找到前綴分叉的位置,再結合 usage 判斷緩存是否真正命中。本文也會說明走 API易 中轉時怎麼自查。(如果你有這個問題,可以在看完這篇文章後把這篇文章發給你的 Agent,讓他去排查)
緩存沒命中不是玄學,API 會告訴你前綴從哪一段開始分叉。你只需要把上一輪響應的 id 傳回去,就能看到第一個不一致的地方落在 model、system、tools 還是 messages。
這不是一篇功能發佈解讀。本文寫給已經在用 Claude 提示詞緩存、但命中率突然歸零或賬單居高不下的開發者,所有排查步驟都會寫清楚每一步會看到什麼。
核心價值:讀完本文,你能在三輪請求之內定位緩存失效的原因。你也能分清 diagnostics 和 usage 各自說明什麼,並知道走中轉時用哪兩個字段互相比對。

Claude 緩存診斷 diagnostics 核心要點
先用一句話說清它是什麼:把上一輪響應的 id 傳進來,API 會對比兩次請求,指出第一個分叉點落在 model、system、tools 還是 messages。以前緩存悄悄失效時,你只能看到 usage.cache_read_input_tokens 變成 0,卻不知道是哪一段變了。
| 要點 | 說明 | 對你的價值 |
|---|---|---|
| 開關 | 請求體頂層帶 diagnostics 對象纔會存指紋 |
不用改業務邏輯,加一個字段即可 |
| 對比方式 | previous_message_id 傳上一輪響應 id |
直接定位第一個分叉段 |
| 結論字段 | cache_miss_reason 給出六種類型之一 |
每種類型都有明確的修復位置 |
| 配合指標 | 需要和 usage.cache_read_input_tokens 一起看 |
避免把「沒分歧」誤判成「沒生效」 |
| 可用範圍 | 只有官方 Claude API 提供 | 走其他通道需要換用 usage 自檢 |
Claude 緩存診斷的時間線
這個功能在 2026 年 5 月以 beta 形式上線,當時需要帶 anthropic-beta: cache-diagnosis-2026-04-07 這個 header。9 月期間規則收緊過一次:只有顯式帶了 diagnostics 對象的請求才會存指紋,只帶 header 的請求不會被記錄。
9 月 23 日它轉爲正式版,不再需要 cache-diagnosis-2026-04-07,帶着舊 header 的請求也照常能用。現在 POST /v1/messages 的響應裏總會出現 diagnostics 字段,沒有開啓時值爲 null。所以看到這個字段是 null,並不代表接口出了問題。
指紋裏只保存哈希和 token 數估計,不保存原始提示詞內容。它按 response id 索引,作用域限定在本組織和本 workspace,保留時間較短。
3 步用 diagnostics 排查 Claude 緩存命中率
下面三步按官方字段說明來寫。如果你通過 API易 調用,Messages 原生接口的 base_url 填 https://api.apiyi.com/v1,請求路徑是 /v1/messages。不過要注意,後文實測部分會說明中轉場景下 diagnostics 的實際回傳情況。

第 1 步:在請求頂層加 diagnostics 對象
diagnostics 是唯一的開關,沒帶它的請求不會存指紋,後面也就無從比較。第一輪沒有可以對比的對象,所以 previous_message_id 傳 null,意思是「從這一輪開始記錄」。
- 請求頭保留常規版本號:
anthropic-version: 2023-06-01 - 正式版之後不需要再帶:
anthropic-beta: cache-diagnosis-2026-04-07 - 在請求體頂層加上:
"diagnostics": {"previous_message_id": null} - 需要緩存的 system 塊照常打斷點:
"cache_control": {"type": "ephemeral"} - 會看到什麼:響應裏
diagnostics爲null,cache_read_input_tokens通常爲 0,cache_creation_input_tokens大於 0
第一輪看到 null 不代表失敗。這一輪是在寫緩存,本來就沒有可比的上一輪,不需要排錯。
第 2 步:之後每一輪都傳上一輪響應的 id
從第二輪開始,把上一輪響應的 id 填進 previous_message_id。最常見的錯誤是隻在第一輪帶 diagnostics,之後漏掉。下一輪指向的那次請求沒有被記錄,結果會返回 previous_message_not_found。
- 第二輪請求體:
"diagnostics": {"previous_message_id": "<第一輪響應的 id>"} - 第三輪請求體:
"diagnostics": {"previous_message_id": "<第二輪響應的 id>"} - 多輪循環的規律:第一輪傳
null,第二輪傳r1.id,第三輪傳r2.id,以此類推 - 流式調用時,結果出現在
message_start事件裏,id 同樣一輪輪往後傳 - 會看到什麼:相鄰兩輪間隔夠短、且在同一 workspace 內時,響應裏開始出現比較結果
第 3 步:讀 cache_miss_reason 並對號修復
diagnostics 有三種取值,讀之前先分清楚:
null:請求沒帶diagnostics;或者previous_message_id爲null;或者比較已經完成且沒有發現分歧{"cache_miss_reason": null}:比較還在進行中,因爲響應開始得太快,這一輪先不下結論,看下一輪cache_miss_reason是一個對象:已經有結論,裏面帶着分叉類型和細節- 會看到什麼:拿到類型後按下一節的對照表修改,先修最早的那個分叉,因爲它只報第一個分歧點,後面的問題可能被它擋住了
🚀 快速開始:如果想先確認自己的緩存前綴能不能寫入和命中,可以在 API易 apiyi.com 用同一個 Key 切換 Claude 各型號做兩輪對照,重點看 usage 裏緩存寫入和讀取兩個數字是否對得上。
cache_miss_reason 六種類型與修復位置
拿到 cache_miss_reason 之後,按下表對應到要改的地方:
| 類型 | 含義 | 改哪裏 |
|---|---|---|
model_changed |
模型和上一輪不同,比如路由、A/B 測試或 fallback 換了模型。緩存按模型隔離 | 同一段緩存對話裏固定模型 |
system_changed |
system 變了,最常見的是插入了時間戳、請求 ID 等每次都不同的值 | system 改成逐字節穩定的常量,動態數據挪到斷點之後的第一條 user 消息 |
tools_changed |
工具被增刪、調換順序,或 input_schema 序列化結果不穩定 |
每輪發送同一份工具列表,順序固定,序列化按鍵排序 |
messages_changed |
更早的消息被改動、重排或刪除,而不是在末尾追加 | 歷史只追加,assistant 內容和工具結果原樣回傳 |
previous_message_not_found |
找不到對應指紋,不等於請求變了 | 每輪都帶 diagnostics,不跨 workspace,間隔不要太長 |
unavailable |
這一輪拿不到診斷結果,比如 tool_choice、thinking、context_management、output_config、output_format 或 beta header 集合不一致,也可能是對話太長 |
一條緩存對話的整個生命週期裏,這些參數保持不變 |
四個 *_changed 類型還會附帶 cache_missed_input_tokens,表示分叉點之後大約丟掉了多少可緩存的輸入 token。這個數是按字節長度換算的,只能用來判斷數量級,不是賬單數字,偶爾還會比 usage.input_tokens 還大。
單看 diagnostics 會誤判:結合 usage 判斷 Claude 緩存命中
diagnostics 回答的是「我的請求變了嗎」,usage.cache_read_input_tokens 回答的是「緩存命中了嗎」。兩個問題不一樣,只看其中一個就容易得出錯誤結論。
| diagnostics 結果 | 緩存讀 token | 結論 | 怎麼做 |
|---|---|---|---|
null |
高 | 前綴穩定,緩存命中 | 不用處理 |
null |
低或爲 0 | 請求沒變,但緩存已經過期 | 縮短請求間隔,或改用 1 小時 TTL |
*_changed |
低 | 請求變了,導致沒有命中 | 按上一節的對照表修復 |
*_changed |
高 | 變化發生在靠後的位置,前面的斷點仍然命中 | 值得修,但影響較小 |
需要再強調一次:null 不等於沒生效,它可能正是最好的結果。還有幾種情況不適用這張表:第一輪,cache_miss_reason 爲 null(比較還在進行),以及 previous_message_not_found 和 unavailable。這幾種情況下根本沒有產生有效比較。

如果你還沒確定哪一輪屬於哪個格子,可以在 API易 apiyi.com 上把同一份請求連發兩輪,記錄每輪的緩存讀寫數字,再對照上面的矩陣逐項排除。
Claude 緩存命中率低的常見原因:三個硬條件
很多時候命中率低,並不是請求變了,而是緩存從一開始就沒寫進去。下面三個條件缺一個,緩存就不會生效:
- 必須顯式打
cache_control:可以放在具體內容塊上做顯式斷點,也可以在請求頂層放一個cache_control,由系統自動把斷點打在最後一個可緩存塊上。如果 content 是純字符串,沒有可以掛標記的內容塊,就永遠不會緩存。 - 長度達到最小可緩存長度:在 Claude API 上,Sonnet 5.5 和 Opus 5.5 都是 512 tokens。前綴不夠長時,緩存會被靜默忽略,也不會報錯。
- 前綴逐字節相同:歷史只追加,system 和 tools 保持穩定。空格、JSON 字段順序、時間戳任何一處變了,都會被當成新的前綴。
API易 的緩存文檔還寫了兩個硬限制:單次請求最多 4 個 cache_control 斷點,每個斷點只向前回溯最近 20 個 content block。長的多輪對話只在最後一條打標記,是覆蓋不到全部歷史的。
TTL 也經常被忽略。默認是 5 分鐘,每次命中都會續期,但計時從寫入或讀取那次請求開始算,而不是從響應結束時算。如果一次流式響應輸出了 4 分鐘,下一次請求大約要在 1 分鐘內發出。需要更長的窗口時,可以在 cache_control 裏寫 "ttl": "1h"。
Claude 緩存命中率掉到 0 的成本賬
下面先列出價格,單位是美元/百萬 tokens,數據時間爲 2026-10-25,以控制檯實時價格爲準:
| 型號 | 輸入 | 輸出 | 緩存讀 | 5 分鐘寫 | 1 小時寫 |
|---|---|---|---|---|---|
| Claude Sonnet 5.5 | $2 | $10 | $0.10 | $2.50 | $4 |
| Claude Opus 5.5 | $4 | $20 | $0.20 | $5 | $8 |
| Claude Haiku 5.5(10 萬 tokens 以內) | $0.1 | $0.5 | $0.01 | $0.125 | $0.20 |
| Claude Haiku 5.5(超過 10 萬 tokens) | $0.50 | $2.50 | $0.05 | $0.625 | $1 |
倍率需要分開看。API易 緩存指南給的通用口徑是:命中 0.1×,5 分鐘寫入 1.25×,1 小時寫入 2×。Sonnet 5.5 在 10 月 7 日隨官方調整,緩存讀從 $0.20 降到 $0.10,變成基礎輸入價的 0.05×,寫入價沒有變。
這次調整不是全線降價,Sonnet 5 的緩存讀仍然是 $0.20。所以不要拿 0.1× 去算 Sonnet 5.5,具體型號與價格以平臺型號列表爲準。
回本點按平臺的通用 0.1× 口徑計算:5 分鐘 TTL 複用兩次就能回本(1.25 + 0.1 = 1.35,低於不緩存的 2.0);1 小時 TTL 需要複用三次(2 + 0.2 = 2.2,低於 3.0)。
再看一個算例。Sonnet 5.5,固定前綴 3 萬 tokens,一天發 200 次,全部在 5 分鐘 TTL 內:
- 全部命中:200 × 3 萬 × $0.10/百萬 = $0.60,加上一次寫入 $0.075,合計約 $0.675/天
- 全部不命中:200 × 3 萬 × $2/百萬 = $12/天
兩者的整日賬單差約 17.8 倍,這不是單價差。單價是 $2 對 $0.10,相差 20 倍。如果改用 1 小時 TTL,一次寫入是 $0.12,命中價不變。請求間隔經常超過 5 分鐘時,可以對比一下:多付的這部分寫入費用,和反覆重建前綴的費用相比哪個更低。

走 API易 時如何排查 Claude 緩存命中率
先說實測結果。2026-10-26 我們在 API易 上實測,用 Claude Sonnet 5.5 跑了兩輪:第一輪緩存寫 2523、讀 0;第二輪原樣回傳後,緩存讀 2523、寫 0,token 數完全對得上。Claude Opus 5.5 用長前綴同樣能寫入,也能命中。
但響應裏沒有 diagnostics 字段。非流式調用沒有,流式調用的 message_start 裏也沒有。我們又帶上 beta header 重發了一次,還故意修改 system 製造了一次真實的不命中(讀 0、寫 2526),響應裏仍然沒有這個字段。所有請求都返回 200,沒有報錯。中轉層的上游通道不一定是官方那條 Claude API,因此在中轉場景下,主要靠 usage 裏的兩個字段互相比對。
| 自檢現象 | 說明 |
|---|---|
本輪 cache_read_input_tokens 精確等於上一輪 cache_creation_input_tokens |
前綴完整命中 |
| 本輪讀明顯小於上一輪寫 | 只命中了更靠前的一段,中間有內容變了 |
| 寫入一直爲 0 | 沒打標記、長度不夠,或者用了 OpenAI 兼容格式 |
| 第二輪又在寫入,而讀爲 0 | 前綴變了,檢查時間戳、UUID、序列化順序 |
另外要特別注意:緩存只在原生 /v1/messages 下生效。用 OpenAI 兼容格式 /v1/chat/completions 調用 Claude,無論怎麼傳參都拿不到緩存計費。
💡 排查建議:API易 apiyi.com 會把
cache_control原樣轉發給上游,響應裏的兩個緩存字段也原樣返回,代碼不需要爲中轉層額外適配。把「本輪讀 = 上一輪寫」做成日誌告警,就能取代大部分人工排查。
Claude 緩存診斷 diagnostics 的限制
diagnostics 不能解決所有問題,使用前先了解它的邊界:
- 只有官方 Claude API 提供,Amazon Bedrock 和 Google Cloud 託管的 Claude 都沒有
- 指紋只短期保留,需要連續幾輪、間隔較短地發送請求
- 兩次請求必須屬於同一組織和同一 workspace,可以用響應頭
anthropic-workspace-id覈對 - 長對話裏,如果變化藏在消息列表很深的位置,可能只會返回
unavailable - 它是 best-effort 機制,拿不到結果也不會阻塞請求,也不會讓請求失敗
常見問題 FAQ
Q1:爲什麼 diagnostics 一直是 null?
分三種情況:沒帶 `diagnostics` 對象;當前是第一輪,`previous_message_id` 爲 `null`;比較完成且沒有分歧。要結合緩存讀數來判斷:讀數高就說明一切正常,讀數爲 0 多半是緩存過期了。如果是走中轉,字段可能根本不會回傳,這時改用 usage 自檢。
Q2:previous_message_not_found 是不是說明請求變了?
不是。它只表示找不到對應的指紋。常見原因有三個:上一輪沒帶 `diagnostics`,上一輪來自別的 workspace,或者間隔太久。每輪都帶上 `diagnostics` 並縮短間隔即可。
Q3:診斷會不會額外收費?
官方文檔沒有把「診斷費用」單獨列爲一項,它隨普通 Messages 請求一起計費。文檔也沒有明確寫不加價,所以計費請以賬單和控制檯爲準。
Q4:走中轉還能用這套診斷嗎?
我們在 API易 的實測中沒有拿到 `diagnostics` 字段,但緩存的寫入和命中都正常。可以用「本輪讀是否精確等於上一輪寫」來判斷,接入方式見 API易 apiyi.com 的緩存計費文檔。
Q5:寫了 cache_control 爲什麼一次都沒寫進緩存?
先檢查三點:content 是不是純字符串;前綴是否達到 512 tokens(Sonnet 5.5 和 Opus 5.5);是否走的是 OpenAI 兼容格式。三者中有任何一個不滿足,緩存都會被靜默跳過。
Q6:同時出現多個問題,應該先修哪個?
先修 `cache_miss_reason` 報出來的那一個。它只報最早的分叉點,修好之後再跑一輪,後面被擋住的問題纔會顯現出來。在 API易 apiyi.com 上用同一份請求反覆回放,可以比較快地逐個排除。
Claude 緩存診斷核心要點 Key Takeaways
- diagnostics 是什麼:傳入上一輪響應 id,定位前綴第一個分叉段
- 怎麼開啓:頂層帶
diagnostics,第一輪傳null,之後每輪都要傳 - null 的含義:第一輪或沒有分歧時也是
null,不能單獨當作故障信號 - 怎麼判斷:diagnostics 配合
cache_read_input_tokens一起看才能下結論 - 硬條件:顯式打標記、達到 512 tokens、前綴逐字節相同
- 成本差距:3 萬前綴每天 200 次,整日賬單相差約 17.8 倍
- 中轉自檢:在 API易 apiyi.com 上看「本輪讀是否等於上一輪寫」
總結
Claude 緩存命中率排查可以歸納爲三件事:
- 定位分叉:每輪帶上
diagnostics,讀cache_miss_reason,先修最早報出的那一處 - 交叉判斷:diagnostics 和 usage 兩邊一起看,
null不代表沒生效 - 守住硬條件:打好標記,長度達標,歷史只追加,system 和 tools 保持穩定
如果你的調用鏈路拿不到 diagnostics,就用 usage 裏的兩個字段建立自檢。推薦先在 API易 apiyi.com 用兩輪請求驗證緩存讀寫數字,再上線到生產環境。
📚 參考資料
- Claude 官方文檔:Cache diagnostics:診斷字段、六種類型與判斷矩陣
- 鏈接:
platform.claude.com -
說明: 本文 diagnostics 的字段、時間線和限制均以該文檔爲準
-
Claude 官方文檔:Prompt caching:緩存規則、TTL、最小長度與價格
- 鏈接:
platform.claude.com -
說明: 最小可緩存長度和官方價格表的來源
-
API易 型號列表:Claude 各型號的輸入、輸出與緩存讀價格
- 鏈接:
docs.apiyi.com/models -
說明: 價格數據更新於 2026-10-25
-
API易 Claude Prompt Caching 緩存計費指南:倍率、回本點與自檢判據
- 鏈接:
docs.apiyi.com/api-capabilities/claude-prompt-caching - 說明: 中轉場景下的排查依據
作者:APIYI 技術團隊
技術交流:歡迎在 API易 網站首頁聯繫我們,更多資料可訪問 docs.apiyi.com 文檔中心
