快是可以生成的,可信只能证明(vLLM 重写 Kimi K3 解码路径,以及怎么放心合并 Agent 写的内核)
vLLM 重写 Kimi K3 的 batch-1 解码路径,把又多又碎的内核合并起来;更值得抄的,是怎么验证 Agent 写的内核真的可信。
让代码变快,已经不是最难的部分了。
难的是,你敢不敢把它合进去。
10 月 16 日,vLLM 官方博客发了一篇文章,作者是 NVIDIA 的 Benjamin Chislett。
表面上,这是一篇性能文章:Kimi K3 单条请求的解码,提速 1.6 到 1.9 倍。
但如果你只看到这个数字,你就错过了真正值得带走的东西。
据 vLLM 博客,这条专用解码路径是工程师在 Agent 辅助下写出来的。而文章花了同样多的篇幅,去回答另一个问题:
这种代码,凭什么让人放心?
为什么一条请求会慢
先把问题本身拆开。
Kimi K3 是一个 2.8T 参数的多模态 MoE 模型。每个 token 只激活 896 个专家里的 16 个,最长支持 1M 上下文,权重原生就是 MXFP4(据 vLLM 7 月 27 日的 day-0 博客)。
听起来,每次只算一小部分,应该很快。
现实不是这样。
batch 很小的时候,GPU 大部分时间不是在算,而是在等。
等什么?
等权重从显存里搬出来。等一个内核结束、下一个内核启动。等卡和卡之间把结果对齐。
据博客,原因是内核太多太碎,以及受内存带宽限制。
原版 vLLM 跑这个模型,每一层要启动 23 个内核,耗时 130 微秒。
换句话说,瓶颈不在算力,在调度和搬运。
(这也是为什么"单用户也要快"这件事,比大多数人以为的更难。)
他们换掉了什么
新路径几乎把所有算子都换成了定制的 CuTe DSL 内核。
目标环境很窄:NVIDIA Blackwell(GB300),8 卡或 16 卡在同一个 NVLink 域里,解码 batch 在 1 到 64 之间,可以选择打开解码上下文并行(DCP)。
结果是:每层 13 个内核,69 微秒。
手法可以归成四类。
- 按 batch 选内核形状。batch 1–2 用小矩阵内核,更大的 batch 用 split-K。
- 计算和通信重叠。注意力的输出投影直接融合 all-reduce 和后面的 attention-residual,GPU 把部分结果写进 NVLink 可访问的缓冲区。
- 不让每张卡做重复的活。MoE 路由打分和潜空间投影在各个 TP rank 之间拆开算,共享专家放进单独的 stream。
- 利用等待的时间。通信期间,用旁路 stream 把下一步的权重预取进缓存。
注意这几条的共同点。
没有一条是"让算术更快"。
每一条都是在消灭等待。
数字(以及一个必须澄清的数字)
据 vLLM 博客,不开投机解码、看整组吞吐:
- TP8,batch 1:193.3 tok/s,是原版的 1.58 倍。
- TP16,batch 1:256.4 tok/s,1.88 倍。
- TP16,batch 64:3,606.1 tok/s,1.62 倍。
打开 DSpark 投机解码(7 个草稿 token,合成接受长度 6),TP16 batch 1 达到 842 tok/s,原版同样设置是 488,1.73 倍。
还有一组 AgentX 测试,回放真实编码 Agent 会话的流量模式:P90 交互速度 403.2 对 223.7 tok/s/user。需要注意,这组对比的是 16 卡优化版和早前的 8 卡结果,卡数不一样,不能当作同条件对比。
然后是那个在 X 上被热议的数字:423 tok/s。
423 tok/s 不是 vLLM 这次的成绩。 它出自 SGLang 7 月的 day-0 博客,条件是 8×GB300 加 DSpark,是另一个推理框架、另一个时间点的数字。
把它和上面任何一个 vLLM 数字放在一起比较,都是在比较两件不同的事。
这本身就是一个关于验证的小教训。
真正的问题:谁来为 Agent 写的内核担保
现在进入这篇文章最重要的部分。
Agent 能写内核。这已经不新鲜了。
新鲜的是:当 Agent 写得足够快,人的审读就跟不上了。你不可能逐行读完每一个融合内核,再凭直觉判断它对不对。
所以,"它看起来没问题"不再是一个合格的标准。
速度可以被生成。可信度只能被证明。
vLLM 给出的回答,是一套叫作"快且负责"的规则。四条。
1) 隔离改动
只改这个模型自己的代码。
采样、KV cache 管理这些共享组件,一律不碰。
道理很简单:如果出了问题,你希望它只影响一个模型,而不是所有用户。隔离不是保守,是给自己留一条可以退的路。
2) 限定范围,但不许砍掉生产需要的东西
这条路径本来就窄:特定硬件、特定卡数、特定 batch 区间。
窄是可以的。
但全上下文、温度采样、结构化输出,这些生产里必须有的功能,不能被"优化掉"。
这里有一个很常见的陷阱:一个系统跑得飞快,是因为它悄悄不做某些事了。你以为得到了速度,其实是丢了功能。
3) 系统性地验证正确性
内核测试要有,模型评测也要有。两者缺一不可。
而且有一个容易被忽略的要求:测试必须真的走到新的代码路径。
如果评测跑完了,全绿,但请求根本没经过新内核,那这份绿色什么也证明不了。
4) 广泛地测性能
扫 batch,扫上下文长度,扫并行配置。
MoE 模型要用真实的提示词。路由会跟着输入走,假的输入可能让负载看起来比真实情况更均匀(这是我的推断,博客原文只要求用真实提示词)。
除此之外,vLLM 还提出了一个"自带 GPU 跑评测"的 RFC。
踩过的坑,才是最有价值的部分
博客没有只讲成功。它也讲了踩过的坑。
一个是:审计时发现,编译器把激活的读取,挪到了同步等待之前。
也就是说,代码写的顺序是对的,编译出来的顺序不对。数据可能在还没准备好的时候就被读走了。
修法是:只对静态权重用那种加载方式。权重不会变,提前读没关系。激活会变,必须等。
另一个是:MRCR、AIME25 这类长上下文、长生成的评测,暴露了一些数值问题。这些问题,用 mock 输入的单独内核测试复现不出来。
这些坑说明了同一件事。
单元测试证明的是"这个零件在实验室里没问题"。
只有端到端、长序列、真实负载,才能证明"这个零件装进整台机器以后没问题"。
如果你只做前者,你得到的是一种虚假的安全感。
这套方法在往外走
据博客,同样的设计正在用到别的模型上。
DeepSeek-V4.1-Flash 走同样的设计(PR #61868)。Meta Muse Spark Open 发布两天内,早期结果超过每用户 950 tok/s(K=7、AL=6)。GLM5.3 的低并发优化也在做。
新路径的开关是 decode_backend: latency_specialized,需要你主动选择启用。
默认不开。
这个设计本身也是一种态度:快,是一个选项,不是一个强加给所有人的默认值。
写在最后
很多人看 Agent 写代码,盯着的是产出速度。
这个案例给的是另一个视角。
当生成变得便宜,稀缺的东西就变成了判断:哪些改动可以隔离,哪些功能不能砍,哪些测试真的走到了新路径,哪些数字是在同一个条件下比出来的。
这些判断,Agent 不会替你做。
你可以让 Agent 写内核。
但证明它是对的,是你的工作。
来源:vLLM 博客(2026-10-16);vLLM Kimi K3 day-0 博客;SGLang day-0 博客。性能数字为 vLLM 博客自报,未见第三方复现;423 tok/s 为 SGLang 在 8×GB300 加 DSpark 上的 day-0 数字,不是 vLLM 成绩,未作对比;AgentX 两组数字卡数条件不同。