跳到正文
AI 知识地图 0.18 · 2026-07-30
关于与纠错文字目录 / Search
理解原理

提示缓存:复用共同前缀的 KV 计算

从最长共同 token 前缀、KV 占用与命中价值,到提示排序、路由亲和、失效和租户隔离。

核心命题 提示缓存跨请求复用相同 token 前缀在模型各层产生的 KV 状态,减少重复预填充。它不缓存最终答案,也不减少新后缀和输出解码;净收益由命中长度 × 复用频率 × 预填充成本 − 查找/搬运/驻留代价决定。
读完你应该能:区分请求内与跨请求 KV cache;计算最长共同前缀和收益;设计缓存友好提示布局;处理容量、失效与隐私隔离。
  1. 测量 prefill 占比与重复前缀
  2. 按稳定性和权限重排上下文
  3. 用配置/租户/token 前缀构建键
  4. 价值感知存储与路由命中
  5. 版本变化原子失效
  6. 用命中长度/TTFT/显存/质量联合验收

1重复计算发生在输入预填充直觉

每一轮 Agent 对话都携带几乎相同的系统规则和工具 schema,如果每轮都让 GPU 从头处理一遍这些输入,计算就浪费在完全相同的内容上。要看清浪费发生在哪里,需要先拆开自回归服务的处理过程:它先并行处理全部输入 token,为每一层生成对应的 K/V 中间张量,这一步称为预填充;随后再逐 token 生成输出,称为解码。相邻请求之间往往共享系统提示、工具定义和对话早期的历史,这些 token 序列逐字相同,但默认实现仍然为每个新请求重新计算一遍它们的 K/V。

跨请求前缀缓存针对的正是这部分重复计算:把某个请求已经算好的中间张量保存下来,当新请求到来时,先查找它的输入与哪个已保存前缀一致,找到后直接从共同前缀的末尾继续预填充,只为新增的后缀 token 计算 K/V。于是重复部分只需计算一次,后续请求全部复用。

缓存里存的不是自然语言答案的存档,也不是语义检索的结果索引。它只对特定模型、特定 tokenizer、特定权重(含适配器)和特定位置配置下的确切 token 前缀有效:换一个模型版本、换一种分词方式,甚至同一串文字被切成不同的 token 序列,缓存都不能直接复用。

主要收益集中在输入侧:减少重复的输入计算量、降低首 token 延迟(TTFT)、把原本被重复预填充占用的吞吐释放给新请求。边界同样明确:被省略的只是输入预填充,长输出的逐 token 解码过程完全不变,仍然一个 token 一个 token 地生成,输出部分不存在“缓存加速”。

从输入输出关系看:提示缓存的输入是模型配置和多个请求共享的精确 token 前缀,输出是可以被后续请求复用的中间 KV 状态。服务端的处理顺序是——先查找最长可用的已缓存前缀,再只为新后缀计算。一次“命中”只表示省掉了部分输入计算,不表示答案被缓存过,也不保证输出一定正确。它只适用于模型、tokenizer、位置配置和安全域一致的请求;任何一个维度不一致,缓存都应视为不可用。

2三种缓存不要混淆消歧

“缓存”在提示处理系统里至少指代四类彼此不同的机制:请求内 KV cache、跨请求前缀缓存、响应(语义)缓存和应用数据缓存。它们被混用同一个“缓存命中率”数字是危险的,因为后两类保存的已经不是纯计算状态,而是可能陈旧或越权的内容。要区分它们,只需要回答三个问题:保存的对象是什么、在什么范围内复用、跳过了哪一个计算阶段。把这三个问题的答案作为分类输入,输出就落在四类之一。

请求内 KV cache 保存的是同一次生成过程中已经计算过的历史 token 的键值状态,复用范围严格限于当前序列本身,命中条件就是这些状态属于正在解码的这个序列,改变的是逐 token 解码阶段。它是最纯粹的算力复用:后续每个 token 解码时不再对整个前缀重新计算,而且被保存、被复用的东西从未离开这次请求,不携带任何跨请求的语义。

跨请求前缀缓存保存的是不同请求共同开头部分对应的输入状态,复用范围跨请求,键由模型加上精确的 token 前缀构成,改变的是输入预填充阶段。它复用的仍然是计算状态,只是把“本次已经算过”推广为“上一次请求算过、且本次开头逐 token 一致”。命中与否在答案产生之前就由前缀是否一致决定,因此不引入内容层面的正确性问题。

响应缓存,也叫语义缓存,保存的是相同或近似问题的最终答案,键由请求本身或其语义表示加上版本构成,跳过的可能是部分或全部生成阶段。应用数据缓存保存的是检索结果或工具调用结果,键由查询加上权限和新鲜度约束构成,跳过的阶段位于外部组件。这两类的共同点是:保存和复用的对象变成了“内容”。当问题语义近似但提问者不同、权限不同,或者外部数据已经变化时,直接返回缓存内容就可能给出陈旧或越权的答案,正确性风险远高于前两类的纯计算状态复用。

正因为如此,这四种机制不能共享同一个命中率口径:前缀缓存命中意味着省下了一批预填充计算,而语义缓存命中意味着直接返回了一个旧答案,两者的收益和风险含义完全相反。判断一个具体缓存属于哪类,就看它复用的是什么——当前生成历史、共同输入状态、最终答案还是工具结果。据此可以解释它的收益来自哪里,也能说清它的正确性边界。

机制复用范围键/条件改变的阶段
请求内 KV cache同一次生成历史 token当前序列逐 token 解码
跨请求前缀缓存不同请求共同开头模型+精确 token 前缀输入预填充
响应/语义缓存相同或近似问题答案请求/语义+版本跳过部分或全部生成
应用数据缓存检索/工具结果查询+权限+新鲜度外部组件

3只有连续共同 token 前缀可直接复用机制

前缀缓存能够复用多少,取决于两条 token 序列从第一个 token 起连续相同的长度,也就是最长共同前缀(LCP)。给两条 token 序列 A、B,LCP 的输出是长度 ℓ,表示从首 token 开始逐位相同的连续 token 数。系统按 token 逐个比较,遇到第一次分叉就停止,分叉点之后的 KV 不能直接复用。这解释了为什么两份包含同一份 8000 token 文档的提示,只要顺序不同,命中率就可能为零:因果注意力中位置 i 的表示依赖此前全部 token,文档换个位置,后续每个位置的输入上下文都变了,整条 KV 链从分叉处起全部失效。

共同前缀必须精确到 token,而不是语义。语义相同不代表 token 相同:JSON 字段顺序、空格、Unicode 规范化、模板版本和工具排序中的任何差异,都会改变 token 序列,从而缩短甚至抹掉共同前缀。一些基于 radix-tree 的系统可以在大量已存前缀中寻找最长命中,让缓存不必一对一匹配整条提示,但搜索的目标仍然是“从首 token 起精确相同的前缀”这一条件,命中规则没有改变。

这条规则直接决定了提示布局:不要把动态值放在最前。请求 ID、当前时间或用户问题一旦出现在开头,后面所有稳定内容——系统指令、工具定义、知识文档——都会因为前缀被打断而失去复用。把静态内容前置、动态内容后置,是把共同前缀做长的基本手段。

需要注意,LCP 长只说明计算状态可以复用,并不说明两份提示语义更相近。两条截然不同的问题可以共享很长的公共前缀(例如相同的系统提示部分),而两条语义几乎相同的问题可能因为一处 token 差异而命中归零。任何影响 token、位置或模型状态的变化——改一个字符、插入一行、换模型版本——都会在对应位置终止命中。

LCP(A,B)=max{A1:=B1:}

4运行示例:12k 输入里究竟省了多少逐步演算

用一个 12k token 的典型请求可以看清布局与收益估算的全过程。假设提示由五段组成:系统规则 2k、工具定义 3k、共享政策 5k、会话历史 1k、当前问题 1k。如果不做任何布局,动态内容可能夹在中间或顶在开头,共同前缀会被截断;按稳定性排序之后,大段共享内容在前,动态历史与问题在后,最长共同前缀才有机会达到 10k——于是 12k token 的提示被拆成 10k 的缓存命中区与 2k 的新后缀。

节省量的核心公式是期望避免处理的输入 token 数,即命中率 h 乘以命中长度 L。h 是请求能命中前缀的比例,L 是命中的 token 长度;两者相乘得到平均避免量。这个公式要求先按稳定性排布出足够长的 L,再用命中率 h 做加权——只谈命中率不谈命中长度,或者只谈前缀最长值不谈实际命中比例,都会高估或低估收益。

延迟收益可以用同一组假设估算。无缓存时预填充占 TTFT 的 600ms;命中后 10k/12k 的预填充计算被省掉,但要付出 60ms 的缓存查找与搬运成本。单个命中请求的粗略节省是 600×(10/12)−60=440ms:先按命中长度占输入比例换算省下的预填充时间,再扣除缓存本身的固定开销。再叠加命中率,全流量的期望节省约 440×70%=308ms。平均节省的 token 数按同一逻辑为 10k×70%=7k。

这里的 440ms 与 308ms 都是给定假设下的估算:预填充 600ms、命中长度 10k、命中率 70%、查找搬运 60ms。真实注意力计算成本随长度非线性增长,且查找、搬运、失效检查的实际开销因实现而异,任何部署前结论都必须以实测为准。这个例子的意义在于给出估算顺序:先按稳定性排布确定 L,再用 h×L 求平均避免 token 数,最后换算延迟并扣除缓存开销。

系统 2k稳定工具 3k稳定共享政策 5k版本 p17历史 1k动态问题 1k每次不同命中前缀 10k:直接复用 KV新后缀 2k:仍需 prefill若命中率 70%,平均避免处理约 0.7×10k=7k input token/请求
图 1 按稳定性排序把大段共享内容放在前,动态历史与问题放后,最长共同前缀才有机会达到 10k。
E[Nsaved]h×L=0.7×10000=7000

5提示布局与规范化决定命中工程

布局与规范化的目标不是把命中率做到最大,而是在不破坏语义和权限边界的前提下,让共同前缀尽可能长。排序的依据是每个片段的稳定性、权限域和语义顺序:稳定且公共的内容放前面,动态且私有的内容放后面。

具体顺序可以这样组织。最前放模型与应用版本都稳定的系统规则;随后放排序固定的工具 schema 和共享的少样本示例;再往后放版本化的公共文档或政策。后部才是会话历史、检索证据和当前输入。时间戳、随机 nonce、trace id 这类每次请求都变的值,要么放进不参与模型计算的元数据,要么放在最末尾,避免打断前缀。

序列化同样要确定化:对象序列化时固定字段顺序与工具顺序,统一空白与 Unicode 规范化。这些差异在语义上不可见,却足以改变 token 序列,让完全相同的上下文失去命中。规范化做得越好,精确前缀复用的机会越大。

但布局有一条不可逾越的边界:不能为了提高命中率,把用户特定的权限或秘密提升为共享前缀,也不能把本应私有的内容移进公共区。性能优化服从数据边界,任何提高复用率的移动都必须同时保持安全规则的含义和租户隔离。语义顺序也受这条约束:把安全规则挪到靠前位置对缓存有利,可一旦模板的整体语义随之改变,就必须重新评测安全效果,而不是只看命中率涨了多少。布局的输出是稳定公共内容在前、动态私有内容在后的序列,其正确性标准始终是安全规则含义与租户隔离同时成立。

6KV 容量随层、token 和并发增长内存

一个 10k token 的前缀不能无限期常驻 GPU,原因可以直接从 KV 缓存的体积公式看出来。粗略估算中,KV 字节数 MKV 与 2×层数 Nlayer×KV 头数 NKVhead×头维 d×token 数 Ntoken×每元素字节数 b 成正比。系数 2 来自 K 与 V 各保存一份。以 32 层、8 个 KV 头、128 维、FP16(每元素 2 字节)、10k token 为例:2×32×8×128×10000×2 = 1,310,720,000 字节,约 1.31 GB——这只是一个请求的一段前缀。乘上并发请求数,占用会与模型权重和活跃请求一起争夺显存。不同架构、张量并行方式和量化会改变具体数值,但量级说明前缀缓存绝非免费。

因此容量规划的输出不仅是字节数,还包括存储层级的选择,输入则是层数、KV 头数、头维、token 数、每元素字节和并发。几种典型策略各有代价:GPU 常驻命中最快,但昂贵且挤压并发;搬到 CPU 或远端容量大,但搬运开销可能超过重算本身;TTL/LRU 实现简单,却不理解前缀价值,可能淘汰掉最值钱的长前缀;按“节省计算除以占用字节”的价值感知淘汰能保留长且热的前缀,但估值与实现都复杂。工程上常用分块或 PagedAttention 管理内存、用前缀树组织共享结构,再叠加 TTL、LRU 或价值淘汰,在命中速度、容量与并发之间做取舍。

策略优点代价
GPU 常驻命中最快昂贵、挤压并发
CPU/远端层级容量大搬运可能超过重算
TTL/LRU简单不理解前缀价值
价值感知保留长且热门前缀估值和实现复杂
MKV2×Nlayer×NKVhead×d×Ntoken×b1.31GB

7缓存键和失效必须包含模型语义版本正确性

文本前缀没变,不代表 KV 还能复用。换一个 LoRA、调整 RoPE 配置,隐藏状态就会整体偏移,此时直接复用旧缓存等于让新配置读旧状态。凡是可能影响隐藏状态的因素——权重与适配器、tokenizer、位置编码、注意力实现、精度、模型模板,以及各类推理配置——只要发生变化,就必须进入缓存的命名空间,或直接触发失效。提示、工具和政策版本变更也会改变 token 序列本身,同样需要通过版本字段反映在键里。

缓存键通常由模型快照、适配器标识、token 序列哈希、租户或安全域、位置起点等共同构成。命中后还可以抽样重算部分结果进行对比,用来捕获实现层面的错误。滚动发布时新旧缓存必须隔离:v42 不能读取 v41 留下的状态,隔离靠的就是版本字段进入键和命名空间。

这样设计是因为缓存污染会静默传播。一段错误状态如果被高频复用,影响面远大于一次单发推理错误,而且难以追溯。因此除哈希与版本校验外,系统还要保留快速全量失效的开关,出现污染迹象时能立刻停用整片缓存。

失效设计的输入是模型快照、适配器、tokenizer、位置配置、模板和租户域,输出是缓存命名空间、键和失效动作。只要其中任何一项改变,同一段文本就可能产生不同的 KV。当版本字段不完整时,正确的做法是拒绝复用、按未命中重新计算,而不是冒险读取旧状态。

8隐私、租户隔离与侧信道安全

KV 看起来只是数值张量,不是可读文本,但它是对输入的派生表示,可能包含敏感信息,因此必须按敏感数据状态治理。风险不止于内容本身:跨租户共享缓存时,攻击者可以通过命中延迟推测某个前缀是否已存在于缓存中,形成侧信道;如果缓存键缺少权限字段,还可能复用本不应共享的内容。

默认做法是按租户、组织或数据分类隔离,公共系统前缀与用户私有历史分开放置。缓存需要设置保留期、加密、访问审计和删除传播,日志只记录前缀的哈希与长度,不记录原文。共享公共政策等前缀时,要先确认所有租户持有相同版本并具有相同访问权;服务供应商的缓存政策本身属于数据处理协议的一部分,需要在协议层面明确。

用户可控的前缀不能用来直接寻址共享缓存。这类设计必须配合域隔离、完整哈希和长度或配额限制,才能防住哈希碰撞、前缀探测和资源耗尽攻击。

安全治理的输入是前缀的数据分类、租户、保留期和访问权,输出是隔离域、加密、审计与删除策略。核心结论是:KV 是输入的派生数据,命中时间可能泄露“某前缀是否存在”,所以跨租户共享只限真正公共、版本一致、权限一致的版本化内容。

9评测要证明净收益而非命中率评测

命中率从 40% 升到 80%,TTFT 却没有改善,这并不矛盾。可能的解释有三类:命中的都只是很短的前缀,省下的预填充微乎其微;缓存查找或跨机搬运的耗时超过重算本身;请求被路由到缓存节点,排队时间抵消了计算节省。所以评测不能只看命中率,要看请求级的命中长度分布、节省的预填充 token 数与时间、查找与搬运耗时、GPU KV 占用、驱逐行为、TTFT 的 p50/p95/p99、吞吐、费用和质量——这些才是净收益的构成。

A/B 对比的前提是可比性:两组的提示语义和路由负载必须保持一致,否则命中的变化只是布局差异的假象;结果还要按租户、长度和并发切片,避免平均值掩盖某类流量实际变差。故障路径同样要纳入测试:版本错配、缓存节点丢失、缓存雪崩、冷启动、删除传播和跨租户访问,任何一项失效都可能让线上收益归零甚至变成事故。

对决策真正有用的价值指标是每 GB·小时缓存带来的 TTFT 或计算节省,以及在 SLO 内增加的可服务吞吐。它们直接对应缓存占用与业务容量,比裸命中率更接近决策。

缓存评测的输入是请求级命中长度、计算与搬运时间、显存占用、延迟、吞吐和质量,输出是按租户、长度、并发切片的净收益。命中率升高而 TTFT 不降,通常说明命中太短,或查找、搬运、排队抵消了收益。

11把因果链连起来综合

提示缓存的完整因果链可以串成一条从问题到验收的路径。起点是测量:先确认预填充在总延迟中的占比,以及流量里重复出现的 token 前缀有多少。只有这两项真实存在,缓存才有收益空间。

第二步是按稳定性和权限重排上下文,把稳定公共内容前置、动态私有内容后置,让最长共同前缀有机会变长。第三步是构造缓存键,键由配置、租户和 token 前缀共同构成,保证相同文本在不同模型版本、不同租户下不会错误复用。第四步是价值感知的存储与命中路由,按“节省计算除以占用字节”决定哪些前缀常驻 GPU、哪些降级到 CPU 或远端、哪些淘汰。第五步是版本变化的原子失效:权重、适配器、tokenizer、位置配置或模板任一改变,立即停用对应命名空间,防止旧状态被新配置静默复用。

最后一步是联合验收:命中长度、TTFT、显存占用与质量四者一起看,而不是用单一命中率代替结论。链条每一环都以前一环为条件——没有测量就不知道该重排什么,没有正确的键和失效就谈不上安全复用,没有价值感知存储就守不住容量,没有联合验收就无法证明净收益。

资料来源与改编说明
访问日期:2026-07-22