这些天,DeepSeek 以它牛逼的缓存机制和低到离谱的价格,给所有 AI 玩家们上了一课。
一时间,所有人开始重新审视这个原来一直被忽略的东西——缓存。
甚至引发了一款产品的现象级火爆,也就是 reasonix。它号称能够最大化地利用 deepseek 的缓存,吸引了一大批的羊毛党。
这套缓存机制的名称叫KV 缓存,也叫前缀缓存。
所有基于 Transformer 结构的模型,都有这套缓存机制。
本篇讲几件事:它是什么、各家模型厂商是如何对待它的,以及上下文怎么组织才能最大化利用缓存。
没错,这也属于上下文工程的一环。
一、原理:模型是怎么读题的
先说模型那边发生了什么。不用展开论文,知道个大概就够——因为后面所有"摆放技巧",都是从这个原理里长出来的。
读题和作答
大模型生成回答,不是一口气写一整段,而是一个字一个字往外蹦。每蹦一个字,都要把前面所有内容重读一遍,这叫自回归。
这个"重读",工程上分两段:
- 读题(Prefill):把你发来的整段上下文过一遍网络——最贵的一步,也是钱花得最多的地方;
- 作答(Decode):然后一个一个吐字,每吐一个新字,只处理这一个字。
往深一层看:网络有几十层,每一层里,模型都会给每个字算三样东西——Query("这个字想找什么")、Key("这个字带了什么标签")、Value("这个字实际携带什么信息")。拿当前字的 Q 去和前面所有字的 K 比对,算出"该关注谁";再按权重把各字的 V 揉到一起——这一步,就是"读懂了上下文"。几十层叠起来,就是整个"读题"的过程。
关键点来了:一个字的 K 和 V,只由它前面的内容决定,跟后面要生成什么毫无关系。也就是说——同一个字,不管后面接什么,它的 K、V 永远是同一份。
算过的,不必再算
既然固定,就不必重算,存下来反复用。这就是 KV 缓存:把"读过的题"记住。
而你每一轮发出去的消息里,前面绝大部分都跟上一轮一模一样——服务端一看:"这段我读过",直接跳过重读。这就是前缀缓存省钱的原理。
不过这里要澄清一个很容易想歪的地方:缓存住的是各层算出的 K / V——它们只是"读题"环节的中间产物。缓存省掉的,是"重复读题"的开销;但这一轮要算出什么字,后面的计算一步都不会少——注意力照跑、前馈照过、最后还得采样挑字。缓存不替模型做任何决定,它只是让"读过的部分不再重读"。可光是这一项,就够把账单打下来了——Agent 的场景里,前缀重复度太高了。
省多少?读 1000 个字、写 1000 个字:没有缓存,大约是 1000 × 1000 的活;有缓存,是 1000 + 1000。平方级变成线性级——数量级的差别。
顺带回答一个常见疑问:改 temperature 会让缓存失效吗?不会。因为缓存里没有"答案"这回事——它存的只是"读题的笔记";temperature 管的是"作答时怎么挑字"。笔记复用,不影响这道题怎么写。
二、铁律:只能从头开始比对
前缀缓存有个脾气:它不是"内容寻址"——不是你发来一段东西,它帮你翻翻哪部分存过;它是序列寻址:从第一个 token 开始,逐字比对,对到哪算哪。
一旦有某个字符对不上——从断点往后,全部重算。
看两种情形:
- 系统提示词、工具定义、历史全都和上一轮一致,只在末尾多了新问题——前缀全命中,一分钱不白花;
- 历史里改了一个字——从那个字往后,全部重算,哪怕改的只是一个标点。
为什么这么苛刻?因为 K 里记着"我排在第几位",而且每一层的 K 都建立在上一层的输出上——开头变一个字,几十层叠下去,层层都对不上。
这条铁律推出一个非常实用的结论:唯一"零成本"的操作,是往末尾追加;而且,改动越靠后,代价越小——改在末尾接近免费,改在中间赔上后面全部,改在最开头就是全军覆没。
中间插入?开头修改?重写历史?——都要付"从头重算"的代价。
三、门道:各家怎么对待缓存
这份便宜,主流服务商现在都在卖——但姿势和底细各不相同。一家一家看(价格都按每百万 token 计):
- OpenAI:全自动。GPT-5.4 的标准输入 $2.5、命中缓存的输入 $0.25——直接一折;门槛是共享前缀至少 1024 token。缓存住显存,不活跃几分钟就被挤掉,也不跨实例;
- Anthropic:要显式打点——用
cache_control划出缓存边界。Claude Opus 4.6:输入 $5、缓存写入 $6.25(1.25 倍)、缓存读取 $0.5——十分之一;默认 5 分钟有效、命中自动续期,1 小时版本写入价翻倍。缓存也在显存里,同样不跨实例; - DeepSeek:全自动,两档价:v4-flash 未命中 $0.22、命中 $0.007——差三十倍,且不收缓存写入费。缓存写进分布式硬盘阵列——寿命拉到几小时到几天;存储天然共享,不存在"打回哪台机器"的问题;
- Gemini:显式建"缓存对象"。Gemini 3 Pro:读取 $0.2,对 $2 的标准输入同样是一折;但存储要另算——$4.5/百万/小时,生命周期由你划定。
合起来看,两个数字就记住了:读缓存基本都是一折上下,写缓存(Anthropic、Gemini 这种显式模式)付一点点"入场费";还有一条:输出 token 从不打折——缓存省的是"重复读题"的钱,写答案的钱一分不少。
价格之外,还有一层更底层的分水岭:缓存到底放在哪儿——显存的(OpenAI、Anthropic)活得短、不跨实例;硬盘的(DeepSeek)活得久、天然共享。这个差别不小,它决定你要不要为它多做一层设计(比如下一章要讲的"会话粘住实例")。
先算一笔小账:如果你的系统提示加工具定义有 1 万 token,一天跑 5000 次请求——不缓存,这同一段内容,你要付 5000 遍钱;缓存之后,大部分请求走很低的"读取价",只有写入那一下贵一点。高频跑上几天,省下的绝不是零头。
但别光看折扣。缓存是尽力而为的:不保证 100% 命中,有效期通常只有几小时,还可能因为服务端内存吃紧被挤掉。所以有一条纪律——所有"为缓存做的优化",都要留好降级路径:命中了是赚的;没命中,请求也得照常发出去。
四、编排:稳定的往前放
原理和计价都清楚了,接下来是最有用的一章:上下文怎么摆,才能一直命中。
一条总原则
原则只有一条:稳定的往前放,变化的往后放。
因为前缀是"从头往下比"的——越靠前的内容,越要经得起对比。把最稳定的内容供在最前面,共享前缀才最长;把每轮都变的东西推到末尾,它们就不会连累任何缓存。
按稳定度排下来,一份请求长这样:
- 系统提示词——永远别动,收益最大;
- 工具定义——别动,连顺序都别动;
- 老历史——可能被摘要重写,属于"不可避免的变动";
- 新历史——可能被压缩改写;
- 当前问题——每轮都变,但它在末尾,无害。
再记一张"影响清单",以后就不会踩坑:
- 影响缓存的:消息的内容与顺序(决定性的);工具定义本身;工具定义的顺序;system 消息的位置;
- 不影响缓存的:
max_tokens、temperature——它们是生成参数,不进输入的 token 序列。
五个招式
道理不复杂,难的是每个细节都踩对。下面这五招,都是真金白银换来的:
- 系统提示词保持常量。别注入时间戳、用户名、随机 ID。最经典的坑:把"当前时间"加进系统提示——听着很有用,实则每次请求的第一个 token 就变了,命中率归零;
- 工具定义稳定排序。在遍历顺序随机的语言里(比如 Go 的 map),每次序列化出来的工具顺序都可能不同——顺序一乱,token 序列整体偏移,缓存永远对不上。解法很笨但有效:排序;
- 压缩摘要时,复用原请求的前缀。比如"该总结了"——别让摘要请求自己渲染一份"原文历史",而是克隆主请求的消息和工具定义,只在末尾追加一句总结指令:前缀与主请求完全一致,直接命中。反直觉的细节:连工具定义都要原样带上,哪怕这次根本不调工具——少带一段,序列就错位了。代价嘛,提示词里补一句"不要调用工具"就行;
- 运行时内容别拼进系统提示词,而是作为用户消息(或工具结果)拼在后边。两个真实案例:
- 技能(skill)正文:原先追加进系统提示——每加载、卸载一次技能,整段前缀缓存作废;改成使用专门的 load skill 工具加载进来,只在末尾追加,前缀纹丝不动,再配一个压缩白名单,保证它不会因为工具结果过长而被压掉;
- 压缩后的摘要也一样:原先塞进系统提示,摘要一更新缓存就废;改并入用户消息侧,系统提示从此稳如泰山。
- 会话粘住同一个实例。缓存不跨实例的时候,路由就不能乱跳——跳一次,前缀再稳也白搭。所以会话 id 得固定:一个会话一个 id,从生到死不变,每轮请求原样带上(
Venus-Session-Id这类)。路由怎么选,是平台的事;你要做的,就是别把标识传丢。实测:命中率 78% 冲到 92.44%,Input 成本直降 45%。
最后再带一个习惯:把命中率当指标看。主流服务商的响应里都带着"这轮读了多少缓存、写了多少缓存"的字段——算得出命中率,才谈得上优化它。别闷头摆,抬头看数。
五、稳定
在计算机领域,缓存这个事的道理一直很朴素:稳定的东西、没变的东西,不用反复付钱。
不过,缓存是平台应该提供的底层能力,命中率却是工程成果。工程做得不好,还是得花冤枉钱。
稳定的往前放,变化的往后放。,在 Agent 开发领域,记住这一句已经能省很多钱了。