聊模型上下文缓存这件事,我踩过的坑比想象中多。刚接触时我以为缓存就是个“省钱开关”,打开就完了。真正做下来才发现,不同厂商嘴里说的“缓存”压根不是一回事。有的人说的是把整段提示词存起来复用,有的人说的是推理过程中KV矩阵的临时存放,还有的人把向量检索里的语义匹配也叫缓存。这几个东西混在一起聊,对比就失去了意义。所以我打算先把这个概念的地基打牢,把边界划清楚,后面的命中率、成本、选型才有共同语言。
我自己的理解是,上下文缓存本质上解决的是“重复计算”的问题。同一段上下文被反复送进模型,系统如果能记住之前算过的东西,就不用从头再算一遍。但记住什么、记住多久、怎么判断“这段我见过”,不同机制的答案差别很大。有人只记前缀,有人连中间插进去的块也能复用,有人靠语义相似度来判断,有人靠精确的Token匹配。这些差异直接决定了后面每一项能力指标的走向。
1.1 上下文缓存的定义边界与能力构成
我习惯把上下文缓存拆成五个层次来看。最窄的是KV Cache,它是推理引擎内部的东西,把注意力计算里的键值矩阵留在显存里,主要服务于单次生成过程中的自回归解码。这东西对开发者基本透明,你调不调它都在那儿,但它决定了首Token时延和吞吐的上限。往外一层是Prompt Cache,也叫前缀缓存,它把一段稳定的提示词前缀对应的KV状态持久化下来,跨请求复用。这是目前云厂商宣传“上下文缓存”时最常见的所指。
再往外走,语义缓存是另一条路。它不关心Token是不是一模一样,而是把请求转向量,看语义上是否足够接近,接近就返回之前的结果。这条路在客服问答、FAQ场景里很实用,但它和精确前缀复用是两种哲学,混着比容易得出错误结论。分页缓存则更像操作系统里的内存分页,把长上下文切块管理,按需换入换出,主要解决显存装不下的问题。跨请求复用是一个结果性描述,前几种机制都可能带来跨请求的收益,它本身不算独立机制。
我见过不少人把“支持长上下文”和“有缓存能力”画等号。这两件事的耦合度其实很低。长上下文说的是窗口能塞多少Token,缓存说的是塞进去之后能不能少算一点。一个模型可以支持百万级窗口却没有任何跨请求缓存,也可以窗口只有几万但前缀缓存做得很精细。把这两个概念分开,是我做任何对比之前必须跟自己确认的第一件事。
1.2 大模型上下文缓存机制对比
自动前缀缓存是目前最省心的一类。你什么都不用做,系统自己检测请求之间的公共前缀,命中了就复用。OpenAI的自动缓存、Anthropic的提示词缓存(部分模式)都带有这个味道。它的好处是接入成本几乎为零,坏处是你对命中条件没有控制权,前缀稍微变动一个字符,后面的缓存全部作废。我遇到过在系统提示词开头加了个时间戳,结果命中率直接掉到零的情况,排查了半天才反应过来。
显式缓存则把控制权交还给开发者。你得主动声明哪一段要缓存,给它打标记,设定TTL。Anthropic的cache_control、Google Gemini的显式上下文缓存都属于这一类。这种机制适合前缀非常稳定、复用频率高的场景,比如固定的系统指令、大型知识库摘要、代码仓库的公共上下文。代价是你得自己设计缓存结构,写错了不会有人提醒你,账单会提醒你。
块级缓存和分页缓存更偏底层。块级缓存把上下文切成固定大小的块,按块做哈希和复用,前缀里插入变化内容时,后面的块还有机会命中。分页缓存则是为了解决显存碎片和长上下文换页,vLLM的PagedAttention是典型代表。语义缓存走的是向量相似度路线,GPTCache这类方案是代表,它适合答案容错率较高的场景。混合机制则是把前缀缓存和语义缓存叠在一起,先走精确匹配,不中再走向量召回。这几种机制的工作路径完全不同,放在一张表里比“命中率”是没有意义的,得先分清比的是哪一层。
1.3 能力对比的核心维度设计
做对比最怕维度选错。我一开始只看“有没有缓存”和“便不便宜”,结论非常粗糙。后来我逼着自己列了一张维度清单,每次对比都对着走一遍。命中条件是第一位的:是精确Token匹配,还是允许一定前缀差异,还是语义相似度阈值。这一项决定了你的业务能不能用上缓存,比价格重要得多。
缓存粒度是第二项。整段缓存、前缀缓存、块级缓存,粒度越细理论上复用机会越多,但管理开销和实现复杂度也上去了。TTL和容量要一起看,TTL太短命中率上不去,太长又可能返回过期内容,容量则决定了你能同时养多少条缓存。模型覆盖这一项经常被忽略,同一个平台不同模型支持的缓存能力可能完全不同,旗舰模型有、轻量模型没有,是很常见的情况。
API易用性听起来软,实际影响很大。有的平台加一行参数就能开缓存,有的要改请求结构、维护缓存ID、处理失效回调。隔离性是安全维度,多租户环境下缓存会不会串,缓存键怎么设计,这些在合规审查时会被问到。计费规则更是五花八门,有的按缓存写入Token收费,有的按存储时长收费,有的命中Token打折但不收写入费。不把这些维度拆开,所谓“能力对比”就只是营销话术的搬运。
1.4 代表性模型与平台的上下文缓存能力矩阵初览
我手上这份矩阵是动态更新的,因为各家迭代太快。粗略来看,OpenAI走的是自动前缀缓存路线,命中后输入Token有折扣,开发者无需声明,适合提示词结构稳定的通用场景。Anthropic提供显式缓存标记,支持自定义TTL,对长系统提示词和文档问答比较友好,控制粒度更细。Google Gemini同时提供显式和隐式两种上下文缓存,显式模式需要创建缓存对象,适合大批量重复查询。
开源侧,vLLM的自动前缀缓存和PagedAttention组合,是自建推理服务时绕不开的选项,灵活性高但运维成本也高。GPTCache这类语义缓存方案适合做应用层加速,和模型厂商的缓存不是替代关系,而是叠加关系。国内几家云厂商近一年也陆续上了前缀缓存能力,计费口径和命中判定各有差异,我在矩阵里单独列了一栏“命中判定方式”,就是被这些差异逼出来的。
这张矩阵我不建议任何人直接照抄。模型版本一更新,计费规则一调整,矩阵就过期。它的价值在于提供一个检查清单,让你在评估新平台时知道该问哪些问题,而不是给你一个现成答案。适用场景和限制条件这两列,我写得比能力项还细,因为限制条件往往才是选型时真正卡脖子的地方。
1.5 机制对比中的常见误区
第一个误区是把缓存能力当成上下文扩展能力。前面提过,这两件事没有必然联系。一个平台缓存做得好,不代表它能处理更长的文档;反过来,窗口很大的模型也可能完全没有跨请求复用。我在早期方案里就犯过这个错,选了个长窗口模型以为能顺带解决成本问题,结果每次请求都在全量重算。
第二个误区是把缓存等同于语义记忆。缓存是有生命周期的、基于匹配的、无状态的复用,它不会理解内容,也不会主动遗忘或归纳。语义记忆是另一套东西,涉及持久化、检索、更新策略。把缓存当成“模型记住了我说过的话”,在产品设计上会做出错误预期。第三个误区是只看命中率不看命中质量,语义缓存命中了一个相似但答案不同的请求,省了钱却答错了题,这种账不能只算成本侧。机制对比的意义,是让你知道自己到底在比什么,而不是比出一个“谁更强”的口号。
我最早算缓存这笔账的时候,脑子里只有“命中率越高越省钱”这一条线。后来跟几个做推理服务的朋友聊,发现自己漏了太多变量。命中率这个数字本身含义就很暧昧,你说的是请求级命中还是Token级命中,差出去可能是一个数量级的成本差异。更别说不同机制的命中判定逻辑完全不同,拿显式缓存和自动前缀缓存比命中率,就像拿短跑成绩去评价马拉松选手。
这一章我想把命中率和成本这条链路拆开看。从怎么测、什么因素在影响它,到命中之后成本到底怎么算,再到不同业务场景下这笔账长什么样,最后聊聊什么时候该为了节省成本去卷命中率、什么时候不该。这些结论我自己也是踩了坑才慢慢摸清楚的,直接照着公式套用容易翻车。
2.1 上下文缓存命中率的定义与测量口径
我见过最模糊的说法是“我们缓存命中率挺高的”,问到具体口径就开始打太极。命中率起码有四个层次要分开看。请求级命中是说一次API调用里只要有一部分缓存命中就算数,这个指标看起来漂亮,但对成本几乎没有指导意义,因为命中的那部分可能只占整个上下文的百分之几。Token级命中才是成本视角真正关心的,命中的Token数除以总输入Token数,这个数字才能换算成钱。
再往下还有两个细分口径。前缀复用率更偏向机制层面,算的是请求之间公共前缀的实际复用比例,适合评估自动前缀缓存在你的业务负载上到底能起多大作用。多轮会话复用率是我在做客服项目时自己定义的一个指标,专门看同一会话里历史上下文被复用的比例。这几个口径混着用,做出来的对比结论基本没法互相对照。我现在做任何评估都会先问一句“你这个命中率是哪个口径”,对方答不上来,后面的数字我就不怎么信了。
测量方法本身也有讲究。离线回放能拿到最干净的Token级数据,但回放顺序和真实请求分布可能有偏差,尤其是多租户的线上系统,缓存条目的竞争关系在回放里复现不出来。线上打点更真实,麻烦在于你得在每次请求里记录命中Token数、缓存写入量、TTL剩余时间这些字段,有些平台的API根本不返回细粒度数据,只能靠输入Token减去计费Token的差值去反推,精度有限。我自己习惯两套数据都留着,离线回放看趋势,线上打点看异常,偏信哪一边都容易误判。
2.2 缓存机制差异对命中率的影响路径
显式缓存和自动缓存的命中率曲线长得完全不一样。自动前缀缓存是我什么都别管,系统自己找公共前缀,这种情况下命中率高度依赖你提示词结构的稳定性。前缀里有个时间戳、有个用户ID、有个随机排序的few-shot示例,整个前缀就废了。显式缓存是我主动声明哪段要缓存,命中条件由我定,理论上可以把命中率做得更高,代价是我得持续维护缓存结构,业务一变缓存策略就得跟着调。
前缀稳定性是影响命中率最直接的一个因素。我自己做过一个实验,同一套系统提示词,一版把动态变量放在最前面,一版挪到最后,Token级命中率差了将近四十个百分点。这个数字当时把我惊到了,后来想想很合理,前缀缓存是全有或全无的逻辑,前面一变,后面全完。这也是为什么我现在写提示词都习惯把稳定内容往前压、变化内容往后放,哪怕平台支持块级缓存,这个结构习惯也能多兜一层底。
分块策略和TTL是另外两个杠杆。块级缓存能在前缀中间发生变化时保住后面的块,命中率比纯前缀缓存更稳,尤其是多轮对话里中间插入工具返回结果的场景。TTL设置更像一个旋钮,调短了缓存还没被复用就过期,调长了内存占用上去,而且过期内容被命中的风险也在。我一般先按业务请求间隔的分布来定TTL,集中在一个时间窗口内的重复请求多,TTL就跟着这个窗口走。路由负载均衡这一项经常被忽略,同一个前缀的请求被分发到不同推理实例上,各自的缓存互不可见,命中率会被硬生生打散,做推理集群的时候得把路由亲和性一起设计进去。
2.3 上下文缓存命中率对推理成本影响
成本这块我想把公式列清楚,不然讨论容易飘。一次请求的总成本可以粗略拆成四块:未命中Token的单价乘上未命中Token数,缓存命中Token的折扣单价乘上命中Token数,缓存写入费用(有些平台按写入Token收,有些按存储时长收),加上存储占用带来的固定成本。命中率提升之所以省钱,是因为它把Token从第一项挪到了第二项,两个单价之间的折扣比例就是省下来的空间。有些平台命中Token单价是未命中的十分之一,那命中率从零提到八成,输入侧成本能砍掉七成以上,这个账很直观。
麻烦的是缓存写入和存储费用这一项经常被漏算。显式缓存要建缓存对象,有的平台对写入单独收费,写入成本摊到每个命中请求上可能并不便宜。存储费用更隐蔽,缓存条目维护在那里,哪怕没被命中也在占资源。我见过一个团队把TTL设得特别长,命中率数字很好看,月底一算存储费用把省下的推理成本吃掉了一大半。所以我现在看任何缓存方案,都要求对方把这三项费用都列出来,只看命中折扣的报价单是不完整的。
还有一个反直觉的点,命中率不是越高越省。语义缓存这条路线特别容易出这个问题,相似度阈值调低,命中率上去了,但命中返回的答案是给另一个问题准备的,用户不满意重新问一遍,这一来一回的成本比老老实实算一次高得多。我现在评估缓存经济性会同时看命中带来的节省和缓存误命中带来的返工成本,两个数放在一起看,才能判断这个命中率是不是“有效的”。
2.4 场景化成本测算
长文档问答这个场景,缓存收益非常明显。一份上百页的合同或者技术手册被反复提问,前缀部分几乎完全一致,自动前缀缓存的Token级命中率可以做到很高。我做过一个内部测算,同一份文档被问二十个问题,开缓存之后输入成本降了大概六成多。这种场景的关键是文档内容要放在提示词前部,问题放在尾部,结构上天然适合前缀复用。
代码助手是另一种情况。代码仓库的公共上下文、项目规范、依赖清单这些内容复用频率很高,显式缓存把这一大块锁住,每次补全只需要传当前文件片段。命中率不如长文档问答那么夸张,因为不同文件的请求前缀差异较大,但单位请求的成本下降依然可观。多轮客服场景的特点是会话语义缓存更合适,相似问题高频出现,向量召回能覆盖相当一部分请求,不过得把答案时效性和误命中风险一起考虑进去。
RAG检索增强和Agent工具调用这两个场景,缓存收益容易被高估。RAG每次检索回来的文档片段顺序和内容都在变,前缀稳定性很差,自动缓存的命中率经常不理想。我在这类项目里更倾向于把固定的系统指令和输出格式约束做成显式缓存,检索结果部分不指望命中。Agent工具调用更麻烦,工具返回结果插入上下文中间,把后面的内容全打乱了,纯前缀缓存基本用不上,得靠块级缓存或者干脆接受低命中率。场景不同,同一个命中率数字背后的经济意义可以差很远。
2.5 命中率、成本、时延与吞吐的权衡
我在内部推缓存方案时,被人问过最多的一个问题是“命中率要到多少才值得上”。这个问题没有通用答案,但我自己会算一个临界命中率:缓存带来的节省等于缓存引入的写入和存储成本时的那个命中率。低于这个线,上缓存是负收益。这个临界值跟平台计费规则强相关,有的平台写入费用低、存储便宜,临界线可能在两成左右;有的平台写入贵,临界线会抬到四成甚至更高。算清楚这个数,比笼统讨论“命中率高不高”有用得多。
时延和吞吐是另外两个维度。缓存命中通常能让首Token时延明显下降,因为省掉了一部分预填充计算,这个收益在交互式场景里往往比省下的钱更值钱。吞吐方面,缓存把计算资源释放出来,同样的硬件能扛更多并发。我遇到过的权衡是,为了追求高命中率把TTL拉长、把缓存粒度做细,缓存管理的开销和内存占用上去了,吞吐反而被拖下来。这个平衡点得靠压测去找,拍脑袋定参数不太靠谱。
ROI评估这个动作我现在会放在项目启动前做,而不是事后复盘才想起来。把业务请求的间隔分布、前缀重复特征、平台计费规则和SLA要求放在一起,能估出一个大概的经济性区间。缓存失效策略也是这里面的一个变量,全量失效简单粗暴但命中率会周期性地掉下来,增量失效精细一些但实现复杂。经济性边界不是一个固定数字,是跟着业务负载和平台规则一直在动的,隔一个季度重新算一次比较稳妥。
上一章把命中率和成本这笔账算了一遍。算账是一回事,真到选型那一步,手里拿着几家平台的报价单,我还是会犯难。机制参数表看起来都差不多,真跑起来差距能拉出好几倍。这一章我想聊聊我自己做缓存能力对比时的实际动作,从业务需求对齐到评测方案设计,再到具体的优化手段和选型清单。踩过的坑比较多,写出来给大家少走点弯路。
3.1 业务需求到缓存能力映射
我做选型的第一个动作不是打开平台的文档,是拿一张白纸把业务写清楚。请求长什么样、上下文从哪来、哪些部分每次请求都一样、哪些每次都在变、请求间隔的分布大概是什么形态。这几句话答不上来,后面看任何平台的参数表都是瞎看。我见过团队一上来就研究各家的块大小和TTL上限,研究了两周,回头发现自己业务的上下文每次请求都在变,缓存结构根本立不住。
场景画像做完,才轮到跟能力对齐。长文档问答和代码助手这类上下文高度稳定的业务,自动前缀缓存就能拿到不错的收益,选型时重点看模型覆盖和计费透明度。多轮客服和多租户SaaS这类业务,隔离性和数据边界是硬约束,某些平台不支持租户级缓存隔离,功能做得再好也只能出局。SLA这块我主要盯时延敏感度,交互式场景里首Token时延的改善往往比省下的那点钱更值钱,批处理场景就无所谓,成本优先。
隐私合规是我现在会单独拎出来过一遍的。缓存数据能不能落盘、能不能跨租户复用、缓存条目的保留周期和销毁机制,这些问题在选型阶段问清楚,比上线之后被安全团队叫停强得多。我碰到过一个项目,方案都定了,安全评审时发现缓存条目跨会话可见,整个架构推倒重来。成本目标和模型选型约束这两项要放在一起看,有时候便宜的缓存方案绑定的是一个能力不够的模型,硬换过去损失的推理质量远大于省下的成本。
3.2 对比评测方案设计
评测方案我一般分两段走。离线回放负责把候选名单从五六家缩到两三家,用真实流量日志按原始顺序回放,记录每次请求的命中Token数、缓存写入量、时延和计费Token的差值。在线A/B只留两三个方案做灰度,跑够样本量再下结论。离线回放的局限我上一章提过,多租户系统的缓存条目竞争关系在回放里复现不出来,所以离线的结论只能当趋势看,不能当定论。
指标设计上我吃过只看均值的亏。均值好看不代表用户体验好,P95时延才反映尾部情况,尤其是缓存未命中集中出现的那种毛刺。命中率必须带着口径一起报,请求级和Token级的数字放在同一张表里,做决策的人很容易误读。单位请求成本这个指标我建议按场景分开算,把所有请求平均在一起会掩盖掉长尾场景的亏损。
缓存污染监测是很多评测方案里缺失的一块。我现在的做法是埋探针,定期构造一批已知答案的请求,看缓存返回的结果对不对。语义缓存尤其需要这个,相似度阈值调松之后,错误命中在日志里根本看不出来,用户也不会每次都投诉,只是在悄悄流失。显式缓存的污染更多来自内容陈旧,业务规则改了缓存没失效,返回的还是旧答案,这类问题得靠版本戳和失效通知来兜。
3.3 提升命中率与降低推理成本的优化策略
优化策略按投入产出排个序,最便宜的永远是改提示词结构。稳定内容放前面,动态变量往后挪,这个动作不需要任何平台支持,改完命中率就能涨一截。我接手过一个系统,系统提示开头塞了用户ID和当前时间戳,这种写法令任何前缀缓存都失效,把这两个字段挪到末尾之后,Token级命中率从一成多涨到六成。
前缀复用要做到位,得把系统提示、工具定义、少样本示例这些内容当成固定资产来管理。版本化、变更走评审、改一次评估一次对命中率的影响。我自己维护了一个提示词变更记录表,每次改动标注影响的业务线,出问题的时候回溯很快。分层缓存是架构层面的事,系统级、租户级、会话级分开存,各自的TTL和失效策略都不一样,混在一起存会互相挤占容量。
TTL和容量调优得靠压测,不能拍脑袋。我一般先按请求间隔分布的P50定一个起点,往上试到命中率增长趋缓的位置,再结合存储费用的曲线找拐点。路由亲和这一条在多实例部署时特别关键,同一个前缀的请求被负载均衡打散到不同实例,各自的缓存互不可见,命中率直接归零。网关层做一致性哈希或者按租户粘性路由,这个改动不大但收益非常直接。
3.4 模型与平台选型决策清单
选型清单我用的是一个加权评分卡,维度包括命中条件匹配度、计费透明度、API易用性、模型能力覆盖、隔离能力、可观测性、供应商稳定性。权重按业务调,金融类项目里隔离性和合规审计的权重会拉到很高,创业团队跑的轻量应用里API易用性和上手速度更重要。评分卡的作用不是给出一个绝对排名,是把讨论从感觉拉到台面上,每个维度的分数都要有依据。
成本模型要用上一章那套公式算全,写入费用、存储费用、命中折扣一个都不能漏。报价单上只写命中Token单价的那种,看着便宜,实际用起来写入和存储能把省下的吃回去大半。我习惯按三个业务场景各算一遍月度成本,再乘上一个安全系数,因为线上流量的分布通常比测试集更离散。
风险项里供应商锁定和计费规则变更这两项最难量化。评分卡上分数接近的时候,我会优先选计费规则写得更明确、变更需要提前公告的那家,至少未来涨价有预期。迁移成本容易被低估,缓存结构和业务代码耦合深了之后,换平台不是改个API地址的事,提示词结构、失效逻辑、监控打点全都要跟着动。我一般会在方案里单独列一行迁移预估工时,让决策的人看到这项成本。
3.5 趋势与治理
缓存标准化这事我持谨慎态度。现在各家对缓存的命名、定义、计费口径差异很大,“上下文缓存”这四个字在不同平台指的东西能差出好几层。短期内指望行业统一标准不太现实,比较务实的做法是内部先立规范:缓存策略怎么声明、命中率按什么口径打点、成本怎么归因到业务线,用自己的口径把各家平台的数据拉齐,横向对比才有意义。
隐私安全得从设计阶段就进。缓存条目里可能有用户输入、检索结果、工具返回值,生命周期、脱敏规则、跨租户隔离这些要在架构图上画出来。缓存服务的日志本身也是数据资产,访问权限和留存周期都得管起来,这块容易被当成纯技术问题忽略掉。
可观测性是我觉得最值得持续投入的一项。命中率、写入量、存储占用、误命中率这些指标按业务线持续打点,积累几个月之后,成本归因和容量规划都有据可依。持续优化机制说白了就是定期复盘,业务负载会变,平台计费规则也会变,一个季度重新算一次账、重新跑一轮小规模评测,比做完选型就撒手不管靠谱得多。我现在每个季度会花半天时间把这条链路从头过一遍,收益比想象中高。