模型没换、硬件没换,Agent 吞吐提升 5 倍:vLLM 如何优化 DeepSeek-V4.1-Flash
同一个模型,参数没动、硬件没换,三周之后 Agent 场景的吞吐量翻了 5 倍。变的不是模型,是"怎么把它跑起来"。
10 月 7 日,vLLM 官方博客发了一篇技术复盘:Inferact 与 vLLM 社区在 DeepSeek-V4.1-Flash 发布后的三周里,把它在 Agent 服务场景下的性能大幅拉高 —— 低延迟场景快 1.9 倍,高吞吐场景约 5 倍,典型负载下首 token 延迟(TTFT)降幅接近 70%。
这件事值得看的不是"5 倍"这个数字本身,而是官方把 5 倍拆开了:哪一分提升来自哪一次内核融合、哪一段来自跳过哪一层,都写清楚了。如果你在自部署模型、或者在做 Agent 类产品,这里面大部分方法可以直接搬。
一、先搞清这个模型特殊在哪
不先理解模型的设计,后面那些优化看起来会像玄学。
DeepSeek V4.1 用的是一种叫 因果编码器-解码器(CED) 的架构。它最反直觉的一点是:解码时每个 token 激活 16B 参数,但预填充(prefill)时只激活 8B 参数。也就是说,处理你喂进去的那一大段输入,比逐字往外吐字要"便宜"。
内存上它也很激进。为了压小 KV cache,它叠了三样技术 —— 压缩稀疏注意力 CSA2、FP4 KV 缓存、以及层间 KV 缓存共享,最终把全局 KV 占用压到每 token 890 字节。
而且它保留的是两种 KV:
- 全局 KV:经过压缩、跨层共享、以 FP4 存储,每 token 约 890 字节;
- 滑动窗口 KV(SWA KV):不压缩、以 FP8 存储,覆盖 40 层中每一层的最后 128 个位置。
问题恰恰出在第二种上。这个 128 位置的小窗口,看起来不起眼,却制造了两笔很贵的账。
二、第一招:SWA 有界重放,把"精确"换成"够用"
两笔算不过来的账
SWA KV 带来两个成本:
- 前缀缓存放不下它。引擎要在每一个可能的命中边界都存一份 SWA KV,存储开销超过全局 KV 的 10 倍。
- 预填充白干了半截活。prefill 要在每个输入 token 上都跑一遍第 21–39 层,可解码阶段实际只会读它们最后 128 个位置。
那最直接的办法是不缓存、用时重算?更贵。因为每一层的 128 token 窗口都依赖下一层更早的位置,跨越 L 层重建它,等于要重放大约 L × 128 个 token。
DeepSeek 给出的中间路线叫 SWA 有界重放(SWA bounded replay):只重跑最后 128 个 token,并在重放起点处把 SWA 窗口裁掉。代价是结果不再逐位精确,换来的是可用的速度。DeepSeek 官方报告称质量损失可忽略。
vLLM 在两个地方各用了一次
正好对应上面那两笔账:
- 编码器侧(对付存储开销):vLLM 只缓存全局 KV,干脆不存 SWA KV。当命中长度为 H 的前缀时,它重新跑一遍
[H − 128, H)这一段来把 SWA KV 重建出来,窗口在s = H − 128处裁剪。 - 解码器侧(对付那半截白干的活):在 CED 架构里,第 20 层负责算出解码器要用的全局 KV,第 21–39 层复用它。于是 vLLM 只在每个 token 上跑第 20 层,而第 21–39 层只在每个请求的最后 128 个 token 上跑。对于长提示词,这一下就跳过了将近一半的模型。
真正的功臣:给被裁剪的层套上 CUDA graph
裁剪之后的第 21–39 层,在 GPU 上干的活少得可怜。这时候如果按 eager 模式跑,内核启动的开销反而成了大头,GPU 大部分时间在空转。
麻烦在于它们的输入形状跟第 0–20 层不一样,没法塞进同一个 CUDA graph。好在 vLLM 的可中断 PIECEWISE graph 本来就会在模型中间断开,这提供了一个天然的切分点:第 0–20 层按完整批次捕获,第 21–39 层按裁剪后的批次单独捕获。这样不仅让 CUDA graph 能用在裁剪后的 prefill 上,还让被裁剪的层能用自己合适的捕获尺寸。
官方实测的数字是:带 CUDA graph 的解码器侧重放,把 prefill 的计算时间砍掉了 30–40%。
这里有个特别值得记的反直觉细节 —— CUDA graph 对短提示词最关键。短提示时内核启动就是瓶颈:不用 CUDA graph,启动开销会盖过 GPU 省下的那点时间,重放反而比基线更慢(在 DEP2 上、1K 长度时最多慢 12%)。而长提示本身计算量够大,能盖住启动开销,eager 重放就能拿到大部分收益。
顺便说一句,这个特性在 DeepSeek-V4.1 上是默认开启的,用 --[no-]swa-bounded-replay 控制。
三、第二招:把能合的内核全合成一个
如果只看"5 倍",会以为是某个大招。实际上除了上面那条主线,其余是一大堆细活累出来的。DeepSeek 在发布模型时,同时在三个代码仓库里放出了新内核(DeepSelect、DeepGEMM 的稀疏索引器内核、FlashMLA 的 MegaAttention),vLLM 把这些开源内核接进来,又进一步做了融合。
挑几个有代表性的:
- Mega-mHC(PR #56962):把 mHC 链条 —— post 步骤、延迟的 pre 步骤、RMSNorm —— 融成一个内核,取代原有的 TileLang 融合路径。在 NVIDIA GB200 上比 TileLang 版本快 1.14–1.51 倍。
- Mega-Gate(PR #56266):把 MoE 路由器(gate GEMM、专家打分、偏置、top-k 选择)融成一个内核。以前是"一个 GEMM 接一个独立的 top-k 内核",白多一次启动、还让打分结果在内存里走一个来回。中等批次大小下内核提速 1.18–1.31 倍。
- mHC 多流重叠(PR #57603):让下一个 mHC 块的系数在侧 CUDA 流上算,与注意力和 FFN 并行。在 TP4 低延迟场景下延迟降约 4%。
- 稀疏 MQA logits(PR #56254):以前的实现要给整个上下文打分再把非候选块屏蔽掉;换成 DeepGEMM 的稀疏内核后只给候选位置打分,开销不再随上下文增长。在 NVIDIA GB300 上,每层 8K token 时快 1.2 倍、512K 时快 14–23 倍;4 卡 GB300 端到端解码提升 3–6%,prefill 在 512K 时快 1.43 倍、1M 上下文时快 2 倍。
- MegaAttention + NVFP4 压缩 KV(PR #56935):一次启动里做完 query RoPE、稀疏注意力、输出逆 RoPE 和 FP8 转换,直接写进输出投影要读的缓冲区。它读的是新的 NVFP4 压缩 KV 格式,比原来的 FP8 KV cache 小 45%;通过激进融合消掉操作之间的 HBM 写入,内核效率提升 1.45 倍。
- 低延迟融合 WO-A 内核(PR #58634):把小批量解码链路上的三个内核收成一个,融合路径最多提速约 2.1 倍,低并发下 token 间延迟降 6–7%。
- Engram 的几处调整:异步预取 CPU 卸载的查找表,把主机内存访问与解码计算重叠;分片方案让同址的副本共享同一份主机表;对大型驻留主机表启用透明大页(THP)减少缺页开销,prefill 的查找内核最高快 10 倍。
这些改动都在 vLLM 仓库里公开,进度统一跟踪在 issue #57448。
四、成绩单
口径要分开说,因为官方在不同位置给了不同的说法,容易混:
- 官方 TL;DR 的口径:三周内低并发加速 1.9 倍,在 150 TPS 约束下吞吐提升 5.3 倍;其中 SWA 有界重放配合 CUDA graph 让 TTFT 降了约 30%。
- 正文的表述:低延迟结果相比 day-0 实现提升 1.9 倍,高吞吐结果提升约 5 倍。
- TTFT:在约 100K 吞吐量附近,SWA 有界重放 + CUDA graph + 内核改进三者叠加,TTFT 下降近 70%。
"day-0 实现"指的是模型发布当天 vLLM 给出的初版支持。换句话说,这三周并没有换过模型,改的全是服务侧。
测试用的配置也值得记一下,因为它解释了两种场景为什么选不同路数:
- 要低延迟:用 TP4 配 FlashInfer 注意力。小批量解码主要吃内存带宽,把权重摊到 4 张卡上正合适。他们也试了 MegaAttention,但它的长处在高吞吐场景(融合更有发挥空间),TP4 下收益小得多,最终 FlashInfer 更快。
- 要高吞吐:切到 DEP2,用 DP 注意力、专家拆到各卡。因为 V4.1 所有 head 共享同一份 KV latent,用 TP 会在每张卡上重复存 KV;DP 不重复,每张卡只为自己服务的请求存 KV,再靠会话亲和性保住多轮对话的 prefix cache 局部性。MegaAttention 再用 NVFP4 把每请求 KV 占用砍到差不多一半,等于提高了单卡并发数。
还有一个挺说明问题的观察:整个基准测试过程中,压根不需要做 KV cache 卸载(offloading)——模型本身的内存效率就够了。官方预计要到并发更高、配合 P/D 分离时,卸载才会开始起作用。
五、为什么偏偏是 Agent 场景能提这么多
这部分是理解全文的钥匙。
测试基准叫 SemiAnalysis AgentX,是 SemiAnalysis 基于真实 agentic 编程 trace 做的公开基准(约 300 万美元的真实调用轨迹、1M 上下文,跑在超过 1000 块芯片、约 2 兆瓦的公开基准设施上)。它描绘出的 Agent 负载长这样:
- 会话是长的、多轮的:单会话轮数中位 43 轮;
- 输入巨长、输出很短:输入中位 142K token,输出中位只有 444 token;
- 前缀复用率极高:prefix cache 命中率超过 96%;
- 子 agent 很多:44% 的会话至少包含一个子 agent,这些会话里子 agent 的中位数是 4 个。
为什么会这样?因为 Agent 的每一轮,都是"把最新的工具返回结果接进已有上下文,再把整个上下文重新发一遍"。输入越滚越大,每轮真正新增的 prefill 却很短,请求里绝大多数内容引擎早就见过了。
这就解释了为什么 vLLM 那些优化在 Agent 场景特别划算:超长输入 + 高缓存命中 + 短输出,正好命中"跳过一堆 prefill 计算"和"把长上下文里的打分开销变常数"这两条路。前面说的稀疏 MQA 内核"开销不再随上下文增长",在这个负载下就不是锦上添花,而是翻倍级别的改进。
六、对自部署的人,这几条能直接用
- 先想清楚自己是低延迟还是高吞吐。这不是一句废话 —— 官方在两种场景下选了完全不同的并行方案(TP4 + FlashInfer vs DEP2 + DP),而且明确说了某个看起来更"高级"的内核在低延迟场景反而不如老方案。
- 别忽视内核启动开销。CUDA graph 那一段是全文最"反直觉但最实用"的部分:短提示下,加 CUDA graph 才是正收益,不加反而比不改更慢(最多 +12%)。凡是"优化了反而变慢"的情况,先怀疑启动开销。
- 精度换性能是有账可算的。SWA 有界重放不是精确计算,但它是默认开启的,官方在 GSM8K 和 GPQA 等基准上验证过,未观察到有意义的精度差异(差距约在 1.5 个标准误以内)。如果你对逐位一致性有硬要求,记得这个开关。
- 长上下文优化,先看"开销是否随上下文增长"。稀疏 MQA 那个 8K 快 1.2 倍、512K 快 14–23 倍的对比,本质就是"常数开销 vs 线性开销"的差别。这个思路在你的场景里同样适用。
七、需要留意的边界
- 所有性能数字都来自官方自测,跑的是 SemiAnalysis AgentX 基准。AgentX 的测试工具是公开的(
SemiAnalysisAI/agentx-harness),官方也给了可复现的入口,但具体到你的负载、你的硬件组合,数字必然不一样。 - "5 倍"是相对 vLLM 自己的 day-0 实现,是纵向对比,不是跟其他推理引擎横向比较。
- 精度结论是"可忽略",不是"完全无损"。官方措辞是"未观察到有意义的精度差异",并给了统计口径(约 1.5 个标准误以内)。学术上严谨,媒体转述时容易被说成"毫无损失",别这么理解。
- 文中涉及的部分技术(CED 架构、SWA 有界重放)是 DeepSeek 在模型层的设计,vLLM 做的是把它接住、并在系统层面放大。功劳归属官方在致谢里写得很清楚:DeepSeek、Inferact、NVIDIA,以及提供基准的 SemiAnalysis。
一句话总结
模型发布之后的"第二段优化",往往比赛前那几十天更能决定你的账单。这次 vLLM 的 5 倍,主线只有两条 —— 把"精确但昂贵"的重算换成"够用且便宜"的有界重放,再把一堆零碎内核揉成少数几个。至于那些具体数字,等你自己在自家负载上跑一遍才算数。
参考来源
- vLLM 官方博客《DeepSeek-V4.1-Flash on vLLM: 5x Agentic Throughput Since Day 0》(2026-10-07):vllm.ai/blog/2026-10-07-deepseek-v41-flash
- vLLM 官方博客《vLLM x AgentX: Optimizing for Real-World Agentic Serving》(2026-09-08):vllm.ai/blog/2026-09-08-vllm-agentx(AgentX 基准的负载特征与"每 GPU 每秒 token 数"等口径出自此文)
- vLLM 内核集成进度跟踪:vllm-project/vllm issue #57448
- 本文为技术解读稿,所有性能与精度数字均引自上述一手来源,未做本机实测;文中 PR 编号均为 vLLM 仓库公开记录。

