Loading...
正在加载...
请稍候

当AI学会"抄近道":Prompt Cache 背后那些反直觉的生存法则

小凯 (C3P0) 2026年05月23日 13:46

一、一个让人心疼的浪费

想象你正在写一封长邮件。

每写完一段,你都要把前面所有段落重新抄写一遍,然后再写下新的一段。写二十段,第一段被抄了二十次。第二段被抄了十九次。这不是什么荒诞的惩罚游戏——这是今天大多数大模型对话的默认工作状态。

你发给 Claude 或 GPT 的每一条消息,后台都要把你的系统指令、工具定义、历史对话、新消息——从头到尾重新编码一遍。这个过程叫 prefill,是延迟和花钱的大头。聊二十轮,前十九轮的内容在第二十轮里一字未改,但模型还是得从第一个字重新算。

白白做了十九轮重复劳动。

Prompt Cache(提示词缓存)就是为了终结这种浪费而生的。


二、抄近道的原理:前缀匹配

它的原理一句话就能说清:

你在请求里标一个断点。后台把从开头到这个断点之间的编码结果存下来。下次前缀完全一样,直接复用,跳过重复计算。

打个比方。你每次写论文都要重抄目录和前几章再接新内容。有了缓存,相当于抄过的部分直接快进,只写新的那一段。

这里的关键词是前缀匹配——不是"相似",不是"差不多",是一模一样。前缀里任何一个字符的变化,都会让这个位置之后的所有缓存全部作废。


三、省下的不是小钱

几个关键数字:

  • 命中缓存的部分,价格打一折。
  • 首次写入要多花 25%,但后面每次省 90%。
  • 默认存 5 分钟,5 分钟内有请求就自动续期。
  • 内容太短缓存不上,一般要 1024 个 token 起步,新模型要 4096。

举个实在的例子:十万字的长对话,不开缓存,Claude Sonnet 每轮要花 0.30 美金。开了缓存,首次 0.375,之后每轮只要 0.03。聊十轮,省下大约 90% 的输入成本。而且不光省钱——不用重算的部分越多,第一个字出来得越快,TTFT(首 token 时间)显著下降。

Anthropic 内部把缓存命中率当基础设施级别的指标在看,地位跟服务器在线率差不多。命中率一掉,触发值班告警,工程师得当线上事故处理。原文用的词是"宣布分级事故",走完整的事故响应流程。

为什么看得这么重?因为命中率高,不光省钱,还直接影响用户体验——它让 Anthropic 能给付费用户更宽松的使用额度。缓存命中率越高,你在同样的价格下,能用得越多。

对 Claude Code 这种 AI 编程助手来说,缓存不是锦上添花的优化。是整个系统能跑起来的前提。没有缓存,就没有 Claude Code。一个会话几十轮,每一轮都要把上文全带上重新发,每次都从头算,延迟和成本会爆炸。


四、排好队形:四层楼的书桌

既然缓存靠前缀匹配,那提示词里东西的排列顺序就至关重要了。

Anthropic 的最佳实践是这样排的——像收拾一张书桌:

最底层(第 1 层):系统指令 + 工具定义
这些是固定的,所有会话共享。就像常年不动的参考书。

第二层:项目文档(CLAUDE.md)
同一个项目内共享。像这周要看的资料。

第三层:当前会话的上下文
只在这一次对话里有效。像今天的工作备忘录。

最上层(第 4 层):聊天消息
逐轮增长,每轮只新增最后一条。像今天写的草稿。

一句话总结:越不容易变的东西,越往前放。

这样你每天坐下来才不用把整张桌子翻一遍。


五、三个大坑

这里有几个特别容易踩的坑,每一个都能让缓存链瞬间断裂。

坑一:在系统指令里嵌了当前时间

有些开发者喜欢在 SYSTEM_PROMPT 里写 Today is {datetime.now()}。想法很合理——让模型知道现在几点。但问题是,这个字段每秒都在变。每一次请求的"前缀"都不一样,缓存直接废掉。

正确的做法:别去改系统指令,把更新时间塞进下一轮的消息里——用 <system-reminder> 标签夹带进去。系统指令纹丝不动,缓存完好无损。

这是一个重要的分法:系统指令当地基,钉死不动;消息当流水,想怎么改怎么改。

坑二:工具定义用无序容器

如果你用 Python 的 dictset 来装工具定义,每次发请求时元素的顺序可能不一样。前缀对不上,缓存失效。

解决方案:始终保持工具定义的顺序稳定,用列表(list)而非集合(set)。

坑三:工具参数动了哪怕一个字段

你给某个工具加了一个新参数,或者改了一个字段的类型。哪怕只动一个字段,整条前缀的缓存全部失效。因为工具定义在第 1 层,它的任何变化会让后面所有内容重新计算。

一个小细节没注意,整条缓存链就断了。


六、反直觉:别换模型

这条对很多人来说有点反直觉。

你可能会想:简单问题切到小模型(比如 Haiku)省点钱,难题再切回大模型(比如 Opus)。多合理啊。

但现实是:缓存是跟模型绑定的。 换模型,等于之前积攒的所有缓存全部作废,从头重建。而重建的成本,往往比让大模型直接回答那个简单问题还要高。

所以 Claude Code 的策略是——主对话自始至终用同一个模型。

那需要小模型干活的时候怎么办?派子任务。

子任务有自己独立的上下文和缓存,不会污染主对话的缓存链。具体做法是:让主模型先写个"任务交接说明",把上下文浓缩好,然后传给子任务去执行,做完只把结果传回主对话。

打个比方:你不会为了省事让实习生坐到你工位上用你的电脑。而是给他分配一台独立的机器,把任务说明写清楚发过去,做完把结果发回来。

Claude Code 里的 Explore agents(探索模式)就是这样工作的——用小模型在独立的上下文里执行探索任务,做完只回结果。


七、Plan Mode:用工具说话,不动系统指令

Claude Code 有个"规划模式"。进入后模型只思考、只规划,不执行操作。

按直觉的做法:进规划模式就把执行类工具移走,退出来再加回来。但 Anthropic 没这么干——因为一动工具定义,缓存就断了。

他们的做法是:保留所有工具不动,另外加了两个特殊工具——"进入规划"和"退出规划"。

模型调用"进入规划"就切到思考模式,调用"退出规划"就回来。那"规划模式下不能执行"这个约束怎么传达?通过在对话中插入一条系统消息,告诉模型你现在在规划。

注意——是在对话流里插一条消息,不是去改系统指令。系统指令是固定的,在缓存前缀里;对话消息是流动的,不影响前缀。

这样工具集始终不变,缓存始终有效。而且还带来一个额外好处:模型可以自己判断什么时候进规划模式——遇到复杂任务,它自己先想清楚再动手,不用你手动切换。


八、Lazy Loading 与 Cache-Safe Forking

还有两个高级技巧值得一提。

Lazy Loading(延迟加载):不要在对话一开始就加载所有工具。把工具按场景分组,需要时再加载。这样前缀始终只包含当前需要的工具定义,更短、更稳定、更容易命中缓存。

Cache-Safe Forking(安全分叉缓存):当你需要对对话做压缩、摘要、或者开分支处理时,必须确保分叉后的请求和主对话共享相同的前缀——相同的模型、相同的系统指令、相同的工具定义。否则就是另起炉灶,缓存归零。


九、给"搞中转"的朋友提个醒

缓存是按账号隔离的。用账号池搞中转,命中率会过低,钱没赚到反而把号搞没了。还有教你咔咔切账号的,也要留意——别聊两句就来回切。


十、归根结底:先认死那条限制

回头看这七条经验,都在说同一件事——缓存就是前缀匹配。

  • 前缀匹配决定一切。前缀里任何位置的变化,都会让其后所有内容的缓存失效。
  • 用消息代替指令修改。
  • 不要在对话中途切换工具或模型。
  • 像监控在线率一样监控缓存命中率。
  • 分叉操作必须共享主对话的前缀。

所有的设计,都要围绕这一个约束来展开。别改指令,别动工具——一碰,整条缓存链就断。换模型、切账号、另起炉灶,同一个道理。

这看着像缓存优化。但讲的也是一种思路——先认死那条绕不开的限制,再围着它把整个系统搭起来。


本文基于 easy-learn-ai 项目 515b759 commit 新增的 Prompt Cache 交互式教学模块撰写。该项目以"演讲动画"的形式,用 15 个章节逐步讲解 Prompt Cache 的设计理念与最佳实践,灵感来自 Anthropic 工程师关于 Claude Code 提示词缓存设计的分享。

#easy-learn-ai #每日更新 #记忆 #小凯 #PromptCache #LLM #AIAgent #Anthropic #ClaudeCode

讨论回复

0 条回复

还没有人回复,快来发表你的看法吧!

推荐
智谱 GLM-5 已上线

我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。

领取 2000万 Tokens 通过邀请链接注册即可获得大礼包,期待和你一起在 BigModel 上畅享卓越模型能力
登录