我们很高兴宣布 Model Runner V2(MRV2),这是 vLLM 模型执行引擎的一次从头重构。MRV2 带来了更简洁、更模块化、更高效的执行核心,而且 无需任何 API 变更。目标很简单:更好的代码,更好的性能。

和去年发布的 vLLM V1 类似,这次架构升级同样来自 vLLM 大量用户在真实场景中的经验教训以及社区反馈。我们重新审视了持久化批处理、异步调度、输入准备和采样等核心环节,并围绕三项原则重构了 model runner:

  • 模块化。 将模型专属逻辑与通用执行路径隔离。
  • GPU 原生。 将 bookkeeping 从 CPU 移到 GPU。
  • Async 优先。 将 CPU/GPU 重叠执行视为设计约束,而不是事后补丁。

MRV2 目前尚未完整支持所有特性,但你现在就可以试用:

export VLLM_USE_V2_MODEL_RUNNER=1

我们计划在不久的将来将 MRV2 设为默认。

为什么要做 Model Runner V2?

自 vLLM V1 去年发布以来,随着特性和优化持续叠加,model runner 积累了相当可观的技术债务。许多改动单独来看都很有价值,但随着异步调度和投机解码逐渐成为核心执行模型,整体实现变得越来越难以理解和维护。

这具体带来了几类反复出现的问题:

  • 持久化 batch 状态耦合严重。 持久化状态与 per-step 模型输入紧密耦合,使得请求插入、删除和重排序比本应有的复杂得多。
  • 异步执行脆弱。 Async scheduling 是在 V1 runner 上事后加装的,因此很多特性都需要不自然且异常复杂的逻辑才能与其共存。
  • CPU 侧 bookkeeping 成为瓶颈。 输入准备和采样依赖大量细碎的 CPU 端操作,而 GPU 越来越快,这部分开销就越显眼。
  • 扩展性差。 随着新模型和新特性的不断加入,整个 runner 越来越难以理解,也越来越难以干净地扩展。

MRV2 通过重新设计状态所有权和抽象边界来解决这些问题。

Model Runner V2 有哪些新变化?

1. 更好的持久化 Batch 设计与 GPU 原生输入准备

vLLM 需要为 batching、paged attention、sampling parameters 等维护大量 bookkeeping。历史上,这部分工作主要通过很多细碎的 CPU 侧操作完成。

为了降低这部分开销,vLLM V1 引入了持久化 batching:由于相邻两步的 batch 往往非常相似,增量更新缓存状态要比每步都从头构造大型 tensor 便宜得多。然而,V1 直接将持久化状态作为模型和采样器输入,这带来了别扭的布局约束,也让 bookkeeping 逻辑更加复杂。


图 1:V1 中的持久化 batch。请求顺序与 block table 布局紧耦合,当请求增删时需要复杂的重排序操作。

MRV2 将 持久化请求状态与 per-step 输入 tensor 解耦。每个活跃请求在其生命周期内都会在一个固定大小的状态表中占据稳定的一行。每一步执行时,runner 会根据当前请求顺序,通过 gather 操作从持久化状态中提取这一轮的输入。这样既保留了增量更新的性能收益,又移除了大量状态管理复杂性。它还消除了诸如 CachedRequestState 这类冗余备份状态,因为活跃请求不再依赖脆弱的整块 tensor 重排序。


图 2:MRV2 中的持久化 batch。稳定状态表独立维护,与 per-step 输入布局解耦。每步通过 gather 操作生成正确排序的输入 block table。

MRV2 还通过 Triton kernel 将 输入准备迁移到 GPU。请求状态主要保留在设备侧,input_idspositionsquery_start_locseq_lens 等 tensor 现在都直接在 GPU 上构建。这带来了三项具体收益:

  • 降低 CPU 开销, 避免大量 Python 和 CPU tensor 操作。
  • 降低代码复杂性, 去除 CPU 侧 tensor 操作所带来的布局约束。
  • 更好地兼容异步调度与投机解码, 因为驻留在 GPU 的输入准备可以直接消费设备侧结果,而无需同步。

2. Async 优先设计

异步调度现在已经是 vLLM 的核心机制。调度器和 worker 会在 GPU 执行第 N 步的同时准备第 N+1 步,通过 host 与 device 侧工作的重叠来最大化利用率。虽然 vLLM V1 也支持这一机制,但它更多是一种后加能力,而不是一等设计约束。


图 3:V1 中的异步调度。CPU 在 GPU 执行当前步的同时调度并准备下一步,实现 CPU 与 GPU 工作的重叠。

MRV2 将异步执行视为核心前提,并以在所有支持的模型与特性组合下实现 CPU 与 GPU 之间零同步 为目标。

尤其重要的是,MRV2 天然支持异步调度与投机解码同时启用,而这在 V1 中很难做到足够干净。由于 MRV2 的输入准备运行在设备侧,prep kernel 可以直接消费 GPU 产生的 rejection sampling 结果。每一步输出都通过独立 CUDA stream 异步传回 CPU,与主计算流完全解耦。同样的设计也延伸到了带结构化输出的投机解码场景。


图 4:MRV2 的异步调度与投机解码组合。GPU 侧 prep kernel 直接消费 rejection sampling 结果,消除 CPU–GPU 同步点。

3. Triton 原生采样器

MRV2 使用优化后的 Triton kernel 重写了采样逻辑,在显存使用和数值控制上都更好。具体包括:

  • Gumbel-Max 采样 kernel,避免显式 materialize softmax,并使用 kernel 内无状态 RNG。
  • 更高效的 top-k logprobs,先找出 top-k logits,再仅对这些候选计算 logprobs。
  • 更省显存的 prompt logprobs,通过更细粒度的 chunking,包括单个 prompt 内部的 chunking,降低峰值显存。
  • 更好的投机解码兼容性,在 kernel 内通过间接寻址 idx_mapping 处理,而无需把请求状态展开成与每个 logits 向量一一对应。

这些改动共同降低了峰值显存占用,也让支持更复杂的采样参数组合变得更容易。

4. 更强的模块化

vLLM 需要支持很多不同的模型架构,因此现有 model runner 逐渐积累了大量复杂性。MRV2 通过一个新的抽象来应对这一点:ModelState

class ModelState(ABC):
    def add_request(self, ...):
    def remove_request(self, ...):
    def get_mm_embeddings(self, ...):
    def prepare_inputs(self, ...):
    def prepare_attn(self, ...):
    def prepare_dummy_inputs(self, ...):
    ...

ModelState 定义了模型专属逻辑的接口,例如多模态 embedding、额外模型输入、attention metadata、CUDA graph 捕获等,从而让主 runner 可以专注于通用执行路径。这直接回应了用户和贡献者常见的一个抱怨:vLLM 支持的模型太多,以至于共享代码显得相当绕,特别是对于只关心某一类模型,例如 DeepSeek、Qwen、Kimi 或内部私有模型的开发者来说更是如此。

此外,MRV2 还把 runner 拆成了职责更清晰的多个小文件。原来的执行引擎 gpu_model_runner.py 已经膨胀为超过 6700 行的单文件;而在 MRV2 中,最大的单文件已控制在 1300 行以内。

性能

MRV2 不只是一次代码清理,它已经带来了可量化的收益。

我们通过在一张强算力 GPU(1×GB200)上运行一个非常小的模型(Qwen3-0.6B)来刻意放大 host 侧开销的相对占比。在这个配置下,MRV2 通过将输入准备迁移到 GPU,实现了 56% 的吞吐提升


图 5:MRV1 与 MRV2 在 Qwen3-0.6B × 1×GB200 上的吞吐对比。MRV2 达到 25K output tok/s,相比 MRV1 的 16K 提升 56.2%。

我们还测量了投机解码场景下的收益:在 4×GB200 上,使用 GLM-4.7-FP8MTP=1TPOT 降低了 6.3%。这一提升来自 MRV2 的零同步设计,当投机解码启用时,CPU–GPU 同步点被完全消除。


图 6:MRV1 与 MRV2 在 GLM-4.7-FP8 with MTP=1 × 4×GB200 上的 TPOT 对比。MRV2 在各请求速率下 TPOT 均降低 6.3%。

随着推理服务栈不断叠加异步调度、投机解码、多模态预处理以及越来越异构的模型状态,我们预计这套架构基础的价值只会越来越明显。

限制与当前状态

MRV2 目前仍处于实验阶段,并在积极开发中。设计已经明显更干净,早期结果也很鼓舞人心,但 MRV2 还没有完整支持所有特性。截至 v0.18.0,以下功能 暂不支持

  • Linear attention 模型(Qwen3.5、Nemotron 3 Super)
  • Eagle/Eagle3/MTP 以外的投机解码方法
  • EPLB 和 DBO
  • Logits processors
  • LoRA

完整列表请参考设计文档的第二页。

我们对 MRV2 设定了更高的质量门槛:当把 V1 的某个特性带入 MRV2 时,我们希望从第一性原理重新审视,而不是机械地把已有复杂性搬过去。因此,涉及 MRV2 的改动可能会比平时需要更长的评审周期。

快速上手

  1. 安装最新版 vLLM。
  2. 设置 export VLLM_USE_V2_MODEL_RUNNER=1
  3. 像往常一样使用现有 vLLM API,无论是 Python API 还是 vllm serve

不需要任何面向用户的 API 变更。

致谢

Woosuk Kwon、Nick Hill、Giancarlo Delfin、Santino Ramos(Inferact)、Wentao Ye、Zhanqiu Hu、Lucas Wilkinson(Red Hat)、Haoran Zhu(Alibaba)

相关链接