快取診斷
透過比較連續的請求並精確找出提示前綴發生分歧的位置,診斷非預期的提示快取未命中。
Prompt caching(提示快取)能大幅降低延遲與成本,但前提是您的提示開頭必須與最近的某個請求逐位元組完全相同。工具順序被重新排列、系統提示中插入了時間戳記,或是對較早訊息的編輯,都可能在無聲無息中使快取失效。若沒有快取診斷,唯一的訊號就是 usage.cache_read_input_tokens 降為零,卻沒有任何跡象顯示是什麼發生了變化。
「Cache diagnostics」(快取診斷)填補了這個缺口。傳入您上一個回應的 id,API 便會比較這兩個請求,並告訴您它們在何處發生分歧(模型、系統提示、工具或訊息歷史),讓您能修正根本原因,而不是憑空猜測。
快取診斷的運作方式
當 beta 標頭存在時,API 會為每個請求儲存一份輕量的「fingerprint」(指紋),以回應的 id 作為鍵值。在您的下一個請求中,將該 id 作為 diagnostics.previous_message_id 傳入。API 會為新請求重建指紋,將其與已儲存的指紋進行比較,並在回應中附加一個 diagnostics 物件,描述第一個分歧點。
此比較針對的是請求結構,與快取是否實際命中無關。請參閱搭配 usage 解讀診斷結果,了解如何將 diagnostics 結果與 usage.cache_read_input_tokens 結合使用。
指紋僅包含雜湊值與 token 數量估計值(絕不包含原始提示內容),保留時間有限,範圍限定於您的組織與工作區,且不會用於任何其他用途。
基本用法
在每一輪都傳送 beta 標頭。在第一輪,傳入 "previous_message_id": null 以選擇加入,此時沒有先前的訊息可供比較。在後續各輪,傳入上一個回應的 id。
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
# 第 1 輪:以 previous_message_id=None 選擇加入
r1 = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[{"role": "user", "content": "Summarize section 1."}],
diagnostics={"previous_message_id": None},
betas=["cache-diagnosis-2026-04-07"],
)
# 第 2 輪:參照前一個回應的 id
r2 = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
)
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")串流
在「streaming」(串流)回應中,diagnostics 會出現在 message_start 事件上。
# 第 2 輪:串流,並參照前一個回應的 id
with client.beta.messages.stream(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
r2 = stream.get_final_message()
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")message_start 事件帶有完整的 diagnostics 欄位;可能的值請參閱回應格式。
在對話迴圈中串接診斷
在多輪對話中,每一輪都將最新回應的 id 作為 previous_message_id 往下傳遞。第一次迭代傳入 null 以選擇加入;之後每次迭代都傳入上一個回應的 id。
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
messages = []
prev_id = None
for i, user_message in enumerate(
["Summarize section 1.", "Now section 2.", "Now section 3."]
):
messages.append({"role": "user", "content": user_message})
r = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=messages,
diagnostics={"previous_message_id": prev_id},
betas=["cache-diagnosis-2026-04-07"],
)
if r.diagnostics is not None and r.diagnostics.cache_miss_reason is not None:
print(f"Turn {i + 1} cache_miss_reason: {r.diagnostics.cache_miss_reason.type}")
messages.append({"role": "assistant", "content": r.content})
prev_id = r.id回應格式
回應 Message 上的 diagnostics 欄位有四種可能的狀態:
| 值 | 意義 |
|---|---|
| 欄位不存在 | 請求未包含 diagnostics,或缺少 beta 標頭。 |
null | previous_message_id 為 null(第一輪,無可比較對象),或是比較已執行且未發現分歧。 |
{"cache_miss_reason": null} | 回應序列化時比較仍在執行中。當回應開始得非常快時可能發生這種情況。請將其視為無定論,並檢查下一輪。 |
{"cache_miss_reason": {...}} | 附加了 cache_miss_reason。對於 *_changed 類型,這會指出第一個分歧點;previous_message_not_found 與 unavailable 則是未產生比較結果的情況。 |
當 cache_miss_reason 不為 null 時,其內容如下:
{
"id": "msg_01Xyz...",
"type": "message",
"role": "assistant",
"content": [{ "type": "text", "text": "..." }],
"usage": {
"input_tokens": 42,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 41850,
"output_tokens": 210
},
"diagnostics": {
"cache_miss_reason": {
"type": "system_changed",
"cache_missed_input_tokens": 41850
}
}
}快取未命中原因類型
cache_miss_reason 是以 type 區分的「discriminated union」(可辨識聯集)。回應只會回報最早的分歧,因此請先修正它;後面的分歧可能被它遮蔽。
| 類型 | 意義 | 應變更之處 |
|---|---|---|
model_changed | model 與上一個請求不同(例如路由器、A/B 測試或備援機制選擇了不同的模型)。快取是依模型區分的。 | 在快取的對話中保持模型不變。 |
system_changed | system 參數不同。通常是時間戳記、請求 ID 或其他每次請求不同的值被插入到系統提示中。 | 讓系統提示成為逐位元組穩定的常數,並將動態資料移至快取斷點之後的第一則 user 訊息中。 |
tools_changed | tools 陣列不同:各輪之間新增、移除或重新排序了工具,或工具的 input_schema JSON 以非確定性方式序列化。 | 每一輪都以固定順序傳送相同的工具清單,並以確定性方式序列化 schema(例如排序鍵值)。 |
messages_changed | 模型、系統提示與工具皆相符,但 messages 中較早的項目被修改、重新排序或移除,而非僅附加新內容。通常是對話歷史被截斷或編輯,或是 assistant 輪次與 tool_result 區塊在重新傳送時以不同方式重新序列化。 | 將歷史視為僅可附加;將 assistant 的 content 與工具結果原封不動地回傳。 |
previous_message_not_found | 所提供的 previous_message_id 沒有對應的已儲存指紋。這並不代表您的請求發生了變化。通常是上一個請求未帶有 beta 標頭、來自不同的工作區,或距離傳送時間已過太久。 | 每一輪都傳送 beta 標頭,並讓連續各輪在時間上保持接近。 |
unavailable | 此請求無法取得診斷資訊。這包括 model、system 與 tools 皆相符,但另一個會影響提示的請求參數(tool_choice、thinking、context_management、output_config、output_format,或啟用中的 anthropic-beta 標頭集合)不同的情況,以及分歧點超出比較範圍的極長對話。您的請求已正常處理。 | 在快取對話的整個生命週期內,保持會影響提示的請求參數不變。若問題持續,請套用提示快取頁面中常見問題疑難排解下的手動檢查。 |
搭配 usage 解讀診斷結果
diagnostics 回答的是「我的請求是否改變了?」,而 usage.cache_read_input_tokens 回答的是「快取是否命中?」。將兩者結合即可知道該從何處著手。
此矩陣適用於您傳入了實際 previous_message_id 的輪次。在第一輪(previous_message_id: null),diagnostics 一律為 null,且 cache_read_input_tokens 通常為零,因為此時是在寫入快取而非讀取;無需進行疑難排解。當 cache_miss_reason 為 null(比較仍在進行中;請檢查下一輪),或其 type 為 previous_message_not_found 或 unavailable(未產生比較結果)時,此矩陣亦不適用。
| 診斷結果 | 快取讀取 token 數 | 解讀 |
|---|---|---|
null | 高 | 運作正常。您的前綴穩定且快取命中。 |
null | 低或零 | 您的請求相符,但快取項目已不再可用。請考慮縮短各輪之間的間隔,或使用 1 小時快取 TTL。 |
cache_miss_reason 為 *_changed 類型 | 低或零 | 您的程式錯誤。請求發生了變化;請依 type 所指出的原因進行修正。 |
cache_miss_reason 為 *_changed 類型 | 高 | 罕見。變化發生在提示的後段,但較早的 cache_control 斷點仍然命中。值得修正,但影響不大。 |
限制
- Beta: 在此功能處於 beta 期間,欄位名稱與語意可能會變更。
- 僅限 Claude API: 不適用於 Amazon Bedrock 或 Google Cloud。
- 有限的保留期: 用於
previous_message_id查詢的指紋會在短時間後過期。請在時間間隔接近的請求之間執行診斷比較。 - 相同工作區: 上一個請求必須在相同的組織與工作區中執行。若要確認,請比較兩個回應上的
anthropic-workspace-id回應標頭。 - 比較範圍: 對於唯一變化位於訊息清單深處的極長對話,回應可能是
unavailable而非精確位置。 - 盡力而為: 診斷絕不會阻擋您的請求或使其失敗。若無法取得診斷資訊,回應會傳回
unavailable;若比較仍在執行中,則傳回cache_miss_reason: null。
資料保留
快取診斷符合 ZDR 資格(有條件)。Anthropic 不會為此功能儲存您提示的原始文字或 Claude 的輸出。
為每個請求儲存的指紋僅由加密雜湊值與 token 數量估計值組成,以回應的 id 作為鍵值,且範圍限定於您的組織與工作區。指紋會在短時間後過期,且不會用於任何其他用途。
關於所有功能的 ZDR 資格,請參閱 API 與資料保留。
另請參閱
Compatibility
| Supported platforms |
|
|---|
Was this page helpful?