@kazukifujii: 这篇vLLM博客文章以非常清晰和图示化的方式解释了强化学习中的权重更新和KV缓存重计算,还涵盖了…
摘要
本文解释了vLLM用于强化学习的权重同步API,涵盖了它如何促进RL训练中的权重更新和KV缓存重计算,重点关注降低训练框架的复杂性。
查看缓存全文
缓存时间: 2026/06/23 03:59
这篇 vLLM 博客以非常清晰且图文并茂的方式解释了 RL 中的权重更新和 KV 缓存重计算,并且还介绍了 vLLM 最近引入的用于权重同步的 API,因此我认为这是一篇必读文章。但根据我的观察,它似乎并没有得到太多关注……
作为参考,我也写过一篇关于前半部分的清晰日文文章,请务必查看。 (我原本也打算写后半部分,但没能抽出时间……) https://zenn.dev/kaz20/articles/e3c5dfc5111f1d…
vLLM 博客:
RLVR 时代的推理框架:权重同步篇
来源:https://zenn.dev/kaz20/articles/e3c5dfc5111f1d
引言
我是东京科学大学(https://www.isct.ac.jp/en)博士课程的藤井(https://okoge-kaz.github.io/)。
本文是系列文章的一部分,该系列旨在解释在 RL(强化学习)盛行的当下(2026 年),vLLM 和 SGLang 等推理框架为 RL 提供了哪些功能,以及这些功能是在何种意图/背景下扩展的。本文将重点聚焦于 Weight Syncing,它在实现 Coding Agent(如 Claude Code 和 Codex)所需的 Reasoning LLM 开发中,于 RLVR(基于可验证奖励的强化学习) 方面扮演着重要角色,并解释推理框架在其背后提供了哪些功能支持。
vLLM 标志 (https://vllm.ai/)
Weight Syncing
本文将解释主要推理引擎之一 vLLM 中 Weight Syncing 功能的实现背景,以及 vLLM 提供此功能支持所带来的好处。
Weight Syncing 背景
在 同策略/同步 RL 设置中,需要尽量保持 Trainer 端更新的策略与 Generator 端生成 rollouts 的策略之间差异尽可能小。即使在允许一定 policy lag 或 stale rollouts 的 异步 RL 设置中,rollouts 生成与训练异步进行,这一点也同样重要。通过将 Generator 使用的模型权重更新为最新或足够近期的版本,可以避免当前 Trainer 策略混入过于陈旧的 rollouts,从而更容易保持训练信号(training feedback)的有用性。
关于前提的说明有点长,但简而言之,RL 中需要权重同步。而这项权重同步工作,传统上并非由推理引擎承担,而是由各个 RL 训练框架分别负责。以 vLLM 为例,通常是通过扩展 vLLM 工作节点,使其接收权重并加载权重来实现的。当然,这种 vLLM 扩展是有效的,但也存在以下问题:
- 训练框架端复杂性增加:将 vLLM/SGLang 自定义工作节点扩展的实现/维护成本 强加给了训练框架开发者。如果推理引擎端本身具备权重同步功能,就能解决此问题。
- 不同训练框架之间重复工作:许多 RL 框架采用了类似的数据包张量传输、RPC 端点等实现。仅就 NeMo-RL、slime、verl 等知名 RL 框架而言,类似的实现就已经重复,非常浪费。
- 锁定到特定版本:许多框架针对特定 vLLM/SGLang 版本,以补丁形式在接收权重后临时实现预处理/后处理逻辑。因此,如果推理引擎版本不同,可能无法正常工作,给用户和开发者都带来成本。
基于以上背景,vLLM 开始原生支持用于权重同步的 API。下一节将介绍 vLLM 支持了哪些 API 及其概要。
原生权重传输
vLLM 中的新 API
vLLM 支持的权重同步 API 主要分为以下四类:
- 初始化:
init_weight_transfer_engine。在启动训练循环之前,负责建立训练工作节点(进程)与推理工作节点之间的通信通道。 - 开始权重更新:
start_weight_update。在训练循环中,每次训练步骤后或间隔多个步骤时调用,通知 vLLM 工作节点开始权重更新处理。调用此 API 后,vLLM 工作节点准备接收新权重。 - 更新权重:
update_weights。用于用 Trainer 接收到的权重更新推理引擎端的权重。更新目标可以是整个模型,也可以是部分权重。对于大型模型,可以不一次传输所有权重,而是通过分块权重多次调用update_weights来逐步加载权重。 - 完成权重更新:
finish_weight_update。用于结束权重更新的 API。如果需要对接收到的权重进行量化等后处理,此 API 是执行的起点。
这些 API 在 vLLM 的 API 服务器模式和引擎模式下都已实现。此外,作为权重同步(权重传输)的通信后端,目前支持以下两种:
- NCCL:利用 NCCL 广播操作从训练工作节点传输权重的后端。由于训练工作节点和推理工作节点通常位于不同的 GPU 上,因此通过 NCCL 通信实现权重传输。
- IPC:对于同一设备内的权重传输,利用基于共享内存句柄的 CUDA IPC 进行权重传输。
实现以上权重传输的核心传输逻辑,以可插拔的抽象实现 WeightTransferEngine 的形式提供(通过继承 WeightTransferEngine 类实现 NCCLWeightTransferEngine 和 IPCWeightTransferEngine)。这样将工作节点实现与权重传输实现分离,使得 vLLM 用户可以轻松集成自己的实现。
NCCL 权重传输引擎
IPC 权重传输引擎
初始化阶段和更新权重阶段通常由 RL 框架开发者自定义,传输逻辑也作为其中的一部分被使用。但不同于以往所有工作都由 RL 框架端承担,通过利用 vLLM 的 API 实现,可以简化 RL 框架之间重复的实现(即替换为统一的 API 使用)。
下一节将介绍使用 NCCL 进行权重传输并在后处理中进行 FP8 量化的情况。
权重传输示例
来自 vLLM 博客:vLLM 中的原生 RL API (https://vllm.ai/blog/2026-05-28-native-rl-apis)
以下结合上图,对照如何调用 vLLM 的 API 进行说明。
- 设置权重传输引擎
如下所示,指定本次使用的 NCCL 作为通信后端,准备权重传输。
from vllm import LLM
from vllm.config import WeightTransferConfig
llm = LLM(
model="my-model",
weight_transfer_config=WeightTransferConfig(backend="nccl"),
)
- 初始化通信状态
上图中,/init_weight_transfer_engine 对应此步骤。设置通信所需的 MASTER_PORT、MASTER_ADDRESS,以及表示参与 NCCL 进程组的 ranks 数量的 world_size。通过这些设置,初始化训练工作节点与推理工作节点之间的通信状态。上图中的 init NCCL Process Group 正是通信进程组的初始化。
from vllm.distributed.weight_transfer.base import WeightTransferInitRequest
# 推理端初始化
llm.init_weight_transfer_engine(
WeightTransferInitRequest( # <--- 初始化参数
init_info=dict(
master_address=master_address,
master_port=master_port,
rank_offset=1, # <--- 考虑到 trainer rank 0 的偏移量
world_size=world_size, # <--- 训练工作节点 + 所有推理工作节点
)
)
)
# 训练端初始化
from vllm.distributed.weight_transfer.nccl_engine import (
NCCLWeightTransferEngine,
)
group = NCCLWeightTransferEngine.trainer_init(
dict(
master_address=master_address,
master_port=master_port,
world_size=world_size,
)
)
- 从训练工作节点发送权重
以下开始权重传输。使用 trainer_send_weights 方法发送从 iterator=model.named_parameters() 接收到的参数。NCCLTrainerSendWeightsArgs 可以指定是否使用打包张量广播以提高效率等选项。
from vllm.distributed.weight_transfer.nccl_engine import (
NCCLTrainerSendWeightsArgs,
NCCLWeightTransferEngine,
)
trainer_args = NCCLTrainerSendWeightsArgs(
group=group,
packed=True, # 使用打包广播以提高效率
)
# 从 `AutoModelForCausalLM` 实例发送权重
NCCLWeightTransferEngine.trainer_send_weights(
iterator=model.named_parameters(),
trainer_args=trainer_args,
)
- 推理引擎端接收权重
以下展示了从调用 update_weights 到调用 finish_weight_update 之间,接收权重并更新参数的过程。实现中省略了细节,但调用 finish_weight_update 后,如果正在进行量化,则会如上图所示接着执行 FP8 后处理等操作。
from vllm.distributed.weight_transfer.base import WeightTransferUpdateRequest
# 在训练端发送权重时异步执行
llm.start_weight_update()
llm.update_weights(
WeightTransferUpdateRequest(
update_info=dict(
names=names,
dtype_names=dtype_names,
shapes=shapes,
packed=True,
)
)
)
llm.finish_weight_update()
自定义权重传输
至此,我们解释了为什么需要权重传输,以及 vLLM 如何支持它。最后,我们概述了在进行自定义权重传输时如何进行扩展。
要定义自定义的 WeightTransferEngine,需要创建继承自 WeightTransferInitInfo 和 WeightTransferUpdateInfo 的独立数据类。WeightTransferInitInfo 和 WeightTransferUpdateInfo 本身是抽象类,几乎没有实际内容,因此建议参考 NCCLWeightTransferUpdateInfo、NCCLWeightTransferInitInfo 等实现。
以下示例创建了 MyInitInfo 和 MyUpdateInfo,并利用它们定义了 MyWeightTransferEngine。关于权重传输功能的更多详细信息,请参阅此处的 README (https://github.com/hao-aaron/vllm/blob/89c951b3296578c60cbb82e05ca3d1734364ba8c/examples/rl/sharded_reloading/README.md)。
from dataclasses import dataclass
from typing import Iterator, Callable, Any
from torch import Tensor
from vllm.distributed.weight_transfer.base import (
WeightTransferEngine,
WeightTransferInitInfo,
WeightTransferUpdateInfo,
)
# 定义用于初始化和更新权重元数据的自定义数据类
@dataclass
class MyInitInfo(WeightTransferInitInfo):
"""自定义初始化信息。"""
...
@dataclass
class MyUpdateInfo(WeightTransferUpdateInfo):
"""自定义更新信息。"""
...
# 自定义权重传输引擎
class MyWeightTransferEngine(WeightTransferEngine):
init_info_cls = MyInitInfo
update_info_cls = MyUpdateInfo
def init_transfer_engine(self, init_info: MyInitInfo):
...
def receive_weights(
self,
update_info: MyUpdateInfo,
load_weights: Callable[[list[tuple[str, Tensor]]], None],
):
...
@classmethod
def trainer_send_weights(
cls,
iterator: Iterator[tuple[str, Tensor]],
trainer_args: dict[str, Any] | Any,
):
...
# 最后,注册权重传输引擎
from vllm.distributed.weight_transfer import WeightTransferEngineFactory
WeightTransferEngineFactory.register_engine("my_weight_transfer", MyWeightTransferEngine)
结语
本文对 vLLM 支持的 Weight Syncing 功能进行了说明。从 RLVR 中为什么需要 Weight Syncing,到 Weight Syncing 是如何实现的,贯穿全文进行了讲解。关于异步 RL 中 vLLM 的权重更新功能,计划在后续的另一篇文章中说明。
我的其他文章介绍了 LLM 开发过程中的经验以及训练框架背后发生的情况,感兴趣的话也请一并查阅。
相似文章
@vivek_2332: 新博客:异步强化学习中的权重同步。权重同步最近变得快得多,即使在前沿模型上也低于2秒…
一篇探讨异步强化学习中权重同步技术的博客文章,涵盖了不同框架下传输和负载的权衡。
LoRA 与权重衰减 (2023)
这篇博客文章探讨了LoRA与权重衰减的相互作用如何导致与全参微调不同的优化目标,其中权重被正则化到初始模型而不是零。它解释了对实践者的影响。
CurveRL:面向LLM推理的基于分布感知的上下文权重调整原则性方法
本文介绍了CurveRL,一种基于原则的分布感知提示权重调整方法,用于带有可验证奖励的强化学习(RLVR),通过基于通过率的排名和密度而非绝对值来分配权重,从而改进LLM推理,持续优于GRPO及其他基线方法。
@pallavishekhar_: 大语言模型中的 KV Cache,阅读链接:https://outcomeschool.com/blog/kv-cache-in-llms…
本文解释了大语言模型中 KV Cache 的概念,详细阐述了其通过存储和复用键值对以避免推理过程中的冗余计算,从而优化文本生成的原理。
@amitiitbhu:新文章:vLLM 是如何工作的?请在此阅读:https://outcomeschool.com/blog/how-does-vllm-work…
一篇详细的博客文章,解释了 vLLM 的工作原理,包括 PagedAttention、KV 缓存管理和连续批处理,以实现高效的 LLM 服务。