Claude 提示缓存没有命中,先查看响应的 usage,再检查可缓存前缀是否足够长、是否保持相同,以及第二次请求是否发生在有效期内。把 cache_control 写进请求,不等于这次请求已经读到了缓存。
本文讨论直连 Claude API 的 prompt caching,适合已经能发送 Messages 请求的 Python 开发者。示例使用自己的公开手册作为静态资料,问题内容可以变化;未进行付费 API 实测。规则与接口于 2026 年 10 月 1 日核对,云平台托管接口请另查对应平台文档。

先用 usage 判断属于哪一种情况
| 返回字段 | 代表什么 | 下一步 |
|---|---|---|
| cache_creation_input_tokens 大于 0 | 本次写入了新缓存 | 等待本次响应完成,用相同前缀再次请求 |
| cache_read_input_tokens 大于 0 | 本次读取了缓存前缀 | 核对读取量是否覆盖预期的静态部分 |
| 两个缓存字段都是 0 | 本次没有形成可观察的缓存写入或读取 | 检查长度门槛、字段位置和模型支持情况 |
| 每次都在写入、很少读取 | 前缀可能变化,或旧条目已失效 | 比较静态内容,检查间隔与请求设置 |
缓存读取与写入可以同时出现在一次请求里,例如较早的前缀命中、后面新增的部分写入。因此“某个字段不为零”要结合你缓存了哪一段来解释。普通 input_tokens 也不是整份输入的唯一计数;需一起看缓存字段。字段、最低长度和缓存行为依据官方提示缓存文档。
把缓存断点放在真正稳定的前缀末尾
请求内容按工具定义、system 内容、messages 内容形成前缀。显式断点缓存的是该位置之前的前缀,而不是只缓存标记所在的一个段落。把每次变化的时间戳、用户姓名或问题放到断点之前,会改变前缀,让原有条目无法复用。
典型的问答系统可把稳定的角色说明和公开手册放在 system,给手册这一块加 cache_control;当次问题放在之后的 user 消息中。不要在手册前加“当前请求时间”。如果工具定义也会变化,应将其变化一并纳入排查。
可缓存前缀还必须达到所选模型的最低 token 长度。核对当日文档的 Cache limitations 表,按准确模型 ID 找对应门槛;不能把一个模型的门槛当作所有模型的统一值。短提示即使带断点,也可能正常生成答案却没有缓存字段用量。为了命中而堆无关重复文本会增加成本,优先缓存真实需要反复使用的资料。
最小诊断:同一份手册,连续发送两个问题
- 安装 Python 3.10 或更新版本,并执行
python -m pip install requests。 - 将一份有权使用、没有敏感信息的 UTF-8 手册保存为
handbook.txt。它需要达到模型的缓存长度门槛,并能放入该模型上下文窗口。 - 配置进程环境变量
ANTHROPIC_API_KEY与ANTHROPIC_MODEL。模型 ID 可在官方模型说明核对。 - 保存并执行下面的
cache_probe.py。它会串行发送两次实际模型请求;静态手册不变,第二次只改问题。
import hashlib
import json
import os
from pathlib import Path
import requests
model = os.environ["ANTHROPIC_MODEL"]
headers = {
"x-api-key": os.environ["ANTHROPIC_API_KEY"],
"anthropic-version": "2023-06-01",
"content-type": "application/json",
}
manual = Path("handbook.txt").read_text(encoding="utf-8")
if not manual.strip():
raise ValueError("手册为空,停止测试")
system = [
{"type": "text", "text": "只按所给手册回答;没有依据时说明未找到。"},
{"type": "text", "text": manual,
"cache_control": {"type": "ephemeral"}},
]
prefix = json.dumps(system, ensure_ascii=False, sort_keys=True)
print("static_prefix_sha256", hashlib.sha256(prefix.encode()).hexdigest())
questions = ["概括手册的主要内容。", "按手册列出新手最先完成的两件事。"]
for index, question in enumerate(questions, 1):
response = requests.post(
"https://api.anthropic.com/v1/messages",
headers=headers,
json={"model": model, "max_tokens": 2048,
"system": system,
"messages": [{"role": "user", "content": question}]},
timeout=(10, 60),
)
response.raise_for_status()
message = response.json()
usage = message.get("usage", {})
print("request", index,
"created", usage.get("cache_creation_input_tokens", 0),
"read", usage.get("cache_read_input_tokens", 0),
"ordinary_input", usage.get("input_tokens", 0),
"stop", message.get("stop_reason"))
print("\n".join(b["text"] for b in message["content"] if b["type"] == "text"))
第一条响应完整读取后,程序才发送第二条,避免两次同时启动时缓存还未建立。正常预期是第一条有缓存创建量,第二条有缓存读取量;这是验证目标,具体用量和是否命中要以实际响应为准。即使答案正常,也不能把它当作缓存命中的证据。
没有命中时,按顺序缩小范围
- 核对断点。确认发出去的 JSON 确实在 system 手册内容块上保留了
cache_control;有的请求封装会过滤它。 - 核对长度。查当前模型最低缓存长度。如果两个用量字段全是零,先检查这一项;模型的总上下文容量与最低缓存门槛不是同一个数字。
- 核对静态资料。相同测试的
static_prefix_sha256应相同。摘要更新、空白改动、工具描述变化也可能影响前缀。这里只计算示例 system 的指纹;真实项目还应比较工具定义和其他前置内容。 - 核对有效期。默认 ephemeral 缓存有效期为 5 分钟,缓存被使用时刷新。若业务间隔更长,可按文档评估
ttl: "1h",但一小时写入有不同计费,不能直接假定更省钱。 - 核对请求结构。长会话有大量内容块时,文档说明每个断点最多向前检查 20 个位置。稳定段与新段间隔太远,可在稳定段末尾补显式断点;不要无上限添加断点,当前文档最多支持 4 个。
如果这份最小示例能读到缓存,而业务请求读不到,逐项加回业务 system、工具定义、历史消息,找到首次改变命中结果的那一步。不要一边换模型、一边改断点、一边缩减资料,否则很难确定是哪一项解决了问题。
判断收益时,不只比较生成速度
单次延迟受网络、输出长度和模型生成影响。先保存每次的缓存创建、读取、普通输入和输出 token,再按所用模型当日价格计算。首次写入缓存有写入成本;几乎不复用的前缀可能不值得缓存。缓存也不减少逻辑上的上下文占用,不会让同一模型自动容纳更多资料。
相关问答
删除浏览器缓存能解决这个问题吗?
本文的缓存由 API 请求前缀与服务端缓存逻辑决定,清浏览器缓存不是这里的诊断步骤。若实际问题发生在网页界面,应先区分网页加载故障和 API 缓存用量。
缓存后会把上次的答案原样返回吗?
提示缓存复用输入前缀的处理,不是把整份生成答案当作固定回复。新问题仍需模型生成,仍产生输出 token;第二次答案不同不代表没有命中。
Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30418.html