图解 KV Cache——DS V4.1-Flash的制胜秘密

DeepSeek V1 到 V4.1-Flash,单 token 的 global KV 如何从 389,000 B 压缩到 890 B的?这篇文章对于 Agent 的使用者、本地模型部署者、模型开发者都有一定帮助。

今天跑一个长上下文的 agent,比如让模型读完一个百万 token 的代码仓库再干活,显存里最占地方的并非模型权重,而是 KV Cache。权重是固定的,几百 GB 就几百 GB;而 KV Cache 跟着上下文线性长,只要上下文翻一倍,它就会翻一倍。

9 月初 DeepSeek 发布 V4.1-Flash 技术报告,标题就叫 Pushing the Limits of KV Cache Compression。摘要里的一句话一针见血:prefill 仍然很贵,同时大 KV Cache 持续挤占 HBM 和 SSD 的容量与传输带宽,这三样合起来是降低部署成本面临的紧迫瓶颈。

这篇文章想做的事是把 KV Cache 这几年来几次关键突破画出来,最后重点讲讲 V4.1 Flash 的突破。中间会穿插一点硬件知识,因为不理解 HBM 是什么、为什么贵,就理解不了为什么大家要拼命压这几个字节。

每个 token 的全局 KV Cache 从 V1 的 389 KB 压到 V4.1 的 890 字节,减少到 1/437

阅读指南:

  • Agent 使用者(用 Claude Code、Cursor 之类工具,关心为什么长对话变慢变贵):读第一节和第五节的账单部分就够了,第一节解释 prefill 和 decode 这两种成本,第五节解释缓存命中价为什么能定到未命中的 2%。中间的技术细节可以跳过,看图就行
  • 本地模型部署者(在自己的卡上跑 vLLM、SGLang,为显存发愁):重点是第二节、第三节和文末的“如果你在部署模型”。第二节讲清显存金字塔和为什么 decode 卡在带宽,第三节区分直接决定你有哪些开关可以配置,文末四条是可操作的清单
  • 模型开发者(做架构或训练,想知道 V4.1 到底改了什么):第三节的三维框架和第四节全文是主体,尤其是 CSA2 三模式、40 层排布和 890 字节账单三段。第五节列了四条设计原因,可以对着报告原文核对

没有任何机器学习背景也能读完前两节。第四节涉及具体的层数、维度和字节数,读起来会慢一些,但每一段都配了图,直接看图会更加直观。

一、KV Cache 是什么

这一节讲三件事:KV Cache 为什么存在、它有多大、prefill 和 decode 的区别。后面所有内容都建立在这三件事上。

Transformer 生成文字是一个字一个字往外蹦的,每蹦一个新字,它要回头看一遍前面所有的字,这个”回头看”就是注意力。

注意力的机制是:每个字有三个向量,Q(Query,我在找什么)、K(Key,我是什么)、V(Value,我携带什么信息)。新字的 Q 去和前面每个字的 K 做点积,得到关注权重,再用权重把那些字的 V 加权求和。

这里有一个关键:前面那些字的 K 和 V 不会变,第 100 个字看第 3 个字时用的 K、V,和第 200 个字看第 3 个字时用的,是同一组数。

如果不缓存,每生成一个字就把前面所有字的 K、V 重算一遍,总计算量是 O(N²);而缓存则每步只算新字的 K、V,其余从显存里读,计算量降到 O(N)。后者的代价是显存占用,每个字、每一层都要存一份 K 和 V。

这就是 KV Cache,名字很朴素,就是把 K 和 V 缓存起来。

KV Cache 到底有多大

一个乘法公式就能算清楚:

拿 DeepSeek 的第一代 67B 模型算:95 层,K 和 V 各一份,8 个 KV 头,每头 128 维,BF16 精度每个数 2 字节,相乘得到每个 token 约 389 KB。

389 KB 听起来不多。但 128K 上下文就是 48 GB,一张 H100(2026.9.12市场价约为30万RMB) 的 80 GB 显存放完 KV 就剩不下多少给权重了。1M 上下文要 380 GB,四张 H100 的显存全拿来放 KV 都不够。

这个公式很重要,里面的每一项的优化都意味着 KV Cache 能进一步降低。

prefill 和 decode

  • prefill:模型读 prompt 的阶段,所有 token 一起过一遍网络,把它们的 K、V 算出来存好,属于算力密集型
  • decode:模型生成回答的阶段,一次只处理一个新 token,但要把前面所有 token 的 KV 从显存读出来,属于带宽密集型

agent 场景有个特点:工具调用非常频繁,每次调用都把新结果塞回上下文,再让模型读一遍。所以 agent 场景下 prefill 性能比较重要,这一点决定了 V4.1 Flash 的很多设计选择。

二、硬件层:显存为何如此金贵

要理解为什么大家非要为几个字节较劲,得先看看这些字节存放的位置。

GPU 的内存是一个金字塔。塔尖是片上 SRAM,只有几十 MB,但是快到几十 TB/s,但小到只能放正在计算的那一小块。往下是 HBM 显存,几十到一两百 GB,速度 3-8 TB/s。再往下是主机内存,TB 级,但要走 PCIe,带宽掉到几十到几百 GB/s。金字塔底部是 SSD,几十 TB,带宽只有几 GB/s。

V4.1 把 KV Cache 按照位置分成两类:

  • 运行时 KV:正在服务的请求的 KV,必须在 HBM 里,受 HBM 容量约束
  • 持久化 KV:为了前缀复用而保留的 KV,放在 SSD 或主机内存,受 SSD 容量和 I/O 带宽约束

前缀复用是什么?你已经和模型对话了10轮,如果第11轮的 prompt 前面10轮都一样,且第10轮的 KV 还留着,那么第11轮就不用重算,agent 场景里这种复用极其频繁,所以生产系统会把 KV 存到 SSD 上,能保留几十个小时之久。

HBM 是什么

HBM 全称 High Bandwidth Memory,高带宽显存,它和消费级电脑里的内存条有着本质区别。

普通内存条插在主板上,通过几十根线和 CPU 通信。HBM 是把 DRAM 芯片一层层垂直堆叠起来,用穿透硅片的 TSV(硅通孔)上下打通,然后整个堆和 GPU 计算芯片并排贴在同一块硅中介层上。距离从厘米级缩到毫米级,连线从几十根变成上千根,带宽因此暴涨。

代价是三样:贵、难做、扩展难度指数级上升。每个 HBM 堆要堆 8 层或 12 层芯片,良率随层数指数下降。中介层的面积有限,能贴几个堆是定死的。所以 H100 是 80 GB,H200 是 141 GB,B200 是 192 GB,每一代加几十 GB 都是封装工艺的极限。

还有一个原因让 KV 的每个字节更值钱了。decode 每生成一个 token,都要把权重和整段 KV 从 HBM 读一遍,算力是闲的,瓶颈在 HBM 带宽。上下文越长,要读的 KV 越多,每个 token 花的时间越长。所以压缩 KV 同时能够达到省钱和提速的目的。

三、KV Cache 的几大突破

这一节先给一个最基础的分析框架,然后逐个分析过去 DeepSeek 的六次突破。

这里有一个非常干净的框架,即 KV Cache 的总大小是三个数的乘积:

  • 每条 KV 有多大(entry 大小)
  • 存多少条(序列长度)
  • 存几份(层数)

盒子的体积就是驻留在显存里的字节数,继续往下看之前,先来了解下两个重要区分:

第一个区分:省存储,还是省读取 第二节说过,decode 每一步都要把 KV 从 HBM 读一遍,所以读多少和存多少是不同的两个点。有些技术让每一步少读一些,但盒子本身没变小。GPU 已经塞满的时候,更快的注意力 kernel 腾不出位置给下一个请求,只有缩小盒子才行。

第二个区分:训练时就加进去,还是部署时再分开 GQA、MLA、跨层复用、压缩注意力改变了模型的权重形状和缓存布局,必须在训练时定下来,不能给训好的模型打补丁。量化、分页、前缀缓存、分层卸载是推理引擎上的开关,模型不动。这决定了一项技术能传播多快。

突破一:GQA,让多个 Q 头共用一组 K、V

最早的多头注意力(MHA)里,8 个 Q 头配 8 组 K、V。2023 年的 GQA 说:K、V 没必要那么多,4 个 Q 头共用一组就够。KV 头数从 8 降到 2,缓存直接砍到四分之一。Llama 2 和 DeepSeek-V1 都用了它,代价是精度略降。

突破二:MLA,低秩压缩

DeepSeek-V2(2024 年)的 MLA 走了另一条路:

它不减少头数,而是把所有头的 K、V 压成一个 512 维的潜在向量存起来。算注意力时再用两个上投影矩阵解压回各头的 K、V。更妙的是,数学上这两个矩阵可以吸收进 Q 和输出的投影里,解压这一步可以完全省掉。另外留 64 维给 RoPE 位置编码单独存下来。

效果也很显著:每层每 token 只存 576 个数,而 MHA 是 2048 个,与此同时精度也能和 MHA 一致。

突破三:量化,一个数从 2 字节到半字节

BF16 一个数 2 字节,FP8 一个数 1 字节,DeepSeek-V3 开始用 FP8 存 KV,直接减半。V4.1 更进一步用 FP4,再减半。这是唯一一项既可以当部署开关(推理时直接量化)、也可以训练时就加进去(量化感知训练)的技术。

突破四:滑动窗口和稀疏注意力

序列维度上,第一个想法是滑动窗口注意力(SWA):每个 token 只看最近的 128 个。这样 SWA 的 KV 大小固定,和上下文长度无关。

但只看最近 128 个显然不够,要配一个能看全局的分支。全局分支怎么省?稀疏注意力:用一个轻量索引器给所有历史 token 打分,只挑分数最高的 512 个来做注意力。DeepSeek-V3.2 的 DSA 就是这个思路。

注意稀疏注意力省的是读取,不是存储。KV 还是要全存着,只是每次只读一部分。要省存储有两条路。一条是压缩:DeepSeek-V4 的 CSA 把每 2 个 token 的 KV 压成 1 条,训进去的。另一条是驱逐:运行时按重要性丢 token,比如 H2O 保留最近的 token 加上历史上被关注最多的那些。驱逐是部署开关,代价是丢掉的 token 真的没了,一个当下没人看的工具结果,可能几轮之后正是需要的。

还有一条更激进的路:Qwen3-Next、Jamba 这类混合模型用循环层的固定大小状态代替大部分层的 KV,只留少数全注意力层。这是三个维度之外的第四条路,DeepSeek 完全没走这条路,但我们还是需要知道一下,它是当前另一大流派。

突破五:跨层复用,别存那么多份

层数这一维,2024 年的 CLA 提出让相邻层共用 KV,YoCo 更激进:模型下半段的层算 KV,上半段直接用。

这一维的潜力其实最大,一个 40 层的模型,如果只存 4 份 KV 而不是 40 份,就是 10 倍。V4.1 在这部分做了最多的功课

突破六:系统层,不改模型改部署

vLLM 的 PagedAttention 借鉴操作系统的虚拟内存,把 KV 按固定大小的页分配,解决显存碎片。前缀缓存让多个请求共享相同开头的 KV 页。分层卸载把不活跃的 KV 挪到主机内存和 SSD。

这三样都是部署开关,共同特点是不改变一个请求的 KV 有多少字节,改变的是浪费多少、重复多少、放在哪里。系统层的改动和模型层的改动是相乘的,这一点在 V4.1 上很显著,接下来我们能看到。

四、DS-V4.1-Flash:架构、缓存精度、部署策略三层联合优化

前面的每一次突破基本各打一维,V4.1 的核心主张是在架构、缓存精度、部署策略三个层面联合优化,三个维度加系统层一起压缩。结果是 HBM 里的全局 KV 压缩到 V4-Flash 的 1/4,SSD 里的持久化 KV 压缩到 1/8。

CED:上半段模型的 KV 由下半段代算

V4.1 是一个 40 层的模型,前 20 层叫因果编码器,后 20 层叫解码器:

常规 Transformer 里,第 30 层的 KV 由第 30 层自己的隐状态算出来。CED 说不用,第 21 到 40 层的全局 KV 全部由第 20 层的输出乘各层独立的投影矩阵得到。

这意味着 prefill 只需要跑前 20 层,后 20 层的 KV 一个矩阵乘法就拿到了。prefill 的激活参数从 16B 降到 8B,计算量减半。对 prefill 重的 agent 负载来说,这是直接省一半。

CED 的灵感来自 YoCo,但每个 decoder 层有自己的投影矩阵,KV 容量没打折;滑动窗口的 KV 仍然逐层自算,局部信息的深度没打折。

CSA2:三种模式,40 层只存 4 份

CSA2 是这次架构上最核心的改动。每一层被静态分配三种模式之一:

  • Full 模式:全套自己算。算 main KV,投影出索引器的 K,算索引器的 Q,打分选出 Top-512。
  • Reindex 模式:借用最近一个 Full 层的 main KV 和索引器 K,但用自己的索引器 Q 重新打分。KV 不存,但每层能挑不同的 512 条来看。
  • Reuse 模式:main KV 和 Top-512 索引全借,直接做注意力。

三种模式都保留自己的 Q 和 SWA KV,区别只在 main KV、索引器 K、Top-K 索引这三样从哪来。

报告给出了 40 层的实际排布:

编码器 18 层分 3 组,每组 1 个 Full 加 5 个 Reuse,每 2 个 token 压成 1 条。解码器 20 层分 5 组,第一组 1 个 Full 加 3 个 Reuse,后四组 1 个 Reindex 加 3 个 Reuse。

我们数一数:40 层里处于 Full 模式的只有 4 层。只有这 4 层有实际开销,其余 36 层都不占用空间。

层级稀疏索引器:后面的层只在候选池里找

跨层复用索引减少了打分次数,但剩下的 Full 和 Reindex 层还是要给整个上下文打分,一百万 token 的上下文这个成本不小。

层级稀疏索引器只在解码器里用:第一个 Full 层给所有位置打完分后,按 8 个位置一块取每块最高分,选出前 2048 块,得到 16,384 个候选位置的池子。后面的 Reindex 层只在池子里打分。后续索引器的成本从随上下文线性增长变成常数。报告的 Figure 2 显示,上下文从 4K 扩到 1M,V4.1 单个 token 的 decode 计算量只涨了四分之一。

按第三节的区分,这一项省的是读取。CSA2 的跨层复用和 FP4 负责缩小盒子,层级索引器负责让每一步只读盒子的一小角。两件事都做了,才同时拿到 890 字节和几乎不随上下文增长的 decode 计算量。

P4 main KV:一个数只占半字节

精度这一维,V4.1 把 main KV 从 V4 的 FP8 压到 FP4:E2M1 格式,每 16 个通道共用一个 FP8 缩放因子,选 OCP 标准的 MXFP4 是为了兼容尽可能多的硬件。它参考了 NVIDIA 的 NVFP4 但去掉了第二级全局缩放因子,报告用 RMSNorm 之后 latent 范数有上界这一条论证了全局缩放纯属多余。

这里有两个细节,一是 FP4 只用来,算注意力之前先反量化,所以不依赖硬件原生 FP4 矩阵乘法。二是 SWA KV 对量化敏感,仍然保留 FP8;main KV 的精度损失靠后训练阶段的量化感知训练压到边际水平。

890 字节是怎么算出来的

虽然DS官方报告没有给出分解,我们按格式参数和层配置反推,估算出一个结果:

一条 FP4 main KV:512 维 × 0.5 字节,加 32 个缩放因子各 1 字节,288 字节。一条 FP4 索引器 K:128 维 × 0.5 字节,加 8 个缩放因子,72 字节。编码器 3 份,压缩比 2 意味着每 token 只占半条,3 × 360 ÷ 2 = 540 字节。解码器 1 份,360 字节。合计约 900 字节,和报告的 890 字节基本吻合。

系统层:按存活多久分层,而非按大小分层

模型层的改动到此为止,HBM 里的 KV 压到了 1/4。报告还有另一半功夫在部署系统上,把 SSD 里的持久化 KV 压到 1/8。这一半和硬件的关系最密切。

先看 V4 的问题,V4 的持久化缓存里,SWA KV 占了将近一半。但 SWA KV 的访问模式和全局 KV 完全不同:全局 KV 是长尾复用,一个前缀几十个小时后还可能被命中;SWA KV 只在一个活跃会话的几分钟里有用,会话一结束就成了死数据。用 72 小时的 LRU 策略去管理分钟级的数据,纯属浪费。V4.1 的解决方案分成三层:

  • HBM:正在服务的请求的 runtime KV。毫秒级。
  • 主机内存 DRAM 池(新增):每台机器划出 10% 的 DRAM 组成分布式内存池,只放编码器的 SWA KV,TTL 几分钟。容量远小于 SSD,但周转极快。
  • SSD 持久化缓存:只放全局 KV,保证 72 小时以上。

那少数命中了全局 KV 但 SWA KV 已过期的请求怎么办?这就是 SWA Bounded Replay(有界重放)。各层的滑动窗口依赖层层叠加,精确重建第 20 层的 SWA 状态要从 20 × 128 个 token 之前开始算。有界重放不追求精确:只重放最近 128 个 token,接受一个近似状态。之前的研究表明 SWA 的有效感受野远小于理论值,报告的实验也确认这对回答质量几乎没有影响。

这一招用在两处。编码器侧,它让前缀缓存只依赖全局 KV,SWA KV 从此不必进 SSD。解码器侧更彻底:解码器的 SWA KV 永远不缓存,每次 prefill 只把 prompt 最后 128 个 token 过一遍解码器,prefill 再省一半。

于是持久化 KV 的 1/8 就是两个因子的乘积:去掉 SWA KV 约省一半,全局 KV 本身压到 1/4。

五、总结:这些字节最后变成了什么

压缩 KV Cache 并不是为了论文里的数字好看,它最终将落到API定价,与此同时,还需要确保效果至少不会变弱(对于基座模型而言)。

DeepSeek API定价下调

V4.1-Flash 发布当天,DeepSeek 同步调整了 API 价格:

最能体现 KV 压缩的一个数字是缓存命中价:只有未命中价的 2%。用户命中前缀缓存时,服务商要做的事是把持久化KV 从 SSD 搬回 HBM。KV 每 token 越小,搬得越快,占的 SSD 越少,能保留的时间越长,这个价格就能定得越低。V4.1 把持久化 KV 压到 V4 的 1/8,直接对应了这个价格的下调。四天后,所有 V4-Pro 的请求被直接路由到 V4.1-Flash,按 V4.1-Flash 的价格计费。

横向对比 Claude Opus 5 和 GPT-5.6 Sol:V4.1-Flash 的输出价是它们的1/20到1/25,缓存命中价是它们的1/80到1/160。而且 DeepSeek 的前缀在 SSD 上保留 72 小时以上,Claude 和 OpenAI 的缓存默认 5 分钟到 1 小时。对一个跑几天的 agent 任务,这两个差异是叠加之后,对成本影响巨大。

压缩这么多,能力为何不降反升?

先看看报告里的对比:V4.1-Flash-Base 用 V4-Pro 1/3 的总参数和 1/4 的激活参数,在世界知识、推理、代码上和 V4-Pro-Base 打平。后训练之后,DeepSWE v1.1 拿到 74.2,和 Claude Opus 5 的 74.0、GPT-5.6 Sol 的 73.0 在同一水平。

KV 压缩了四倍,能力为什么不降反升?报告没有单独回答,但我们如果把设计细节拼起来,可以看到答案:

  • 压缩的是冗余,而非信息本身 跨层复用的前提是相邻层的 KV 高度相似。Reindex 模式又保留了”每层挑不同的 512 条”的自由度,共享的只是 KV 本身
  • 每一处近似都在训练里见过 FP4 靠量化感知训练,层级索引器在训练和推理中用同一个候选池,有界重放在后训练中被模拟
  • 容量从 KV 挪到了权重 V4.1 有 552B 骨干参数和 196B Engram 条件记忆参数,比 V4-Flash 的 284B 大得多。存储压力从”每个 token 存多少 KV”转移到了”模型本身记住多少”,后者不随上下文增长
  • 只切了全局分支,没动局部分支 所有压缩都落在全局分支上,每层的 SWA KV 仍然自己算、仍然 FP8

当然,模型的差距仍然存在,Terminal-Bench 3.0 上 V4.1-Flash 是 30.0,Opus 5 是 43.3;HLE 上 36.8 对 56.3。官方报告自己也说,在需要专家级领域知识的科学类 agent 任务上和巨型参数模型还有差距。

如果你在部署模型

读到这里的人里总有几个正在为显存发愁,如果把上面的内容总结成四条:

  • 选模型时看四个数:KV 头数、局部层和全局层的比例、有没有 latent 压缩、有没有循环层
  • 部署现有模型时先开 FP8 KV,再固定住 prompt 模板让前缀缓存命中,这两样不丢任何 token,驱逐规则留到最后,基于真实工作负载测试后再决定如何做
  • 显存看着没变时去看 KV 池能装多少 token,而不是看 nvidia-smi 的总量。池子是固定的,省下的空间是真实容量
  • 如果遇到延迟瓶颈,尝试测量注意力读了多少字节,稀疏读能让每步更快

文章来源:WquGuru

发表评论