DeepSeek DSA、DeepSeek V4与vLLM Hybrid KV Cache详解
本文最后更新于 2026年5月8日 晚上
1. 先说结论
版本说明:本文参考的是2026-05-08访问的公开资料,主要包括DeepSeek-V3.2-Exp技术报告、vLLM官方DeepSeek V4支持博文、vLLM latest Hybrid KV Cache Manager设计文档、Mamba论文和HuggingFace Transformers的DeepSeek V4文档。vLLM latest文档是developer preview,Hybrid KV Cache Manager文档也明确说该特性仍在早期阶段,具体行为要以实际安装版本为准。
这篇文章想回答几个问题:
- DeepSeek Sparse Attention,也就是DSA,到底在干什么。
- DeepSeek V4的attention为什么比普通attention复杂。
- linear attention、Mamba这类结构和普通attention有什么区别。
- 这些结构下,vLLM还要不要KV cache。
- Hybrid KV Cache Manager到底是什么东西。
- 为什么普通PagedAttention管理不了所有新模型。
先给结论。
普通Transformer的KV cache保存所有历史token的K和V。
如果上下文长度是,decode每一步都要看历史个token:
所以KV cache随着上下文长度线性增长:
而attention计算本身在prefill阶段通常是:
长上下文下,这两个都很贵:
- KV cache吃显存。
- attention计算吃算力和显存带宽。
DeepSeek DSA、DeepSeek V4、linear attention、Mamba都在试图解决这个问题,但方法不一样:
| 方法 | 核心想法 | 是否保存所有K/V | 长上下文收益 |
|---|---|---|---|
| MLA | 缓存压缩latent KV | 不保存完整K/V,保存latent | 主要省KV cache |
| DSA | 用轻量indexer选Top-k历史token | 候选KV仍要缓存,但主attention只看Top-k | 主要省attention计算 |
| DeepSeek V4压缩attention | 多token压缩成少量cache entry,再配合稀疏选择和短滑窗 | 保存压缩后的cache和少量局部状态 | 同时省KV cache和attention计算 |
| Sliding Window Attention | 只看最近窗口 | 只需要保留最近窗口 | 省KV cache和计算,但牺牲远程依赖 |
| Linear Attention | 把softmax attention改写成可递推状态 | 通常不保存逐token K/V,而保存累积状态 | 理论上线性复杂度 |
| Mamba/SSM | 用状态空间递推表示历史 | 不保存KV,保存state | decode状态固定或低增长 |
| Hybrid模型 | 多种层混在一起 | 有些层存KV,有些层存window,有些层存state | 需要按层分别管理 |
vLLM的Hybrid KV Cache Manager就是为最后一种情况准备的:
一个模型里不同层需要的“缓存”不一样,不能再用一个统一的普通KV cache逻辑管理所有层。
例如:
full attention层:
要保存所有历史token的KV
sliding window层:
只保存最近W个token的KV
Mamba层:
不保存K/V,而是保存SSM state
DeepSeek V4压缩层:
保存压缩KV、indexer cache、compressor state、局部SWA cache这就是Hybrid KV Cache Manager的背景。
2. 普通KV Cache到底是什么
先从普通Transformer开始。
一层attention通常会把输入投影成:
attention计算是:
在decode时,假设已经有个历史token,现在要生成第个token。
新token只需要算一个query:
但它要和所有历史key/value交互:
所以历史token的必须保存下来。
这就是KV cache。
2.1 KV cache为什么大
假设模型有:
- 层
- 个KV heads
- 每个head维度
- 上下文长度
- dtype大小 bytes
KV cache大小大致是:
这里的表示K和V。
上下文翻倍,KV cache也翻倍。
这就是长上下文推理的核心压力。
2.2 PagedAttention解决了什么
vLLM最经典的设计是PagedAttention。
它不是改变模型结构,而是改变KV cache的内存管理方式。
普通做法可能希望每个请求的KV cache连续存放:
请求A: [token0 token1 token2 ... token999]
请求B: [token0 token1 token2 ... token499]但请求长度不同、动态进出,会产生碎片。
PagedAttention把KV cache切成blocks,像操作系统分页一样管理:
请求A:
block 3 -> block 8 -> block 1
请求B:
block 4 -> block 7逻辑上连续,物理上可以不连续。
它解决的是:
- KV cache碎片。
- 动态batch下的内存复用。
- prefix cache / block sharing。
但注意:
PagedAttention默认面对的是普通attention的KV cache。
如果模型里有Mamba、sliding window、压缩attention、KV sharing,情况就复杂了。
3. MLA:先把KV变小
MLA是Multi-head Latent Attention。
它是DeepSeek-V2之后很重要的结构。
普通attention保存完整K/V:
每个token:
K_t
V_tMLA保存的是压缩latent:
后续再从恢复或投影出attention需要的信息。
直白理解:
普通KV cache:
直接存K和V,东西多,但用起来直接。
MLA cache:
存压缩latent,东西少,但计算时要再加工。MLA主要解决:
- KV cache太大。
- 长上下文decode读KV太多。
但MLA不一定解决attention计算复杂度。
即使每个token的cache变小,如果一个query仍然要看全部历史token,那么历史长度是时,仍然要处理很多位置。
所以DeepSeek后续又引入DSA,进一步减少“看多少历史token”。
4. DSA:不要看所有历史token,只看重要的Top-k
DSA是DeepSeek Sparse Attention。
它最早在DeepSeek-V3.2-Exp技术报告里公开,目标是提升长上下文效率。
DSA的核心想法:
先用一个便宜的indexer给历史token打分,再只选Top-k历史token做主attention。
普通attention是:
当前query看所有历史tokenDSA是:
当前query先问indexer:
哪些历史token最可能有用?
然后只对这些Top-k token做attention。4.1 Lightning Indexer
DSA里有一个lightning indexer。
它会给当前query token 和历史token 计算一个index score:
可以把它理解成:
query t 对历史token s 的粗略相关性评分DeepSeek报告里的indexer设计很轻量,head数少,还可以用FP8实现,因此比完整MLA attention便宜很多。
4.2 Top-k token selection
拿到所有历史token的index score后,DSA选择Top-k:
然后主attention只看这些token:
如果上下文长度是,普通attention大致看个历史位置。
DSA只看个位置,其中:
所以主attention复杂度从:
变成近似:
当然,indexer本身仍然要打分很多历史token,所以不是完全免费。但indexer比主attention轻很多,整体仍然更省。
4.3 DSA和MLA的关系
DeepSeek-V3.2-Exp不是抛弃MLA,而是在MLA基础上做DSA。
报告里提到,DSA在MLA下实例化,并且为了GPU效率,使用类似MQA的模式:每个latent KV entry会被多个query heads共享。
直白理解:
MLA:
每个历史token的KV表示更小。
DSA:
每个query不看全部历史token,只看Top-k。二者解决的问题不同:
- MLA减少每个token存多少。
- DSA减少每次attention看多少token。
所以它们可以叠加。
4.4 DSA对KV cache的影响
DSA不是说“不需要KV cache”。
它仍然需要保存可被选中的历史信息,例如MLA latent KV entry、indexer相关cache等。
区别是:
- 普通attention:所有历史KV都参与主attention。
- DSA:历史KV仍在,但每次只gather Top-k参与主attention。
所以在vLLM实现上,DSA难点不只是省计算,还包括:
- 如何保存indexer需要的cache。
- 如何高效Top-k选择。
- 如何从KV cache里gather稀疏token。
- 如何让稀疏访问不把GPU搞慢。
稀疏attention看起来少算了,但如果gather非常零散、kernel不友好,也可能吃掉收益。
5. DeepSeek V4 attention:不是单一DSA,而是混合压缩attention
vLLM官方DeepSeek V4博文把DeepSeek V4的attention拆成几个关键点。
DeepSeek V4要解决两个问题:
- KV cache memory growth。
- attention computation cost。
它的设计不是只靠一个技巧,而是组合了多种东西。
5.1 Key和Value共享
普通attention里,K和V是两份不同向量。
DeepSeek V4里做了key/value sharing,从存储角度可以理解为:
原来:
保存K
保存V
现在:
K/V共享某种表示这能带来接近2倍的KV cache节省。
但K通常会带RoPE位置信息,V通常不带。如果K/V共享,会带来位置表示问题,所以vLLM博文里提到需要inverse RoPE来修正输出。
初学者可以先记住:
K/V共享能省cache,但需要额外数学处理保持位置性质正确。
5.2 多token压缩:c4a和c128a
DeepSeek V4进一步把多个token压缩成较少的cache entries。
vLLM博文里提到两种模式:
c4ac128a
直白解释:
c4a:
大约每4个原始token压缩成1个cache entry。
具体实现里一个compressed token是8个uncompressed token的加权和,stride是4。
c128a:
大约每128个原始token压缩成1个cache entry。
一个compressed token来自128个uncompressed token。因此,如果上下文是1M tokens:
c4a后大约还有250K compressed entries
c128a后大约还有8K compressed entries这大幅降低KV cache数量。
但问题是:压缩太狠可能丢局部信息。
所以DeepSeek V4还保留短滑动窗口。
5.3 Short Sliding Window保留局部信息
DeepSeek V4使用短滑动窗口,例如vLLM博文里提到window size 128。
作用是:
压缩KV负责远距离历史信息
短滑窗负责最近局部信息为什么需要它?
因为压缩attention有边界。
例如c128a要等128个token形成一个压缩entry。如果当前query还没越过某个压缩边界,它可能不能合法地看未来token形成的compressed entry。短滑窗能保证query至少可以看到最近原始tokens。
直白理解:
远处历史:
看压缩版本。
最近上下文:
看原始窗口。5.4 DSA在DeepSeek V4里的作用
即使使用c4a压缩,1M上下文仍然可能有约250K compressed entries。
如果每个query都对250K entries做完整attention,仍然很贵。
因此还需要DSA:
先用indexer选Top-k compressed entries
再对这些entries做主attention这就是DeepSeek V4 attention复杂的原因:
它不是:
普通attention而是混合了:
K/V sharing
多token压缩
DSA稀疏选择
短滑动窗口
indexer cache
compressor state6. DeepSeek V4的KV cache到底存什么
普通模型的KV cache可以简单说:
每层保存K和V blocksDeepSeek V4就没这么简单。
vLLM博文里说DeepSeek V4有多种KV state:
c4amain KV。c128amain KV。c4aindexer KV。- compressor state。
- sliding window KV。
可以理解成:
main KV:
主attention真正读取的压缩KV。
indexer KV:
lightning indexer用来给历史位置打分。
compressor state:
用于把连续token逐步压缩成compressed entry的滚动状态。
sliding window KV:
最近局部token的未压缩信息。所以DeepSeek V4的“KV cache”其实不是单一cache,而是一组cache。
6.1 为什么vLLM要固定logical block size
不同压缩率会导致自然block大小不同:
c4a:
256个原始token -> 64个compressed entries
c128a:
256个原始token -> 2个compressed entries如果每种attention层都用自己的block大小,allocator会非常复杂。
vLLM的做法是:
逻辑上统一用256个native token positions作为block单位。
也就是说,调度器和prefix cache看的是:
这个请求的第0-255个原始token
这个请求的第256-511个原始token
...而每种cache在物理上放多少compressed entries,由对应cache类型自己决定。
这样好处是:
- scheduler不用理解每种压缩细节。
- prefix cache边界更统一。
- block分配逻辑更简单。
- disaggregated prefill也更容易传输。
6.2 compressor state为什么像sliding window
压缩不是瞬间发生的。
例如c4a可能需要维护一个8-token的滚动状态,c128a可能需要维护一个128-token的滚动状态。
这个状态不是完整历史,而是最近一小段。
这很像sliding window:
只关心最近W个token
超过窗口的状态可以丢掉或已经压缩进main KV所以vLLM把compressor state注册到sliding-window KV cache spec下面,让它复用Hybrid KV Cache Manager已有的窗口语义。
这很重要,因为:
- prefix caching可以复用block语义。
- disaggregated prefill可以像传SWA state一样传compressor state。
- CUDA graph和MTP也能按类似方式处理。
6.3 为什么要统一page size
即使逻辑block统一了,不同cache类型的物理大小仍然不同。
例如:
c4a main KV page
c128a main KV page
c4a indexer KV page
c4a compressor state page大小可能都不一样。
如果每一种都单独一个block pool,会产生跨pool碎片:
c4a pool空很多,但c128a pool满了
不能互相借vLLM的做法是把不同cache kind归到少数几个page-size bucket里。
DeepSeek V4实现里,vLLM博文说整个cache stack可以放进三个page sizes:
- largest bucket
- middle bucket
- smallest bucket
这样allocator只需要管理少数几个pool。
直白理解:
不是每种cache单独开一堆内存池,而是把大小相近/可统一的cache放进同一类池子里。
这能减少碎片和运行时复杂度。
7. Linear Attention是什么
现在换一个方向:linear attention。
普通softmax attention是:
问题是会产生一个矩阵。
prefill复杂度大致是:
linear attention想把它改写成线性形式。
一个常见思路是用特征映射近似softmax kernel:
然后attention可以写成:
核心是维护两个累积状态:
每来一个新token,更新状态:
decode时不需要保存所有历史K/V,只需要保存状态。
7.1 Linear Attention的cache是什么
普通attention cache:
token 1: K1, V1
token 2: K2, V2
...
token T: KT, VTlinear attention cache:
state S
state z它不是逐token KV cache,而是历史信息的聚合状态。
这就是linear attention长上下文省内存的来源。
但是也有代价:
- 表达能力和softmax attention不同。
- 很多任务里需要和full attention混合。
- kernel实现、数值稳定性、训练配方都很重要。
所以很多实际模型不是纯linear attention,而是hybrid:
一些层用linear attention
一些层用full attention这又回到了Hybrid KV Cache Manager的问题。
8. Mamba是什么
Mamba是selective state space model。
它不是attention。
普通attention的历史记忆是:
保存所有历史token的K/VMamba的历史记忆是:
维护一个递推state可以把它想成RNN式更新:
输出:
真实Mamba比这个复杂,有selective机制和高效scan实现。但初学者抓住一点就够了:
Mamba不是每个历史token都存K/V,而是把历史压进一个状态里。
8.1 Mamba的cache是什么
Mamba decode时需要保存state。
它不像普通attention那样保存:
K_1, V_1
K_2, V_2
...
K_T, V_T而是保存类似:
conv_state
ssm_state不同实现名字不同,但本质是:
每层一份状态这个状态大小通常不随上下文长度线性增长,或者增长方式远小于普通KV cache。
所以Mamba类结构对长上下文很有吸引力。
8.2 Mamba为什么常和attention混合
纯Mamba不一定在所有任务上都替代attention。
很多模型会混合:
full attention层:
负责全局信息、精确检索、跨长距离依赖
Mamba层:
负责高效序列建模、压缩历史状态例如vLLM Hybrid KV Cache Manager文档提到的Bamba、Jamba、Minimax等,就是Mamba + full attention类型。
这类模型里:
- full attention层需要KV cache。
- Mamba层需要state cache。
- 两种cache大小、生命周期、prefix cache规则都不一样。
9. Sliding Window Attention是什么
Sliding Window Attention只看最近个tokens。
普通attention:
当前token看所有历史tokensSWA:
当前token只看最近W个tokens公式上可以理解为:
它的KV cache只需要保留最近窗口:
保留 token t-W 到 token t
更老的token可以释放所以SWA能显著降低KV cache。
但代价是:
- 看不到很远的历史。
- 需要和full attention层混合,才能保留全局能力。
Gemma 2/3、Ministral、Cohere等模型里常见full attention + sliding window的混合结构。
10. Local Chunked Attention是什么
Local chunked attention和sliding window类似,也限制可见范围,但组织方式更像按chunk划分。
直白理解:
不是所有token两两attention
而是token主要看本地chunk或有限范围它也会改变KV cache管理:
- 某些层不需要完整历史KV。
- 某些旧block可以释放。
- prefix cache命中规则和full attention不同。
vLLM Hybrid KV Cache Manager文档把Llama4 local attention + full attention列为hybrid模型例子。
11. 为什么这些模型让KV cache管理变复杂
普通模型很简单:
每一层都是full attention
每一层都需要所有历史KV
所有层block大小基本一致
prefix cache规则一致hybrid模型变成:
第0层: full attention
第1层: sliding window
第2层: Mamba
第3层: full attention
第4层: local attention
...不同层需要不同缓存:
| 层类型 | 需要保存什么 | 是否保存所有历史 |
|---|---|---|
| Full Attention | K/V blocks | 是 |
| MLA | latent KV | 是,但每token更小 |
| DSA | latent KV + indexer cache | 候选信息要保存,主attention稀疏读 |
| DeepSeek V4 c4a/c128a | 压缩KV + indexer + compressor state | 保存压缩历史和局部状态 |
| Sliding Window | 最近窗口K/V | 否 |
| Linear Attention | 累积状态 | 否 |
| Mamba | SSM/conv state | 否 |
| KV sharing层 | 复用别的层KV | 自己可能不用分配 |
如果仍然按普通KV cache管理,就会浪费。
比如sliding window层只需要最近1024 tokens,但普通KV manager可能给它保留全部128K tokens。
这会直接浪费显存。
12. Hybrid KV Cache Manager是什么
vLLM的Hybrid KV Cache Manager就是为了管理这些混合模型。
可以先看模块关系:
flowchart TD
S[Scheduler] --> KVM[KVCacheManager 统一入口]
KVM --> C{KVCacheCoordinator}
C -->|单一cache类型| U[UnitaryKVCacheCoordinator]
C -->|多种cache类型| H[HybridKVCacheCoordinator]
H --> F[SingleTypeKVCacheManager: Full Attention]
H --> W[SingleTypeKVCacheManager: Sliding Window]
H --> M[SingleTypeKVCacheManager: Mamba / State]
H --> D[SingleTypeKVCacheManager: Compressed / DSA Cache]
F --> BP1[Block Pool / Prefix Cache]
W --> BP2[Window Blocks / Prefix Cache]
M --> BP3[State Cache]
D --> BP4[Compressed KV / Indexer / Compressor State]
KVM --> MR[Model Runner 使用分配结果执行forward]
这张图的意思是:scheduler只面对一个KVCacheManager接口,不直接理解full attention、sliding window、Mamba、DeepSeek V4压缩cache的区别。区别被藏在coordinator和不同的SingleTypeKVCacheManager里。
官方文档定义的hybrid model包括:
- sliding window + full attention
- Mamba + full attention
- local chunked attention + full attention
Hybrid KV Cache Manager要做两件事:
- 对不同layer type分配不同slots。
- 支持layer-specific prefix-cache规则。
12.1 不同层分配不同slots
例如full attention层:
需要保存所有tokenssliding window层:
只需要保存最近sliding_window_size个tokensMamba层:
需要保存state,不是K/V所以manager不能只说:
给请求A分配N个KV blocks而是要说:
给请求A的full attention group分配N个blocks
给请求A的sliding window group分配M个blocks
给请求A的Mamba group分配state blocks12.2 不同层prefix cache规则不同
full attention的prefix cache命中要求:
prefix里的所有token KV都还在sliding window的prefix cache命中要求:
只要最后sliding_window_size个token还在因为更老的token本来就不会被这一层看见。
如果一个模型同时有full attention和sliding window,那么最终一个请求能复用多长prefix,要取各组命中结果的交集。
vLLM文档说,block pool里会类似用:
(block_hash, group_id) -> block也就是说,同一段tokens在不同KV cache group里是分别缓存和淘汰的。
12.3 KV cache group是什么
可以把KV cache group理解成:
一组缓存行为相同的层。
例如一个模型有:
10层full attention
20层sliding window attention可能被分成:
Group 0: full attention layers
Group 1: sliding window layers part 1
Group 2: sliding window layers part 2每个group有自己的SingleTypeKVCacheManager。
HybridKVCacheCoordinator负责协调多个group:
请求要分配cache
-> full group分配多少
-> sw group分配多少
-> 最终组合成一个allocation result13. vLLM Hybrid KV Cache Manager的三层结构
vLLM设计文档里说,KVCacheManager组织成三层:
13.1 KVCacheManager
这是scheduler和KV cache系统之间的接口。
scheduler不应该关心底层是full attention、sliding window还是Mamba。
它只问:
这个request还能不能分配slots?
这个request命中了多少prefix?
这个request结束后释放哪些blocks?13.2 KVCacheCoordinator
Coordinator协调多个group。
不同情况用不同coordinator:
KVCacheCoordinatorNoPrefixCacheUnitaryKVCacheCoordinatorHybridKVCacheCoordinator
如果只有一种KV cache group,用Unitary。
如果有full attention + 另一种efficient attention group,用Hybrid。
文档里也说明,当前HybridKVCacheCoordinator主要处理“正好两个KV cache groups,且必须包含一个full attention group和另一个efficient attention group”的情况。更多复杂情况还不完整。
13.3 SingleTypeKVCacheManager
每个SingleTypeKVCacheManager管理一种cache group。
例如:
FullAttentionManager:
管full attention blocks
SlidingWindowManager:
管sliding window blocks
Mamba manager:
管Mamba state相关缓存它实现这一类attention自己的:
- allocation
- prefix caching
- eviction
- block lookup
14. Hybrid KV Cache的几个典型case
14.1 Case 1:纯full attention
这是最简单的情况。
所有层都是full attention
所有层都保存完整历史KV只需要普通KV cache manager。
prefix cache命中也简单:
前缀的所有blocks都在 -> 命中14.2 Case 2:full attention + sliding window
假设模型层模式是:
full, sw, sw, full, sw, sw, ...full层需要所有历史。
sw层只需要最近窗口。
如果请求长度是100K,sliding window是4K:
full层:
需要100K token的KV
sw层:
只需要最近4K token的KV如果不用hybrid manager,sw层也保存100K,就浪费了:
个token的KV。
Hybrid manager会让不同group按自己的规则分配。
14.3 Case 3:full attention + Mamba
假设模型有:
full attention层
Mamba层
full attention层
Mamba层full attention层需要KV blocks。
Mamba层需要state。
Mamba state的大小可能和attention层的kv_hidden_size完全不同,甚至每层state size更大。
vLLM文档提到,Bamba、Jamba、Minimax这类hybrid mamba模型会遇到这个问题。
当前算法大致是:
- 增大attention层的
block_size,让一个attention block的物理大小能容纳Mamba state。 - 对Mamba state做padding,使它适配统一page size。
- 再使用grouping策略。
这会带来浪费。
文档也明确说这部分仍是work in progress。
14.4 Case 4:KV sharing
有些模型某些层复用其他层的KV cache。
例如Gemma-3n相关结构里有KV sharing。
这种情况下:
layer B 使用 layer A 的KV那就没必要给layer B单独分配KV cache。
vLLM Hybrid KV Cache Manager会忽略这些KV sharing层,只给真正需要KV cache的层分配。
然后model runner侧打补丁,让使用共享KV的层拿到正确的cache。
15. DeepSeek V4为什么是更复杂的hybrid cache问题
DeepSeek V4不仅是:
full + sliding window它还包含:
- c4a压缩KV
- c128a压缩KV
- indexer cache
- compressor state
- sliding window local cache
- FP8/FP4 cache dtype策略
不同cache有不同大小和生命周期。
可以把DeepSeek V4的一层attention粗略画成:
flowchart LR
X[输入hidden states] --> COMP[Compressor]
COMP --> C4A[c4a compressed KV]
COMP --> C128A[c128a compressed KV]
X --> IDX[Lightning Indexer]
IDX --> TOPK[Top-k compressed entries]
C4A --> TOPK
C128A --> ATTN[Main Attention]
TOPK --> ATTN
X --> SWA[Short Sliding Window KV]
SWA --> ATTN
ATTN --> OUT[Attention output]
COMP --> STATE[Compressor state]
IDX --> IKV[Indexer KV cache]
这张图故意画得简化。重点不是精确到每个kernel,而是说明DeepSeek V4不只有一份普通KV cache,而是同时有compressed KV、indexer cache、compressor state和局部窗口cache。
vLLM为DeepSeek V4做了特殊实现:
- 统一logical block size为256 native token positions。
- 把compressor state当成sliding-window KV cache spec处理。
- 把多种cache kind归并到少数page-size buckets。
- 使用kernel fusion减少HBM读写。
- 使用multi-stream重叠indexer、compression和SWA insertion。
这说明一个趋势:
未来模型的attention结构越复杂,KV cache manager越像一个小型内存系统,而不是简单tensor数组。
16. DSA / DeepSeek V4 / Linear Attention / Mamba对比
| 机制 | 解决问题 | cache形态 | 优点 | 代价 |
|---|---|---|---|---|
| MLA | KV per token太大 | latent KV | 显著省KV cache | attention仍可能看很多历史位置 |
| DSA | attention看太多历史token | latent KV + indexer cache | 主attention只看Top-k | 需要indexer和稀疏gather |
| DeepSeek V4 | KV和attention都贵 | 压缩KV + indexer + window state | 1M上下文更可行 | 实现复杂,cache种类多 |
| Sliding Window | 完整历史太贵 | 最近窗口KV | 简单高效 | 远程依赖弱 |
| Linear Attention | softmax attention二次复杂度 | 累积状态 | 理论线性 | 表达和训练更难 |
| Mamba | 用状态建模历史 | SSM/conv state | decode状态小 | 不是attention,长距离检索能力需混合 |
| Hybrid模型 | 兼顾能力和效率 | 多种cache并存 | 折中效果好 | serving系统复杂 |
最直白的区别:
MLA:
每个历史token存得更小。
DSA:
每次只读一部分历史token。
DeepSeek V4:
历史token先压缩,再稀疏读,还保留局部窗口。
Linear Attention:
不保存所有历史token,保存累积状态。
Mamba:
不做attention,保存递推state。
Hybrid KV Cache Manager:
让vLLM同时管理这些不同类型的缓存。17. 一个具体例子:普通attention vs sliding window vs Mamba
假设上下文长度:
17.1 普通full attention层
每层要保存所有历史KV:
token 1 KV
token 2 KV
...
token 100000 KVdecode第100001个token时,要读全部历史KV。
cache规模:
17.2 Sliding window层
window size:
只保存最近4096个token:
token 95905 KV
...
token 100000 KV更老的KV可以释放。
cache规模:
如果固定,不随增长。
17.3 Mamba层
保存state:
state不保存100000个KV。
cache规模更像:
这里的是相对上下文长度说的,不是说state真的只有一个数字。
17.4 Hybrid模型
假设模型有30层:
10层full attention
10层sliding window
10层Mamba缓存需求就是:
10层 * 100000 tokens 的full KV
10层 * 4096 tokens 的window KV
10层 * Mamba state这比30层都full attention省很多。
但vLLM必须知道每一层是哪种类型,否则就会分配错。
18. 一个具体例子:DeepSeek V4的压缩cache
假设原始上下文:
也就是约1M tokens。
18.1 如果全量保存
普通KV cache要保存约1M个位置。
如果每层每token cache很大,总量会很夸张。
18.2 c4a
c4a大约每4个token生成1个compressed entry。
所以1M tokens会变成约:
个compressed entries。
vLLM博文里也用“1M上下文下c4a仍有约250K compressed tokens”来解释为什么还需要DSA。
18.3 c128a
c128a每128个token生成1个compressed entry。
所以1M tokens会变成:
个compressed entries。
8192已经不算大,所以c128a层可以更接近full attention over compressed entries。
18.4 short sliding window
如果window size是128,那么最近128个原始tokens仍然可被直接访问。
整体就变成:
远处历史:
compressed entries
近处历史:
sliding window原始KV
注意力计算:
对c4a可能用DSA选Top-k
对c128a可以看较少compressed entries这就是DeepSeek V4能把1M上下文做得更可行的原因。
19. vLLM在这种情况下怎么做KV cache
对普通模型:
KVCacheManager:
管每层K/V blocks对hybrid模型:
KVCacheManager:
作为统一入口
KVCacheCoordinator:
协调不同KV cache groups
SingleTypeKVCacheManager:
各自管理full / sliding window / mamba / compressed cache对DeepSeek V4这种模型,vLLM还需要更定制的布局:
logical block:
统一按native token positions算
physical page:
按cache kind放进不同page-size bucket
compressor state:
当成sliding-window状态管理
indexer cache:
单独保存,供DSA打分
main compressed KV:
供主attention读取这比普通KV cache多了很多层。
但目标很简单:
- 少浪费显存。
- prefix cache还能工作。
- disaggregated prefill还能传KV。
- CUDA graph和kernel fusion还能用。
- scheduler不需要理解所有attention细节。
20. 初学者最容易误解的点
20.1 “Mamba没有KV cache,所以vLLM不用管cache”
不对。
Mamba没有普通attention的K/V cache,但它有state。
serving系统仍然要管理这些state:
- 分配。
- 保存。
- 释放。
- prefix cache相关处理。
- batch中不同请求的状态索引。
只是它不叫普通KV cache。
20.2 “Sliding window就是普通KV cache少存一点”
不完全。
除了少存,它的prefix cache和eviction规则也不同。
full attention要保证整个prefix都还在。
sliding window只关心窗口内的tokens。
20.3 “DSA不需要保存历史KV”
不对。
DSA只是主attention不看全部历史token。
但它仍然需要历史token的可选表示,以及indexer需要的cache。
否则Top-k选出来以后没东西可读。
20.4 “DeepSeek V4就是DSA”
不准确。
DeepSeek V4包含DSA相关思想,但它的attention机制还包括:
- K/V sharing
- c4a/c128a压缩
- short sliding window
- compressor state
- indexer cache
- custom KV cache layout
只说“DeepSeek V4 = DSA”会漏掉KV cache压缩这条主线。
20.5 “Hybrid KV Cache Manager是KV压缩算法”
不是。
Hybrid KV Cache Manager不是模型算法,也不是压缩算法。
它是vLLM里的缓存管理系统。
它负责:
不同层需要不同缓存时,
怎么分配、复用、查prefix、释放、避免浪费。21. 对vLLM开发/使用的启发
21.1 看模型结构时要看attention type
以后部署模型,不能只看:
参数量
上下文长度
量化格式还要看:
attention类型
是否MLA
是否DSA
是否sliding window
是否Mamba
是否linear attention
是否KV sharing因为这些决定KV cache怎么分配。
21.2 长上下文性能不只看max_model_len
一个模型支持1M context,不代表普通KV cache能轻松撑住1M。
要看:
- 每token cache多大。
- 是否压缩KV。
- 是否稀疏attention。
- 是否滑窗。
- vLLM是否有对应kernel。
- Hybrid KV Cache Manager是否支持该结构。
21.3 新attention结构会把复杂度转移到系统层
模型论文里说:
KV cache减少
attention计算减少但推理系统还要解决:
- cache布局。
- block分配。
- prefix cache。
- 稀疏gather。
- kernel fusion。
- 多stream并行。
- disaggregated serving。
DeepSeek V4就是典型例子。结构上省了很多,但vLLM需要专门做复杂实现,才能把理论收益落到实际吞吐上。
22. 总结
这篇文章可以用几句话总结。
第一,普通Transformer的KV cache保存所有历史K/V,长上下文下显存和计算都会变贵。
第二,MLA通过latent KV减少“每个token存多少”,DSA通过Top-k sparse attention减少“每个query看多少token”。
第三,DeepSeek V4不是单一DSA,而是把K/V sharing、多token压缩、DSA、short sliding window、indexer cache、compressor state组合起来,目标是在1M上下文下同时降低KV cache和attention计算。
第四,linear attention和Mamba走的是另一条路:不保存逐token K/V,而是维护递推或累积状态。
第五,现代模型越来越hybrid:full attention、sliding window、Mamba、local attention、compressed attention可能混在一个模型里。
第六,vLLM Hybrid KV Cache Manager就是为这种情况服务的。它不是压缩算法,而是一个缓存管理系统,用来按layer type分组管理不同cache,并处理prefix cache、allocation、eviction和memory layout。
一句话概括:
未来长上下文模型的难点不只是“attention怎么算”,而是“每一层到底需要记住什么、记多久、放在哪里、怎么复用”。Hybrid KV Cache Manager就是vLLM为这个问题做的系统抽象。
23. 参考
- DeepSeek-V3.2-Exp技术报告:DeepSeek-V3.2-Exp: Boosting Long-Context Efficiency with DeepSeek Sparse Attention,https://paper.arxivhub.com/DeepSeek_V3_2.pdf
- vLLM Blog:DeepSeek V4 in vLLM: Efficient Long-context Attention,https://vllm.ai/blog/deepseek-v4
- vLLM Design Docs:Hybrid KV Cache Manager,https://docs.vllm.ai/en/latest/design/hybrid_kv_cache_manager/
- HuggingFace Transformers:DeepSeek-V4 model documentation,https://huggingface.co/docs/transformers/main/model_doc/deepseek_v4
- Mamba论文:Mamba: Linear-Time Sequence Modeling with Selective State Spaces,https://arxiv.org/abs/2312.00752
- DeepSeek-V2论文页:DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model,https://huggingface.co/papers/2405.04434