ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DeepSeek的KV cache压缩编年史:从MLA到V4.1

DeepSeek的KV cache压缩编年史:从MLA到V4.1

很长一段时间里,我都在追 DeepSeek 的版本更新。从 V2 引入 MLA 那一刻起,这家模型厂商在 KV cache 压缩上的路线就成了我的重点关注对象。最近社区里关于 DeepSeek V4.1 的讨论热了起来,不少人在猜它又在 KV cache 上做了什么文章。这篇精读系列的上篇,先不讲那些零散的跑分,而是把 DeepSeek 的编年史和 KV cache 压缩这条路从头梳理一遍。读完你至少能明白三件事:为什么 KV cache 是所有长上下文模型的命门,DeepSeek 为什么敢把压缩做到那种程度,以及 V4.1 这个版本在整条技术主线上到底处于什么位置。

1. DeepSeek 编年史:一条围绕效率展开的进化线

1.1 起点:从代码模型到通用对话模型

DeepSeek 最初给人留下印象,靠的是代码和数学。2023 年下半年那批开源模型里,DeepSeek Coder 是少有的把代码能力做到可用级别的选手。它当时采用的还是相对标准的 LLaMA 风格架构,没有在注意力机制上做太激进的改动,但数据配比和训练策略非常扎实。紧接着 DeepSeek LLM 7B/67B 发布,主打数学、代码、推理,这些问题恰好是后来 KV cache 压力最大、上下文理解要求最高的场景。现在回头看不难发现,这家公司从第一代模型开始,就刻意把"用有限显存跑更长上下文"当成核心命题来解决,而不是单纯堆参数。

那个时期大家讨论最多的还是模型本身的准确率。但如果你真的在本地卡上部署过 67B 版本,一定会对显存占用印象深刻。权重占一份,运行时中间激活占一份,生成时 KV cache 再占一份。当时 KV cache 还是一个比较小众的工程话题,大部分教程里最多提一句"注意预留显存",很少有人把它当成一个可以深度优化的方向。DeepSeek 后来的路线证明,他们很早就把 KV cache 当成架构设计的一部分来考虑了。

1.2 V2 与 MLA:KV cache 压缩的真正起点

2024 年初 DeepSeek V2 发布,圈内圈外最轰动的是两件事:价格和架构。价格方面,API 定价低到让同行怀疑是不是在赔本赚吆喝;架构方面,就是那个如今被反复讨论的 MLA,Multi-head Latent Attention。MLA 的核心思路是给 KV cache 做"降维压缩":既然传统多头注意力里每个头都要存一份完整的 K 和 V,那能不能把它们先投影到一个低维的潜在空间,推理时只缓存这个潜在向量,用的时候再还原出来?当然可以,而且效果超出预期。

从 V2 开始,DeepSeek 的 KV cache 占用直接降了一个数量级。这就意味着同样一块 A100 或 H800,它能支持的并发数和上下文长度都大幅提升。推理成本下降的原因有很多,但 MLA 绝对是最关键的那块拼图。我个人的判断是,V2 不是 DeepSeek 第一次尝试优化 KV cache,但它是第一次把这种优化从"工程技巧"提升到"架构创新"的层面。没有 V2 的 MLA,后面就没有办法在 671B 这种体量的模型上支撑超长上下文。

1.3 V3 与 R1:规模与推理能力的分水岭

2024 年末到 2025 年初,DeepSeek 连续放出两个重锤。V3 是一个总参数 671B、激活参数只有 37B 的 MoE 模型,训练成本对外公开的数字是 557.6 万美元。这个数字在业内引起轩然大波,因为同样体量的模型,按当时的行业惯例训练成本要高出几倍甚至十几倍。V3 在架构上延续了 MLA,同时把 MoE 的专家路由做得更精细,上下文长度也进一步拉长。上下文越长,KV cache 的增长压力就越大,MLA 带来的优势也就越明显。

R1 则是把强化学习在推理能力上的潜力彻底释放了出来,让 DeepSeek 从一个"技术圈内讨论的模型"变成了"全世界都在讨论的模型"。R1 的思考链本身就很长,动辄几千 token,这意味着在推理过程中 KV cache 的峰值占用非常恐怖。如果没有 V2 时代打下的压缩基础,R1 这种"长思考"产品在成本和部署难度上根本走不通。所以很多人只看 R1 的推理效果,我却觉得它的基础设施——尤其是 KV cache 管理能力——才是它敢放开长输出的底气。

1.4 从 V4 到 V4.1:版本迭代中延续的压缩主线

关于 V4 和 V4.1,目前公开的细节还很有限,社区里的信息也大多是猜测和局部爆料。但从 DeepSeek 一贯的路线来看,V4 大概率不是推倒重来,而是在 MLA 和 MoE 的骨架上做进一步重构,比如把压缩从"架构层面"延伸到"训练与推理联合优化"的层面。V4.1 则更像一次工程收敛和配套工具的整合,解决的是大规模部署时"算法有了、系统跟不上"的问题。

换句话说,V4.1 时期我们要关注的不只是模型本身,还有它配套的推理框架、量化方案和部署工具链。KV cache 压缩这条主线在 V4.1 里会继续延伸,方向无非是三个:压缩率更高、压缩后的信息损失更小、以及压缩逻辑对不同硬件和场景的适配性更强。下面我把 KV cache 的基础机制和主流压缩路线拆开讲清楚,这样你再回来看 V4.1 的发布说明,就能看懂它在 KV cache 上那些表述到底在说什么。

2. KV cache 是什么,为什么它成了部署的命门

2.1 从 Transformer 解码过程看 KV cache 的本质

要理解 KV cache,得先看 Transformer 生成一个 token 的完整过程。模型在生成第 n 个 token 时,并不是只把第 n-1 个 token 喂进去,而是要把从第 1 个到第 n-1 个所有 token 的相关信息都参与注意力计算。如果不做任何缓存,每生成一个新 token,都要把之前所有 token 的 Key 和 Value 重新算一遍,计算量随序列长度二次增长,这在长文本生成时是完全不可接受的。

KV cache 的做法很直接:每生成一个 token,就把它的 Key 向量和 Value 向量缓存下来。后续生成新 token 时,直接从缓存里读取历史 KV,只对当前这步做矩阵运算。这样单步生成的计算量基本恒定,瓶颈就从"重复计算"转移到了"显存容量"。KV cache 本质上是用显存换速度,但代价是显存被吞得越来越厉害,模型权重反而是固定开销,KV cache 是随上下文长度和并发数动态增长的。

2.2 显存占用公式与实际算例

KV cache 的显存占用可以近似用下面这个公式表达:

KV cache 字节数 = 2(K 和 V) × n_layers(层数) × n_kv_heads(KV 头数) × head_dim(每个头的维度) × sequence_length(序列长度) × batch_size(批量大小) × bytes_per_element(每个元素字节数)

以一个 7B 模型为例,常见配置是 32 层、32 个 KV 头、每个头 128 维。在 FP16 精度下,单个 token 的 KV cache 大约是 32 × 32 × 128 × 2 字节,也就是 256KB 左右。这个数字看着不大,但如果是 8k 上下文、batch size 为 8,就是 256KB × 8192 × 8,约等于 16GB。也就是说,光 KV cache 就能吃掉一张 24GB 显卡的大半显存,这还没算模型权重和激活值。如果是 128k 的长上下文,同样配置下 KV cache 会涨到 256GB 以上,单张卡完全无法承载。

这也是为什么长上下文模型在部署时,最常遇到的不是"模型推理不了"而是"显存不够放历史信息"。模型权重可以通过量化压缩,KV cache 也必须同步压缩,否则长上下文就是纸上谈兵。

2.3 KV cache 为什么难压缩

那有人会问,直接像压缩模型权重那样把 KV cache 也量化到 INT4 不行吗?可以,但没那么简单。KV cache 中的 K 和 V 向量直接参与注意力分数的计算,数值精度会影响最终的注意力分布。如果压缩太狠,模型可能突然"失忆",或者生成质量明显下降。更麻烦的是,不同层、不同头的 KV 向量分布差异很大,同一个量化方案很难在所有位置上同时生效。

KV cache 的另一个难点在于它是一个"动态增长"的缓存,不像模型权重那样加载进来就固定了。生成过程中它不断写入新数据,旧的又不能随意丢弃。做量化要考虑写入时的数值范围统计,做淘汰要考虑哪些 token 的信息可以安全丢弃,做架构改造要保证不破坏训练和推理的一致性。这些约束叠加起来,让 KV cache 压缩成了一个既烧脑又考验工程能力的活。

3. KV cache 压缩技术路线拆解

3.1 低精度量化:最直接的显存瘦身方案

量化的思路最简单粗暴:把 KV cache 里的每个元素从 FP16 降到 INT8 或者 INT4,显存占用立刻减半或者减到四分之一。现代推理框架里已经内置了这类支持,比如 vLLM 中可以通过 KV cache 的量化选项来开启,有些框架还会对 K 和 V 采用不同的量化策略,因为 K 对精度的敏感度通常比 V 更高。

实际使用时需要注意几个点。第一,量化 KV cache 不应该只盯着显存节省,还要观察生成质量的变化。在短上下文场景下损失可能不明显,但长上下文累积误差会放大,所以要在目标场景下做充分的评测。第二,per-channel 或 per-token 的量化粒度比全局量化更稳,但计算开销也会增加。第三,如果你的硬件支持 FP8 计算,优先考虑 FP8 量化方案,它在精度和性能上常常比 INT8 更均衡。从行业实践看,KV cache 量化已经从"可选项"变成了"默认项",V4.1 如果继续沿这条线走,大概率会进一步放宽量化后的精度损失边界。

3.2 架构级压缩:GQA、MQA 与 DeepSeek 的 MLA

架构级压缩是从源头减少 KV cache 的量,典型代表是 MQA(Multi-Query Attention)和 GQA(Grouped-Query Attention)。MQA 让所有注意力头共享同一组 K 和 V,省得最狠但质量损失明显;GQA 把注意力头分成若干组,每组的 K 和 V 共享一份,是质量和显存之间的折中。Llama 2 开始就用的是 GQA,这说明业界的共识早就从"每条路都修"转向了"该省就省"。

DeepSeek 的 MLA 走得更远。它不是简单地让多个头共享 KV,而是把 K 和 V 整体投影到一个低维潜在空间,缓存的是这个低维向量。具体来说,MLA 引入了额外的投影矩阵,把高维的 K 和 V 压缩成低维的潜向量,在注意力计算时才将其解压回来。这样做的好处是缓存量不随头的数量线性增长,压缩比远高于 GQA,同时还能保留每个头的独立表达能力。

从工程实现来看,MLA 需要改动的不只是推理代码,还有训练时的注意力计算方式。这也是为什么它是一个"架构级"方案,而不是一个可以在任何模型上即插即用的补丁。V2 时期 DeepSeek 敢用 MLA,说明这套架构从一开始就是为推理效率和长上下文设计的,不是后来缝补上去的。

3.3 序列级裁剪:滑动窗口与 token 淘汰

除了在"缓存内容本身"上做文章,还有一种思路是从"缓存哪些 token"入手。滑动窗口就是只保留最近 N 个 token 的 KV,更早的信息直接丢弃,但这样做模型会丧失对远距离信息的感知能力。StreamingLLM 发现了一个有意思的现象:即使丢掉了中间大部分 token,只要保留初始几个 token 的 KV,模型的生成稳定性就能维持在一个不错的水平。

H2O(Heavy Hitter Oracle)这类方法则是在线评估每个 token 的重要性,只保留那些注意力权重较高的"重要 token",把不那么重要的 KV 从缓存中淘汰出去。这类方法的优点是压缩比可以动态调节,缺点是实现复杂度高,要实时维护 token 的重要性分数,而且在分布式推理场景下,还需要保证所有节点对淘汰策略的认知一致,否则生成结果可能会出现"记忆漂移"。序列级裁剪和量化、架构级压缩是互补的,三者在实际系统中经常会叠加使用。

3.4 DeepSeek 的融合路线:从 V2 到 V4.1 的猜想

回到 DeepSeek 这条主线上来。V2 用 MLA 解决了"KV 缓存量过大"的问题,V3 延续这套架构并把它规模化,R1 证明了它能在超长思考链上扛住压力。V4 和 V4.1 如果继续进化,合理的推演是在 MLA 基础上叠加更精细的量化策略,同时利用训练阶段引入的压缩感知能力——也就是让模型在训练时就适应压缩后的 KV 缓存,推理时压缩带来的精度损失就会更小。

这里就顺带解释了为什么 V4.1 值得单独拿来精读:它可能不是一次"换骨架式"的大版本,而是把过去的压缩技术线做了一次系统性的收敛和工程化。对于部署者来说,这意味着同样的显存能跑更长的上下文、更大的并发;对于开发者来说,意味着 KV cache 相关的调参窗口变小了,"上手就能用"的体验更好了。当然,这些判断建立在公开信息和行业惯例之上,具体细节要等官方文档和权重实际放出来之后才能验证。

4. 实操视角:部署 V4.1 时如何用好 KV cache 优化

4.1 显存估算与部署规划

不管 V4.1 最终采用的压缩方案是什么,部署前都得先做显存预算。一个实用的做法是把显存占用拆成三块:模型权重、KV cache、运行时激活值和碎片开销。模型权重可以用参数量乘以每参数字节数估算,比如 671B 模型在 FP8 下大约是 671GB,这个数字决定了你需要几张卡。KV cache 部分则要用 2.2 节里的公式,结合框架实际采用的压缩比来计算。

部署时重要的不是精确到每一字节,而是建立一个决策流程:先确定目标上下文长度和最大并发数,反推 KV cache 需要多大,再比对卡的显存,决定是否需要开启更激进的 KV cache 量化,或者降低并发数。很多人在这一步贪心,把 gpu_memory_utilization 设得太高,结果跑起来就 OOM,反而拖累整体吞吐。我实测下来的经验是,留出 10% 到 15% 的显存余量给碎片和临时张量,稳定性会好很多。

4.2 推理框架中与 KV cache 相关的配置

以 vLLM 为例,有几个关键参数和 KV cache 直接相关。max_model_len 决定了模型最大能接受的序列长度,也直接决定了 KV cache 的理论上限。gpu_memory_utilization 控制的是给推理引擎预留的显存比例,框架会在这个范围内分配 KV cache 池。如果开启 KV cache 量化,可以在框架的配置文件中指定量化方式,INT8 通常是无损或接近无损,INT4 则要谨慎评估生成质量。

此外,流水线并行和专家并行组合的部署方式下,KV cache 的分布策略也会影响内存利用率。我希望大家至少在部署前跑一次压力测试:把并发请求逐步增加到目标值,同时监控 KV cache 的命中率、GPU 显存峰值和首个 token 延迟。压力测试中暴露出来的显存波动,往往比理论估算更值得警惕。对 V4.1 这种还在迭代中的版本,我建议先小规模验证,再逐步扩展并发,不要一上来就追求极限吞吐。

4.3 常见问题与排查思路

我整理了几个 KV cache 相关的高频问题,在部署和调优时可以直接对照排查。

现象可能原因排查思路
生成时显存溢出(OOM)KV cache 池预留不足调低 gpu_memory_utilization,或降低 max_num_seqs、max_model_len,优先保证请求不中断
长上下文生成速度越来越慢未命中 KV cache 量化,或滑动窗口未生效检查推理框架日志中 KV cache 的容量和用量,确认是否开启压缩策略
生成结果出现"记忆错乱"KV cache 量化精度损失过大,或 token 淘汰过于激进回退量化等级,或调整淘汰阈值,对比压缩前后同一批 prompt 的输出
多卡部署时显存占用不均衡KV cache 分片策略与模型并行方式不匹配检查 tensor parallel 配置,确认 KV cache 头在各卡上的分配比例
并发升高后延迟急剧劣化KV cache 池超过显存容量,触发内存交换规划合理的 token 吞吐量,必要时用 PagedAttention 或等效的显存分页机制

4.4 几个值得注意的实际心得

我踩过几次坑之后,总结出三条建议。第一,KV cache 是"越压越薄、越薄越险",不要只盯着显存数字,生成质量评测必须跟着走。第二,长上下文场景下,KV cache 的压缩率要和检索阶段配合起来看,模型并不是把所有历史信息都塞进 KV cache 才叫有记忆,合理的取舍往往比盲目堆积更有效。第三,如果用的是社区推理框架,升级版本前一定要看 release notes 里和 KV cache 相关的改动,这类改动经常不动声色地改变显存行为,表面上只是某个大版本号变了,实际部署配置却要跟着调。

我个人现在部署 DeepSeek 系模型时,已经习惯了「架构级压缩 + 量化 + 必要时淘汰」三段式配置策略。先确认模型原生采用什么注意力架构,再决定量化等级,最后才考虑 token 级裁剪。这套顺序不能乱,因为架构级压缩是模型训练时就定好的,量化是推理侧的施加手段,裁剪则是在极端长上下文的兜底方案。V4.1 如果确实在 KV cache 压缩上做了更多文章,我的体会是它会进一步降低这三个环节之间的互相干扰,让部署方可以减少一个维度的调优负担。

5. 关于下篇与后续方向的一点说明

这篇上篇只讲了 DeepSeek 的编年史和 KV cache 压缩这一条线。KV cache 是模型迭代里最接近"用户体验"的技术环节之一,但绝不是我关注的全部。下篇可能会接着讲 V4.1 在训练策略、MoE 路由、以及工具链整合方面的进展,也可能针对具体场景做一轮部署实录。

最后再分享一个心得:技术文章看了再多,不如自己动手配一次环境、跑一段长上下文生成、再亲手把 KV cache 的显存占用打出来看一眼。你在日志里看到 KV cache 从几 GB 涨到几十 GB 的那个瞬间,会比任何理论分析都更能让你理解 DeepSeek 这些版本在 KV cache 上下的功夫值在哪里。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进