首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >14-vLLM-SGLang-TRT-LLM在verl里如何被抽象

14-vLLM-SGLang-TRT-LLM在verl里如何被抽象

作者头像
anzhsoft
发布2026-07-06 14:13:39
发布2026-07-06 14:13:39
120
举报

上一篇说明了 rollout 是训练系统里的推理服务边界。这一篇继续向下看:如果 rollout 是服务,那么 vLLM、SGLang、TRT-LLM 这些后端在 verl 里是如何被选中、启动、调用和同步的?

本文的核心判断是:verl 没有让 trainer 直接依赖某个推理引擎 API,而是通过 rollout.nameBaseRolloutLLMServerManagerRolloutReplica和 backend adapter 把它们包成一个 RL-facing contract。但这层抽象是有意保持“薄”的:生成参数、多模态、logprobs、PD disaggregation、sleep/wake 和权重同步仍然保留后端差异。

先看抽象层次。读这张图时重点看:trainer 侧只需要选择 rollout backend;真正把名字翻译成 server replica 和 engine API 的,是 registry、server manager 和 replica 层。

rollout backend 抽象层

这张图的第一层是配置:rollout.yamlname可选择 hf/vllm/sglang/trtllmmode默认是 async,后面还有 backend 专属的 engine_kwargs.vllm/sglang/trtllmverl/trainer/config/rollout/rollout.yaml:1-8verl/trainer/config/rollout/rollout.yaml:130-140)。配置不是细节,它决定 trainer 后面进入哪条 server 适配路径。

1. BaseRollout定义的是最小合同

BaseRollout的接口很少:resume(tags)update_weights(weights, **kwargs)release()和 sync 模式的 generate_sequences(prompts)verl/workers/rollout/base.py:29-80)。async backend registry 则把 ("vllm", "async")("sglang", "async")("trtllm", "async")分别映射到对应的 ServerAdapter(verl/workers/rollout/base.py:83-104)。

这说明 verl 的抽象目标不是抹平所有后端行为,而是让 trainer 能稳定地说:“我要一个 rollout 角色,它能恢复状态、接收权重、释放资源、生成序列。”至于这个角色背后是 vLLM、SGLang 还是 TRT-LLM,要交给 server manager 和 replica 去处理。

LLMServerManager会根据 rollout_config.name和 disaggregation 配置解析 replica class,计算每个 replica 的 world size 和 replica 数量,然后在 hybrid、TRT-LLM colocated 或 standalone 路径下初始化 server,并创建全局 load balancer(verl/workers/rollout/llm_server.py:222-340)。RolloutReplicaRegistry再把 vllmsglangtrtllm注册到具体 replica loader;如果 SGLang 开启 PD disaggregation,会走 SGLangPDReplica分支(verl/workers/rollout/replica.py:302-402)。

2. 共同的 generate 合同长什么样

下面这张图把 backend adapter 的共同输入输出压成一张图。看图时注意:共同点不是“调用同一个库”,而是都要从 prompt ids、sampling params、多模态输入和 request id 出发,最终返回 token ids、logprobs、stop reason 等 RL 可消费字段。

共同的 generate 合同

三条后端路径都能看到这个形状。vLLM server 的 generate()接收 prompt_idssampling_paramsrequest_id、image/video/audio 和 processor kwargs,计算 max_tokens,构造 vLLM SamplingParamsTokensPrompt,再调用 engine 生成(verl/workers/rollout/vllm_rollout/vllm_async_server.py:447-535)。SGLang server 的 generate()接收类似输入,把 max_tokens/max_new_tokens转成 SGLang 请求,构造 GenerateReqInput,再通过 tokenizer manager 发起生成(verl/workers/rollout/sglang_rollout/async_sglang_server.py:496-606)。TRT-LLM server 也接收相同大类输入,构造 TensorRT-LLM SamplingParams,再调用 llm.generate_async()verl/workers/rollout/trtllm_rollout/trtllm_async_server.py:313-382)。

所以,抽象的核心收益是让上层 RL 流水线拿到稳定的 token output,而不是在 trainer 里到处写 vLLM/SGLang/TRT-LLM 的分支。

3. 这层抽象在哪里会变薄

下面这张图列出后端差异会泄漏的地方。它和上一张图互补:上一张图说明共同合同,下面这张图说明为什么共同合同不能被误读成“所有 backend 完全等价”。

backend 差异泄漏地图

vLLM 路径用 max_tokens,但也兼容 SGLang 风格的 max_new_tokens;它会把 logprobs映射到 vLLM 的 SamplingParams,并通过 TokensPrompt组织多模态输入和可选 LoRA request(verl/workers/rollout/vllm_rollout/vllm_async_server.py:461-526)。

SGLang 路径默认使用 max_new_tokens,也兼容 vLLM 风格的 max_tokens;它有 PD disaggregation 分支,prefill 侧会创建 bootstrap room,并并发本地 prefill 和远端 decode;同时还会处理 prompt logprobs 和 routing replay(verl/workers/rollout/sglang_rollout/async_sglang_server.py:507-606)。

TRT-LLM 路径会把 top_k == -1转成 0,logprobs 在 torch sampler 和 TRTLLM sampler 下映射不同;VLM 场景会构造带 multi_modal_data的 input dict,但 audio 当前直接报 NotImplementedErrorverl/workers/rollout/trtllm_rollout/trtllm_async_server.py:325-382)。

这些差异不是抽象失败,而是抽象边界的真实含义:trainer 不需要知道每个后端的 API 细节,但系统工程师调性能、看错误、查 logprobs 或做多模态/PD 时,必须知道差异在哪一层。

4. backend 抽象还包括生命周期

rollout backend 不只负责生成,还要负责训练和推理之间的状态切换。下面这张图把 placement mode、生命周期 API 和权重路径放在一起看。

rollout 生命周期和权重同步合同

RolloutMode把部署模式分成 hybrid、colocated 和 standalone:hybrid 表示 rollout engine 和训练 engine 共享 GPU 并通过权重同步切换上下文;colocated 表示同 placement group 里的独立进程;standalone 表示单独 GPU 资源,常用于解耦或 off-policy 场景(verl/workers/rollout/replica.py:54-68)。

replica 层提供 wake_up()sleep()clear_kv_cache()release_kv_cache()resume_kv_cache()等控制方法(verl/workers/rollout/replica.py:245-299)。worker 层的 update_weights()再决定同步方式:naive 路径从 actor engine 取 per tensor params 并调用 rollout update_weights();非 naive 路径交给 checkpoint engine send_weights()verl/workers/engine_workers.py:663-740)。

这说明 backend abstraction 的最后一层不是 generate API,而是训推状态机。只有权重、KV cache 和 server 生命周期都接上,rollout 才能成为训练系统的一部分。

小结:backend 抽象是稳定合同,不是消除差异

本文从配置、接口、server manager、replica、adapter 和生命周期五层拆了 rollout backend。可以把它压成一句话:

代码语言:javascript
复制
rollout.name 选择后端
-> registry 找到 adapter / replica
-> manager 启动 server 并分发请求
-> backend generate 返回 TokenOutput
-> lifecycle / weight sync 保证下一轮 rollout 使用正确状态

读完这一篇,读者应该能理解:verl 的 trainer 不直接写 vLLM/SGLang/TRT-LLM 分支,是为了保持 RL 流水线的稳定;但具体后端差异仍然会影响 token budget、多模态能力、logprobs、PD disaggregation、显存状态和权重同步。下一篇会把这条线继续推进到 KV cache、sleep/resume 和显存复用。

本文源码索引

  • verl/trainer/config/rollout/rollout.yaml:1-8:rollout backend 名称和 async mode 配置。
  • verl/trainer/config/rollout/rollout.yaml:130-140:vLLM、SGLang、TRT-LLM 的 backend kwargs。
  • verl/workers/rollout/base.py:29-104BaseRollout接口和 async backend registry。
  • verl/workers/rollout/llm_server.py:222-340LLMServerManager的 replica 创建和 load balancer 初始化。
  • verl/workers/rollout/replica.py:54-68:hybrid、colocated、standalone 三种 rollout mode。
  • verl/workers/rollout/replica.py:245-299:replica 生命周期控制方法。
  • verl/workers/rollout/replica.py:302-402:rollout replica registry 和 SGLang PD 分支。
  • verl/workers/rollout/vllm_rollout/vllm_async_server.py:447-535:vLLM async server 的 generate 适配。
  • verl/workers/rollout/sglang_rollout/async_sglang_server.py:496-606:SGLang async server 的 generate 适配和 PD 分支。
  • verl/workers/rollout/trtllm_rollout/trtllm_async_server.py:313-382:TRT-LLM async server 的 generate 适配。
  • verl/workers/engine_workers.py:663-740:训练权重同步到 rollout 的路径。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 训推工坊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. BaseRollout定义的是最小合同
  • 2. 共同的 generate 合同长什么样
  • 3. 这层抽象在哪里会变薄
  • 4. backend 抽象还包括生命周期
  • 小结:backend 抽象是稳定合同,不是消除差异
  • 本文源码索引
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档