Claude Platform Docs
Messages上下文管理

缓存诊断

通过比较连续请求并精确识别提示前缀发生分歧的位置,诊断意外的提示缓存未命中问题。

提示缓存(prompt caching)可以显著降低延迟和成本,但前提是您的提示开头与最近的某个请求逐字节完全相同。工具顺序的调整、插入到系统提示中的时间戳,或对较早消息的编辑,都可能悄无声息地使缓存失效。如果没有缓存诊断,唯一的信号就是 usage.cache_read_input_tokens 降为零,而没有任何关于发生了什么变化的提示。

缓存诊断(cache diagnostics)填补了这一空白。传入您上一个响应的 id,API 会比较这两个请求并告诉您它们在哪里发生了分歧(模型、系统提示、工具或消息历史),这样您就可以修复根本原因,而不是靠猜测。

缓存诊断的工作原理

当存在 beta 请求头时,API 会为每个请求存储一个轻量级的"fingerprint"(指纹),以响应 id 作为键。在您的下一个请求中,将该 id 作为 diagnostics.previous_message_id 传入。API 会为新请求重建指纹,将其与已存储的指纹进行比较,并在响应中附加一个 diagnostics 对象,描述第一个分歧点。

该比较针对的是请求结构,与缓存是否实际命中无关。有关如何将 diagnostics 结果与 usage.cache_read_input_tokens 结合使用,请参阅结合 usage 解读诊断结果

指纹仅包含哈希值和令牌数量估计值(绝不包含原始提示内容),保留时间有限,作用域限定在您的组织和工作区内,并且不会用于任何其他目的。

基本用法

在每一轮都发送 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_idnull(第一轮,没有可比较的内容),要么比较已运行且未发现分歧。
{"cache_miss_reason": null}响应被序列化时比较仍在运行。当响应启动非常快时可能会发生这种情况。请将其视为无定论,并检查下一轮。
{"cache_miss_reason": {...}}附加了一个 cache_miss_reason。对于 *_changed 类型,它标识第一个分歧点;previous_message_not_foundunavailable 则是未产生比较结果的情况。

cache_miss_reason 非空时,它看起来像这样:

{
  "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_changedmodel 与上一个请求不同(例如,路由器、A/B 测试或回退机制选择了不同的模型)。缓存是按模型区分的。在一个已缓存的对话中保持模型不变。
system_changedsystem 参数不同。通常是时间戳、请求 ID 或其他每次请求都不同的值被插入到了系统提示中。使系统提示成为字节稳定的常量,并将动态数据移到缓存断点之后的第一条 user 消息中。
tools_changedtools 数组不同:在轮次之间添加、删除或重新排序了工具,或者工具的 input_schema JSON 被非确定性地序列化。每一轮都以固定顺序发送相同的工具列表,并使用确定性序列化的 schema(例如,对键进行排序)。
messages_changed模型、系统提示和工具全部匹配,但 messages 中较早的条目被修改、重新排序或删除,而不是仅追加。通常是对话历史被截断或编辑,或者助手轮次和 tool_result 块在重新发送时被以不同方式重新序列化。将历史视为仅追加;原样回传助手的 content 和工具结果。
previous_message_not_found所提供的 previous_message_id 不存在已存储的指纹。这并不能证明您的请求发生了变化。通常是上一个请求未携带 beta 请求头、来自不同的工作区,或者自发送以来已过去太长时间。每一轮都发送 beta 请求头,并使连续轮次在时间上保持接近。
unavailable此请求的诊断信息不可用。这包括以下情况:modelsystemtools 匹配,但另一个影响提示的请求参数(tool_choicethinkingcontext_managementoutput_configoutput_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_reasonnull(比较仍在进行中;请检查下一轮)或其 typeprevious_message_not_foundunavailable(未产生比较结果)时,此矩阵也不适用。

诊断结果缓存读取令牌数解读
null按预期工作。您的前缀稳定且缓存命中。
null低或为零您的请求匹配,但缓存条目已不再可用。请考虑缩短轮次之间的间隔,或使用 1 小时缓存 TTL
cache_miss_reason*_changed 类型低或为零您的 bug。请求发生了变化;请修复 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 输出的原始文本。

为每个请求存储的指纹仅由加密哈希值和令牌数量估计值组成,以响应 id 作为键,作用域限定在您的组织和工作区内。指纹会在短时间后过期,并且不会用于任何其他目的。

有关所有功能的 ZDR 资格,请参阅 API 和数据保留

另请参阅

Compatibility

Supported platforms
  • Claude APIBeta

Was this page helpful?