提示词缓存命中率低应如何划分静态前缀
来源:17golang原创
时间:2026-10-09 18:13:56 453浏览 收藏
提示词缓存命中率低,通常不是把 cache_control 再加一遍就能解决,而是断点放在了每次请求都会变化的内容上。最稳妥的划分是:工具定义、固定系统规则、长期知识和稳定示例放在前缀;时间戳、用户问题、会话变量和本次检索结果放在后缀。断点要落在“最后一个仍然稳定的块”上。
官方文档:https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
- 缓存匹配的是包含断点的完整前缀,前缀中任意早期块变化都会换 hash。
- 显式断点最多 4 个;逐步增长的消息还要考虑 20 个 block 的回看窗口。
- 先看
cache_read_input_tokens,再判断是断点错位、长度不足还是 TTL 与并发时序问题。
先把静态前缀和动态后缀分开
一次请求可以抽象成三段:工具定义、system 内容、messages 内容。Anthropic 文档规定缓存前缀按 tools → system → messages 组织,断点之前的全部内容共同参与匹配。因此,哪怕只把一个请求时间写进了断点块,整个前缀也会变成新的内容。
| 内容 | 稳定性 | 建议位置 |
|---|---|---|
| 工具 schema、角色规则、固定示例 | 跨请求稳定 | 缓存前缀 |
| 版本化知识库、租户公共说明 | 按日或版本变化 | 独立断点 |
| 时间戳、用户问题、检索结果 | 每次变化 | 断点之后 |
这里的关键不是“把 prompt 写得更长”,而是让同一业务路由产生可复用的字节序列。租户 ID 如果每次都不同,就不要塞进所有租户共享的系统前缀;可以把公共规则缓存起来,把租户差异放在后缀,或者按租户分别建立稳定前缀。
断点要落在最后一个不变的内容块
假设第 1~5 块是固定规则,第 6 块是当前时间和用户问题。把断点放在第 6 块时,第二次请求虽然前 5 块没变,也只能回看此前实际写过的断点,通常得不到命中。把断点移到第 5 块,后续请求就能复用同一个静态前缀。
import anthropic
client = anthropic.Anthropic()
# 只有稳定的系统规则放在断点内;时间、用户问题留在 messages 后缀。
system_blocks = [
{
"type": "text",
"text": "你是订单客服。先核对订单状态,再给出可执行的处理建议。",
"cache_control": {"type": "ephemeral"},
}
]
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=800,
system=system_blocks,
messages=[
{
"role": "user",
# 这个块每次都可能变化,不要把它标成静态前缀的结束点。
"content": "订单号 A1024,用户刚刚反馈包裹仍未送达。",
}
],
)
# 记录 usage,区分首次写入、命中读取和普通输入。
print(response.usage.model_dump_json())
示例中的系统规则只是结构示意,生产环境还要保证规则文本、工具 schema、模型参数和内容顺序在同一缓存组内稳定。需要动态信息时,宁可增加后缀,也不要为了“靠近问题”把断点推到变化块上。
按变化频率拆断点,并检查回看窗口
工具定义很少变化,系统规则可能随版本发布,知识上下文可能每天刷新,这三类内容可以用多个断点分层。官方接口支持最多 4 个显式断点,增加断点本身不会单独收费,但实际写入和读取的 token 仍会计费。
增长中的多轮消息还有一个容易忽略的边界:每个断点最多向前回看 20 个 block,且只会找到过去真正写入过的断点。如果对话不断追加内容,旧断点被推到窗口之外,即使旧内容没变也可能不命中。可以从一开始就在稳定的工具区、系统区和阶段性上下文末尾分别布点,不要等窗口已经越过才补救。

用 usage 字段定位低命中原因

不要只看平均延迟。第一次成功建立缓存时,重点关注 cache_creation_input_tokens;复用时关注 cache_read_input_tokens。两者都为 0,可能是缓存内容没达到当前模型的最小 token 门槛,也可能是平台或请求结构没有形成可用断点。命中读取长期为 0,则优先对比断点前的完整文本、工具 schema、模型和 system 顺序。
- 每次都是 creation:断点可能包含时间戳、随机 ID 或检索结果,先把这些字段移到后缀。
- 偶尔命中:检查 5 分钟默认 TTL、请求间隔,以及流式响应尚未开始时发出的并发请求。
- 完全没有读写 token:检查缓存前缀是否达到该模型要求的最小长度,并确认 usage 字段被完整记录。
最后用一组固定请求做灰度:先保持模型、工具和 system 不变,只替换用户问题;再逐项改变工具版本、知识上下文和 TTL。这样才能分清是前缀设计问题,还是请求频率与缓存生命周期不匹配。
常见问题
把整个 messages 数组都标记缓存可以吗?
不建议。多轮消息里包含用户问题和工具结果时,整个数组很容易随请求变化;应把稳定的公共消息放在前面,动态内容放在断点之后。
缓存命中率低是否一定要延长 TTL?
不一定。先确认断点前缀一致,再判断请求间隔是否超过默认 5 分钟;如果前缀每次都变化,延长 TTL 也不会产生命中。
多个断点会让费用翻倍吗?
断点数量本身不单独收费,费用取决于实际发生的缓存写入、读取和未缓存输入;应以 usage 和业务延迟共同决定分层粒度。
-
232 收藏
-
215 收藏
-
236 收藏
-
196 收藏
-
404 收藏
-
372 收藏
-
404 收藏
-
409 收藏
-
128 收藏
-
111 收藏
-
286 收藏
-
127 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习