RAG 场景下,主流引擎的 KV Cache 复用建立在严格前缀匹配之上,而检索结果会随查询动态重排——同样的文档块换个顺序就不再是同一个前缀。结果是块级内容冗余很高,缓存命中率却接近于零。
出路是跨块复用:允许块级 KV 直接拼接,不再考虑顺序。代价是块间 cross-attention 全部缺失,精度显著下降。已有方案用部分重计算来补救,但在 20% 这种实际可接受的重算预算下,精度相对损失普遍达到 30%~50%。我们认为根因是那些全局显著、但与用户问题无关的 token,把有限的重算预算占满了。
ProphetKV 换了一个目标:不去重建全部 cross-attention,只恢复用户问题真正会与之交互的部分。支撑它的是一个此前被忽略的观测——早在 prefill 阶段、decode 尚未开始时,用户问题自身的注意力分布就已经与后续生成 token 的注意力模式高度一致,跨模型跨数据集都很稳健。据此我们推导出以问题注意力为主因子的价值函数,并用两阶段流程在尊重层间依赖的前提下完成选择与重算。20% 重算比下保留全量 prefill 精度的 96%,prefill 耗时相比全量重算下降约 4.6 倍,且完全免训练。
演讲大纲
- RAG 的缓存命中率为什么接近于零
- 前缀匹配复用的适用边界:多轮对话有效,RAG 失效
- 检索块动态重排导致的命中率塌陷
- 跨块复用:命中率上来了,精度掉下去了
- 大幅提升命中率
- 块级 KV 直接拼接,丢掉的是块间 cross-attention
- 重算名额被"看起来重要"的 token 占满了,和问题相关的一个都没排上
- 先知:把用户问题变成调度信号
- RAG 输入的固定拓扑:查询恒在末尾,一个免费但被忽略的先验
- 核心观测:查询注意力分布与后续生成注意力模式的重合度
- 挑 token 只算问题那几十行注意力,不算整张矩阵,所以选择本身几乎不花钱
- 两阶段重计算:怎么在层依赖下高效执行
- 死结在哪:每一层该重算的 token 不一样,但想知道深层该挑谁,得先把前面所有层都算完——而这正是我们想省掉的开销
- 走不通的捷径:只用第一层的结果替所有层做决定,跨层 token 重合度断崖式下跌
- 阶段一,发现:从头到尾走一遍所有层,每层只算问题对上下文的注意力,把各层信号融合成一份全局重要性排序
- 阶段二,重建:名单已定,再走一遍完成重算。因为不必边算边选,隐藏状态可以沿层传递复用,不会走一层停一下等决策
- 与推理引擎 prefill 流程的对接点
- ProphetKV + ContextBox
- 复用单位从前缀降到块,同一份 KV 能被更多请求命中。
- 可缓存对象从会话前缀变成整个知识库,显存装不下,且需要跨实例共用——共享存储成为必需。
- LRU 在 RAG 下会颠簸,先知信号在选择阶段已经算出,可以作为多级缓存的放置依据
- 总结与 Q&A
- 结论:跨块复用的瓶颈不在选择规则,而在预算分配
- 三个数字:20% 重算预算、精度保留 96%、prefill 加速 4.6 倍(基线为全量重算)
- 三个代价:以 I/O 换算力;无小相关子集的任务退化;引擎侧缺部分复用接口
这样的技术在实践过程中有哪些痛点?
- 拿 I/O 换算力:候选块的 KV 要全部读回显存,其中被重算的那部分读回来就作废;上下文越短、存储越慢,越不划算
- 精度并非无损:20% 预算下仍有约 4% 相对损失;摘要、全文翻译这类没有"小相关子集"的任务,以及查询不在末尾的模板,会直接退化
- 引擎侧缺接口:vLLM / SGLang 都没有"复用一部分、重算一部分"的公开接入点,落地成本不低
演讲亮点
- 一个反直觉的观测:模型在开口回答之前,就已经"知道"答案藏在上下文的哪里——用户问题的注意力分布,提前预示了后续生成的注意力模式。
- 一次目标的重定义:同行都在想办法把有限算力分得更均匀,我们证明真正该做的是放弃重建全部 cross-attention,只算用户问题关心的那部分。
- 实测数据:20% 重算比、精度保留 96%、prefill 快 4.6 倍、免训练、可直接接入现有推理引擎。
- 从存储侧视角说清楚,KV Cache 跨块复用之后,多级缓存的收益边界到底在哪里。
听众收益
- 理解 RAG 场景下 KV Cache 复用的真实瓶颈:前缀匹配为什么失效,跨块复用的收益边界在哪里,以及"理论重算比"与"实际算力开销"之间为什么会差出数倍。
- 拿到一套免训练的选择性重计算方案:如何用用户问题定位真正该重算的 token,如何在层间依赖下分两阶段执行,以及方案生效需要满足的三个前提条件。
- 看清跨块复用之后的完整成本账:重算省下的算力、KV 回显存的 I/O 开销、精度损失三者如何权衡,多级 KV Cache 在什么条件下才真正划算。