一声棒喝,本不立文字
偏要著録,已是二义

vllm-blog

vLLM 中的 DeepSeek V4:高效长上下文 Attention

DeepSeek V4 in vLLM: Efficient Long-context Attention

二〇二六年五月三日 · 英文原文

vLLM Team 发布 DeepSeek V4 支持,覆盖 DeepSeek-V4-Pro(1.6T)和 Flash(285B),支持 100 万 token 上下文;实现共享 KV、c4a/c128a 压缩、DSA、hybrid KV cache、Kernel Fusion 与 Multi-stream,1M 下 bf16 KV cache 约 9.62 GiB。

vLLM 中的 DeepSeek V4:高效长上下文 Attention | vLLM Blog

菜单

搜索文档文档Blog活动联系社区GitHub

主题

图片 2:vLLM Logo](https://vllm.ai/)[文档](https://docs.vllm.ai/)[Blog](https://vllm.ai/blog)[活动](https://vllm.ai/events)[联系](https://vllm.ai/contact)[社区](https://vllm.ai/#community)搜索⌘J[](https://github.com/vllm-project/vllm "GitHub")

Blog

vLLM 中的 DeepSeek V4:高效长上下文 Attention

2026 年 4 月 24 日 17 分钟阅读

vLLM Team

#model-support

目录

我们很高兴宣布,vLLM 现在支持 DeepSeek V4 系列模型(deepseek-ai/DeepSeek-V4-Prodeepseek-ai/DeepSeek-V4-Flash)。

这些模型具备高效的长上下文 attention 机制,专为涉及最多 一百万 token 的任务设计。新的 attention 设计初读可能显得复杂,但只要系统地拆解,其基本原理是直接的。

本文分为三部分:

这是我们对该模型支持的初始发布,后续优化正在积极推进。我们希望下面的技术说明能帮助开源社区理解 attention 机制本身,以及我们当前实现决策背后的原因。

在 vLLM 上运行 DeepSeek V4

DeepSeek V4 包含 2 个模型:大型 1.6T 参数模型 DeepSeek-V4-Pro,以及小型 285B 参数模型 DeepSeek-V4-Flash。两个模型都支持最多 100 万 token 的上下文,vLLM 对新 attention 机制的实现也设计为可扩展到这一上下文长度。

DeepSeek-V4-Pro

这里我们重点展示一个单节点部署,面向便捷测试和原型开发进行优化,并包含 FP4 indexer 和 MTP 等若干可选优化。以下命令可在 8xB200 或 8xB300 上运行。

docker run --gpus all \
  --ipc=host -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  vllm/vllm-openai:deepseekv4-cu130 deepseek-ai/DeepSeek-V4-Pro \
  --trust-remote-code \
  --kv-cache-dtype fp8 \
  --block-size 256 \
  --enable-expert-parallel \
  --data-parallel-size 8 \
  --compilation-config '{"cudagraph_mode":"FULL_AND_PIECEWISE", "custom_ops":["all"]}' \
  --attention_config.use_fp4_indexer_cache=True \
  --tokenizer-mode deepseek_v4 \
  --tool-call-parser deepseek_v4 \
  --enable-auto-tool-choice \
  --reasoning-parser deepseek_v4

更多部署策略,包括 disaggregated serving / 更多 GPU 架构,请参考 recipes

DeepSeek-V4-Flash

这里我们重点展示一个单节点部署,面向便捷测试和原型开发进行优化,并包含 FP4 indexer 和 MTP 等若干可选优化。以下命令可在 4xB200 或 4xB300 上运行。

docker run --gpus all \
  --ipc=host -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  vllm/vllm-openai:deepseekv4-cu130 deepseek-ai/DeepSeek-V4-Flash \
  --trust-remote-code \
  --kv-cache-dtype fp8 \
  --block-size 256 \
  --enable-expert-parallel \
  --data-parallel-size 4 \
  --compilation-config '{"cudagraph_mode":"FULL_AND_PIECEWISE", "custom_ops":["all"]}' \
  --attention_config.use_fp4_indexer_cache=True \
  --tokenizer-mode deepseek_v4 \
  --tool-call-parser deepseek_v4 \
  --enable-auto-tool-choice \
  --reasoning-parser deepseek_v4

更多部署策略,包括 disaggregated serving / 更多 GPU 架构,请参考 recipes

DeepSeek V4 的 Attention 机制解释

长上下文推理面临两个主要挑战:

为了解决这些挑战,DeepSeek 团队设计了一种新的 attention 机制,目标是同时压缩 KV cache 并降低 attention 计算时间。

  1. 共享 key 和 value 向量(节省 2x 内存)。为保证正确性,我们对 attention 输出应用 inverse RoPE 操作。

  2. 跨多个 token 压缩 KV cache(节省 4x 到 128x 内存)。在 DeepSeek V4 中,有两种做法: * c4a:将 KV cache 大约压缩到 1/4。一个压缩 token 是 8 个未压缩 token 的加权和,stride 为 4。 * c128a:将 KV cache 大约压缩到 1/128。一个压缩 token 是 128 个未压缩 token 的加权和,stride 为 128

  3. DeepSeek Sparse Attention(有界的 attention 计算成本)。即使用 c4a attention 压缩 KV cache,一百万 token 序列仍有 250k 个压缩 token。为加速 attention 计算,我们可以使用 DeepSeek Sparse Attention (DSA),只 attend 到 top- 个压缩 token。

  4. 保留局部性:短滑动窗口。DeepSeek V4 使用大小为 128 的滑动窗口处理局部信息,并在未压缩 token 上运行,使 query token 在到达压缩边界之前能够 attend 到局部信息。

为了更好地说明这种新的 attention 机制,下面是 c4a attention 处理 13 个 token 的动画。理解上述细节后,c128a 的情况也应当很容易理解。可以打开交互版本,将鼠标悬停在 token 上查看连接关系。

图片 3:c4a attention 动画

c4a attention 动画

这种高效 attention 设计带来了显著的 KV cache 节省。使用 bf16 KV cache 时,DeepSeek V4 在 1M 上下文下每个序列只有 9.62 GiB KV cache。相比之下,61 层 DeepSeek V3.2 风格 stack 的估算值为 83.9 GiB,DeepSeek V4 约小 8.7x。在实践中,我们对 indexer cache 使用 fp4,对 attention cache 使用 fp8,相比 bf16 估算值进一步将 KV cache 大小减少约 2x

图片 4:DeepSeek V3.2 与 DeepSeek V4 中每层 KV state 对比。

DeepSeek V3.2 与 DeepSeek V4 中每层 KV state 对比。

关于算术和数学解释的更多细节,请参见附录。

vLLM 对 DeepSeek V4 的实现

尽管结构上实现了节省,这种 attention 机制仍然具有内在复杂性;要在 vLLM 中高效实现这些节省,是一个包含多个实现挑战的系统问题:

除 attention 机制本身外,还有若干其他更新,包括 Manifold-Constrained Hyper-Connections 这类架构变化,以及 MoE 模块的一些变化。本文不涵盖这些内容,因为它们属于更简单、也更容易适配的模型改动。

vLLM 从两个方面进行优化来应对这些挑战:内存管理和 kernel 效率。

保持 KV Cache 内存紧凑

vLLM 的 KV cache 内存分配器必须在 GPU 内存中紧密打包多种 KV state,同时仍要与 prefix caching、prefill/decode disaggregation、CUDA graphs 以及 vLLM 服务路径的其他部分协同工作。三个设计选择让这件事变得可控。

(1) 单一逻辑块大小

不同层的压缩比例不同(c4a 为 1/4,c128a 为 1/128,SWA 为 1/1)。一个显而易见的设计是围绕某个整数数量的 压缩后 entry 来设置每层的 block 大小。但这样每层都会有自己的 page layout,allocator 必须分别处理它们。

相反,我们为每个压缩层将逻辑 block 固定为 256 个原生 token 位置。这样,一个 c4a block 在物理上包含 256 / 4 = 64 个压缩 entry,一个 c128a block 包含 256 / 128 = 2 个。分配一个 block 始终意味着为某个请求的上下文保留接下来的 256 个原生位置,不管它属于哪一层。Slot mapping、scheduler accounting 和 prefix-hit detection 都可以使用同一个单位,而不需要基于 compress_ratio 分支处理。

(2) 将 compressor state 作为滑动窗口

每个 compressor 层还会为每个请求维护一个小的滚动 residual:C4 使用 8-token(重叠)的 partial state,C128 使用 128-token 的 partial state。一个自然的初始设计是把这个 residual 保存在每个请求的 side buffer 中。单独来看这可行,但一旦它需要与服务栈的其他部分交互,就会变得别扭。

使用 side buffer 时,prefix caching 需要在每个可缓存边界对滚动 state 做 snapshot,将其与 prefix hash 一起作为 key,并在命中时恢复。Disaggregated prefill 需要第二条传输路径,在把 KV block 从 prefill worker 发送到 decode worker 的同时发送 residual。每个需求单独来看都可管理,但合在一起会形成另一条需要跨特性维护的 state-management 路径。

vLLM 通过把 compressor state 当作 sliding-window KV 来避免这个问题。运行时 invariant 是相同的:每个请求固定大小,随 decode 推进而前移,窗口外 state 要么丢弃,要么通过 caching 处理。因此,我们将 compressor state 注册到 sliding-window KV cache spec 中,设置 sliding_window = coff * compress_ratio(C4 为 8,C128 为 128),并在同一个 hybrid KV cache manager 下将其放入 SWA 风格的 block。

这让多个服务特性可以复用同一抽象:

(3) 统一 page size

以上两个选择仍然不够。C4 indexer block、c128a KV block 和 c4a compressor-state block 的 page size(每个 block 的字节数)仍然不同。如果每种 cache 都有自己的 block pool,我们就会遇到原本想消除的跨 pool 碎片问题。

好在每种 cache 的 page size 都是 block_size * compress_ratio * per_entry_size 的乘积,而这三个因子都在我们的控制范围内。如果仔细选择,不同 cache 可以收敛到少数几个 page-size bucket,每个 bucket 都可以由一个共享 block pool 支撑。

在我们的实现中,整个五路 cache stack 可放入 三种 page size。每个 pool 在加载时只需确定一次大小,分配时就是一次 bucket lookup。没有运行时重新划分,没有按 cache kind 分开的 accounting,也没有 cache kind 之间的碎片。

保持 GPU 忙碌

内存布局只是运行时故事的一半;另一半是让 GPU 计算保持饱和。

vLLM 集成了 FlashMLA 和 FlashInfer,它们提供优化后的 attention 和 MoE kernel。但这个模型需要许多小型、主要受内存带宽限制的 kernel。我们需要避免额外 launch 和 HBM 往返,否则会拖慢完整 decode 路径。

图片 5:c4a decode 路径:带有 kernel fusion(彩色轮廓)和 multi-stream 分区(默认 stream = 蓝色带,indexer stream = 琥珀色带)的 operator graph。

c4a decode 路径:带有 kernel fusion(彩色轮廓)和 multi-stream 分区(默认 stream = 蓝色带,indexer stream = 琥珀色带)的 operator graph。

(1) Kernel Fusion

我们部署了三类 fusion 来减少内存往返。在下图中,它们表现为围绕若干 operator 组的彩色轮廓。

我们还复用了 DeepSeek V3.2 工作中的 fusion,包括 Q RoPE + quant + weight multiply,以及 attention 开始处 QK projection 之后 QK norm 的 horizontal fusion。

(2) Multi-stream

main attention 之前的操作高度可并行。它们可分为三部分:indexer computation、main-attention KV compression,以及 sliding-window token insertion。初始 projection 之后,这些分支几乎相互独立,因此我们在多个 CUDA stream 上重叠执行。这里也可以用另一种方式阅读同一张图:蓝色带表示默认 stream,琥珀色带表示 indexer stream。

通过这些重叠,在低 batch size 下,我们观察到 5-6% 的端到端延迟下降;这说明 decode 路径减少了 GPU 利用不足的时间,是一个有用信号。

此外,和其他模型一样,我们在 decode 路径上使用 CUDA graphs 来降低 launch overhead。

完整实现见 PR

计划中的工作

我们正在积极推进以下优化,以进一步提升 DeepSeek V4 在 vLLM 上的性能:

当前实现主要面向 NVIDIA GPU,包括 Hopper 和 Blackwell 架构。针对这些加速器的部署 recipes 可在我们的 recipe 网站找到。借助 vLLM 可扩展的 plugin system,硬件厂商可以直接为模型添加支持。例如,vllm-ascendvllm-mlu 都独立支持 DeepSeek V4。

致谢

我们感谢 DeepSeek 团队开源 DeepSeek V4,也感谢 DeepSeek 管理团队对 vLLM 的信任与支持!该模型支持得益于 Inferact Inc. 的贡献,这家公司致力于将 vLLM 发展为全球 AI inference engine,并通过让推理更便宜、更快速来加速 AI 进展。

附录:DeepSeek V4 Attention 机制背后的数学

为什么 key 和 value 共享时需要 inverse RoPE

给定位置 的 query token,应用 RoPE 后的 query representation 为 ,其中 是旋转矩阵,其旋转角由位置 参数化。旋转矩阵的一些基本性质包括:

给定一组位于 的 key token,应用 RoPE 后的 key representation 分别为 ,,...,,...。

对于位置 的 value vector,我们通常不对它们应用 RoPE。value representation 只是 ,,...,,...。

attention 输出随后为(为简化起见,省略了一些细节,例如 scaling factor):

attention 输出的一个良好性质是它具有平移不变性。任何依赖位置的因子,即 和 ,都只依赖 query 与 key 之间的相对位置。这意味着如果我们将 query 和 key 同时平移相同距离,attention 输出保持不变。

如果共享 key 和 value vector,attention 输出将变为:

此时输出会通过旋转矩阵 直接携带绝对位置信息。这不是我们想要的。修正方法很简单:对 attention 输出应用 inverse RoPE 操作:

这样,输出只会通过旋转矩阵 携带相对位置信息,并重新具有平移不变性。

类似讨论也可见于 https://kexue.fm/archives/10862

实现细节:精确的位置范围和因果性条件

处理压缩 KV cache 时需要小心。对于每个压缩 index ,我们先组合一组固定的局部原始 token,然后使用该压缩 token 的 anchor position 应用一次 RoPE,随后将这个压缩 token 存入 KV cache。

对于 c4a,第 个压缩 token 是位置范围 中 token 的加权和,其中 从 0 开始,负 index 被视为值为 0 的 token。应用 RoPE 时,该压缩 token 的位置是 。

对于 c128a,第 个压缩 token 是位置范围 中 token 的加权和,其中 从 0 开始。应用 RoPE 时,该压缩 token 的位置是 。

对于因果性,我们需要确保位置 的 query token 只 attend 到由位置范围 中 token 产生的信息。这意味着对于位置 的 query 和 KV cache 中第 个压缩 token,我们需要确保 (对于 c4a)或 (对于 c128a)。

实现细节:c4a 和 c128a 中 k 的精确值

在 DeepSeek V4 的 c4a attention 中, 的默认值为 512;在 c128a attention 中, 的默认值为 8192。(作为对比,在 DeepSeek V3.2 中, 的默认值为 2048。)

c128a attention 具有更高的压缩比例。在 100 万 token 上下文下,它最多拥有 8k 个压缩 token。8k token 对 attention 计算来说并不算多,因此我们可以直接对 c128a 压缩 token 使用 full attention。在实现上,我们仍可以将 c128a attention 表述为一个 sparse-attention 问题,其 top- 值为 8192。

实现细节:为什么需要短滑动窗口

使用 c128a 时,位置 的 query token 不能 attend 到 KV cache 中任何压缩 token,因为第一个压缩 token 包含来自位置 到 的信息,但由于因果性,query token 不能 attend 到位置 之后的信息。有了短滑动窗口,query token 可以 attend 到位置范围 中的未压缩 token,因此仍能访问局部信息。

8.7x 节省估算背后的算术

对于 1M 上下文的序列:

使用 bf16 KV cache 的 DeepSeek V3.2:

61 层、使用 bf16 KV cache 的 DeepSeek V4:

分享:

查看 Markdown 源码

上一篇 vLLM 中 FP8 KV-Cache 和 Attention Quantization 的现状下一篇 使用 vLLM 运行基于 NVIDIA Nemotron 3 Nano Omni 的高效多模态 Agentic AI

相关文章

使用 vLLM 运行基于 NVIDIA Nemotron 3 Nano Omni 的高效多模态 Agentic AI 2026 年 4 月 28 日·7 分钟阅读 我们很高兴在 vLLM 上支持新发布的 NVIDIA Nemotron 3 Nano Omni 模型。### 宣布 vLLM 支持 Gemma 4:逐字节看,能力最强的开放模型 2026 年 4 月 2 日·3 分钟阅读 随着 Gemma 4 发布,vLLM 立即支持 Google 最先进的开放模型系列,覆盖多种硬件 backend,并首次在 Google TPU 上提供 Day 0 支持,...### 使用 vLLM 运行高效且准确的 Multi-Agent AI:NVIDIA Nemotron 3 Super 2026 年 3 月 11 日·5 分钟阅读 我们很高兴在 vLLM 上支持新发布的 NVIDIA Nemotron 3 Super 模型。

目录

© 2026 vLLM·保留所有权利。

GitHubXLinkedInSlackDiscuss

译自 vllm-blog · 录于 二〇二六年五月三日