> 来源 Commit: 515b759 (easy-learn-ai)
> 标签: #easy-learn-ai #每日更新 #记忆 #小凯
引子:一句工程界的"咒语"
工程界有句老话,叫"缓存统治一切"。
这话放在互联网刚兴起的时候就有了。那时候工程师们发现,与其每次都从零组装一个网页,不如把常用的部分——导航栏、页脚、用户头像——提前做好,有人来要的时候直接拿现成的。这个朴素的发现,后来被写进计算机科学的教科书,成了一个不言自明的真理。
到了 AI Agent 时代,这句老话依然成立。只不过这次,缓存的不是网页,而是大模型脑子里已经算过一遍的东西。
一、问题:AI 的"重复劳动"
想象一下这个场景。
你正在用 Claude Code——Anthropic 的 AI 编程助手——写一个复杂的项目。你跟它聊了 20 轮,每一轮都在追加新的要求:"帮我改这个函数""这里加个异常处理""再优化一下性能"。
这 20 轮对话里, Claude 每一轮都要把前 19 轮说过的话重新"想一遍"。不是因为它记性不好,而是技术架构就这么设计的:每次发请求,模型都得把整段上下文从头到尾编码一遍,才能理解"现在该干嘛"。
这个过程在业界叫 Prefill ——预填充。它是延迟和花钱的大头。
问题来了:你跟它聊 20 轮,第 20 轮的请求里前 19 轮和上次一模一样。但模型还得从第一个字重新算一遍,白白做了 19 轮重复劳动。
这就好比你每次写论文都要重抄目录和前几章再接新内容。费时费力不说,钱也是哗哗地流。
二、解药:提示词缓存
提示词缓存(Prompt Cache)就是来解决这个问题的。
原理一句话:你在请求里标一个断点。后台就把从开头到这个断点之间的编码结果存下来。下次前缀完全一样,直接复用,跳过重复计算。
打个比方。你每次写论文都要重抄目录和前几章再接新内容。有了缓存,相当于抄过的部分直接快进,只写新的那一段。
在技术层面,这个"编码结果"有个专门的名字:KV Cache(键值缓存)。大模型在处理文本时,会把每个词转换成一个数学向量,并计算它们之间的关系。这些中间结果如果能被保存下来,后续请求就能直接复用,而不需要重新计算。
三、真实账本:省多少?
数字是最诚实的。
命中缓存的部分,价格打一折。首次写入要 1.25 倍——多花 25%,但后面每次省 90%。
默认存 5 分钟。5 分钟内有请求就自动续期,不额外收钱。也可以选 1 小时的付费版本。
不过有个门槛——内容太短缓存不上。一般至少要 1024 个 token,新一点的模型要 4096 个。短 prompt 没缓存的份。
举个实在的例子:10 万字的长对话。
- 不开缓存,Claude Sonnet 每轮要花 0.30 美金。
- 开了缓存,首次 0.375。之后每轮只要 0.03。
而且不光省钱。延迟也降下来了——不用重算的部分越多,第一个字出来得越快(业界叫 TTFT,Time To First Token)。
四、基建级待遇
Anthropic 内部,把缓存命中率当基础设施级别的指标在看。
地位跟服务器在线率差不多。命中率一掉,触发值班告警,工程师得当线上事故处理。原文用的词是"宣布分级事故"(declare SEVs)——走完整的事故响应流程,比普通告警严重多了。
更关键的是,命中率高不光省钱,还直接影响用户体验——它让 Anthropic 能给付费用户更宽松的使用额度。
缓存命中率越高,你在同样的价格下,能用得越多。
所以缓存对 Claude Code 来说,不是锦上添花的优化。是整个系统能跑起来的前提。没有缓存,就没有 Claude Code。
因为 Claude Code 这种 AI 编程助手是长对话的。一个会话几十轮。每一轮都要把上文全带上重新发。每次都从头算,延迟和成本会爆炸。
五、核心原理:前缀匹配
缓存的核心原理是前缀匹配。
下一次请求的前缀跟上次一样,就能复用之前的计算。这看起来简单,但它决定了所有工程决策的走向。
前缀里任何位置的变化,都会让其后所有内容的缓存失效。就像一条多米诺骨牌,推倒第一块,后面的全倒。
理解了这一点,下面所有最佳实践都顺理成章。
六、排好队形:提示词的层次结构
既然缓存靠前缀匹配,那提示词里东西的排列顺序就至关重要了。
Anthropic 的最佳实践是这样排的:
1. 最前面,放系统指令和工具定义。 这些是固定的,所有会话共享。 2. 第二层,放项目文档。 同一个项目内共享。 3. 第三层,放当前会话的上下文。 只在这一次对话里有效。 4. 最后才是聊天消息。 逐轮增长,每轮只新增最后一条。
一句话——越不容易变的东西,越往前放。
就好比收拾书桌。常年不动的参考书放最底层。这周要看的资料放中间。今天写的草稿放最上面。这样你每天坐下来才不用把整张桌子翻一遍。
七、三个坑
前缀匹配是一把双刃剑。一个小细节没注意,整条缓存链就断了。
坑一:在固定指令里嵌了当前时间。
每秒都在变,缓存直接废掉。时间应该在消息层动态传递,而不是钉死在系统指令里。
坑二:工具定义用无序容器来装。
比如 Python 的 set 或 JavaScript 的 Object。每次发请求顺序都不一样,前缀对不上。必须用有序列表(数组)存放工具定义。
坑三:工具参数改了。
哪怕只动一个字段,整条前缀的缓存全失效。因为工具定义是前缀的一部分,一碰就断。
八、别动指令
那信息确实过时了怎么办?比如时间、文件状态这些。
Anthropic 的做法是——别去改系统指令,把更新塞进下一轮的消息里。
具体怎么做?在下一条用户消息里附上一段"系统提醒",把要更新的信息夹带进去。这样系统指令纹丝不动,缓存完好无损。
这个分法挺值得记一下:系统指令当地基,钉死不动;消息当流水,想怎么改怎么改。 这样一分,缓存就稳了。
这就是前面说的"用消息代替指令修改"原则。
九、别换模型
下一条,对很多人来说有点反直觉。
你可能会想。简单问题切到小模型省点钱。难题再切回大模型。多合理啊。
但现实是。缓存是跟模型绑定的。 换模型,等于之前积攒的所有缓存全部作废,从头重建。
重建的成本,往往比让大模型直接回答那个简单问题还要高。
所以 Claude Code 的策略是——主对话自始至终用同一个模型。
需要小模型干活的时候怎么办?派子任务。
十、子任务:独立缓存,互不干扰
子任务有自己独立的上下文和缓存,不会污染主对话的缓存链。
具体做法是:让主模型先写个任务交接说明(hand-off message),把上下文浓缩好。然后传给子任务去执行,做完只把结果传回主对话。
Claude Code 里的探索模式就是这样工作的。它用小模型,在独立的上下文里执行探索任务。
打个比方。你不会为了省事让实习生坐到你工位上用你的电脑。而是给他分配一台独立的机器,把任务说明写清楚发过去,做完把结果发回来。
这里要给搞中转的朋友提个醒——缓存是按账号隔离的。账号池一混,命中率过低,钱没赚到反而把号搞没了。别聊两句就来回切账号。
十一、别碰工具
下一条核心一样——对话过程中,工具集不要动。
直觉上你可能觉得,当前任务只需要 3 个工具,把另外 30 个移走,不更干净吗?
但工具定义是缓存前缀的一部分。加一个,减一个,缓存就断了。一断,就是整个对话的缓存全部重建。代价远远超过多放几个工具定义占的那点空间。
看着像优化,结果是添乱。
十二、规划模式:用工具表达状态转换
Claude Code 有个"规划模式"。进入后模型只思考、只规划,不执行操作。
按直觉的做法,进规划模式就把执行类工具移走,退出来再加回来。但 Anthropic 没这么干。
他们的做法是保留所有工具不动。另外加了两个特殊工具——"进入规划"和"退出规划"。模型调用"进入规划"就切到思考模式。调用"退出规划"就回来。
那"规划模式下不能执行"这个约束怎么传达?通过在对话中插入一条系统消息,告诉模型你现在在规划。
注意——是在对话流里插一条消息,不是去改系统指令。这两个东西要分清。
- 系统指令(System Prompt) 是固定的,在缓存前缀里。
- 系统消息(System Message) 是流动的,不影响前缀。
而且还带来一个额外好处。模型可以自己判断什么时候进规划模式——遇到复杂任务,它自己先想清楚再动手,不用你手动切换。
十三、延迟加载:图书馆的索引卡片
Claude Code 可能要接入几十个外部工具。全部完整定义塞进去?太占空间。按需加减?又破坏缓存。
Anthropic 找到的折中方案,叫延迟加载(Lazy Loading)。
一开始只放一个轻量的占位符(stub)。模型看到的只是工具名字,不含完整的参数定义。等模型真要用某个工具了,再通过"工具搜索"功能去拉取完整定义。
好处是。前缀始终只包含那些轻量占位符,不会因为加载了某个工具就变化。缓存稳稳的。
相当于图书馆的书目索引。你先翻目录,找到想看的书再去书架取,不用把所有书都搬到桌上。
值得一提的是,这个工具搜索功能已经通过 API 对外开放了。开发者可以直接用,简化自己的工具管理。
十四、压缩的麻烦与缓存安全分叉
长对话跑久了,上下文窗口会被填满。这时候要把之前的对话压缩成摘要,腾出空间继续聊。
但问题来了。如果你另起一个请求做压缩,用了不同的系统指令,没带工具定义——那从第一个字开始,就跟主对话的缓存对不上。两条缓存链,互相不复用。
而且你要把整段对话发过去做摘要。这时候你付的是完整的、没有缓存折扣的费用。对话越长越贵。
Anthropic 的解决方案叫 "缓存安全分叉"(Cache-Safe Forking)。
压缩请求必须用跟主对话完全一样的系统指令、用户上下文、工具定义,把主对话的消息作为历史带上。然后在末尾追加一条压缩指令,作为新的用户消息。
从后台视角看,这个请求和上一次几乎一模一样。相同的前缀,相同的工具,相同的历史,所以前缀缓存可以直接复用。
新增成本,只有最后那条压缩指令本身。
同时还要预留一个压缩缓冲区,给摘要输出留够空间。不能等窗口填满才开始压缩,要提前留余量。
一个压缩操作,能复用主对话积攒的全部缓存。几乎不多花钱。
十五、回头看:一切都指向前缀匹配
回头看这 7 条经验,都在说同一件事——缓存就是前缀匹配。
1. 前缀匹配决定一切。 前缀里任何位置的变化,都会让其后所有内容的缓存失效。 2. 用消息代替指令修改。 要切换模式、要更新时间,把这些塞进对话消息,别去动系统指令。 3. 不要在对话中途切换工具或模型。 用工具来表达状态转换,用延迟加载代替工具的增删。 4. 像监控在线率一样监控缓存命中率。 Anthropic 对缓存中断发告警,当线上事故处理。 5. 分叉操作必须共享主对话的前缀。 压缩、摘要、子任务,全部用相同的参数。
所有的设计,都要围绕这一个约束来展开。别改指令,别动工具——一碰,整条缓存链就断。换模型、切账号、另起炉灶,同一个道理。
结语:约束即框架
这看着像缓存优化。但讲的也是一种思路——先认死那条绕不开的限制,再围着它把整个系统搭起来。
提示词缓存的故事告诉我们,有时候最重要的工程智慧不是"怎么做得更多",而是"怎么在不变的约束下走得更稳"。前缀匹配就是那个约束,而 Anthropic 围绕它搭起了一整套 Claude Code 的架构哲学。
在 AI Agent 时代,当每一个 token 都在计费,当每一次对话都可能长到填满上下文窗口,缓存不再是一种可选的优化,而是系统能否存在的先决条件。
工程界的老话没错。
缓存统治一切。
---
#easy-learn-ai #每日更新 #记忆 #小凯