VeRL 框架中的奖励 (reward) 与奖励模型:从 PPO 配置到实现细节
从 PPO 微调大模型的配置入手,我们发现 VeRL 框架将奖励计算抽象为一套独立子系统,包含奖励模型 (RM)、规则函数、并行 Worker 等组件,在配置中通过 reward.* 前缀统一管理。奖励分为两类:函数型 (基于规则逻辑) 和模型型 (基于 RM)。
最近正在入门大模型 RL 微调,阅读 VeRL 框架 的代码。在 VeRL 提供的官方示例 ppo 训练脚本中,我们发现了以下参数:
# 来源于 verl/examples/ppo_trainer/run_deepseek_full_hh_rlhf.sh
reward.num_workers=8 \
reward.reward_model.enable=True \
reward.reward_model.model_path=deepseek-ai/deepseek-llm-7b-chat \
reward.reward_model.rollout.name=vllm \
reward.reward_model.rollout.gpu_memory_utilization=0.8 \
reward.reward_model.rollout.tensor_model_parallel_size=4 \
reward.reward_model.rollout.prompt_length=256 \
reward.reward_model.rollout.response_length=128 \
# 来源于 verl/examples/ppo_trainer/run_deepseek7b_llm_sandbox_fusion.sh
reward.sandbox_fusion.url='https://xxxxxxxxx.apigateway-cn-beijing.volceapi.com/run_code' \
reward.sandbox_fusion.max_concurrent=128 \
reward.reward_manager.name=prime \
然而,这些 reward 参数,在最标准的 verl/examples/ppo_trainer/run_deepseek7b_llm.sh 脚本中,我们都没有看到。笔者感到很好奇,这些 reward 和 reward model 参数表示什么含义?
本博客记录了笔者的学习过程,会围绕两个核心问题展开:
- 在 VeRL 的 PPO 训练中,
reward和reward_model到底是什么? - 这些奖励模型从哪里来、如何被加载和调用、输入输出是什么样、如何融入 PPO 训练流程?
目标:读完之后,能够「一眼看懂」脚本中的那些 reward.* 参数,并对背后整套奖励系统的设计有相对完整的理解。
一、PPO 训练中的奖励子系统:VeRL 是怎么抽象的?
在 RLHF、代码生成 RL、数学推理 RL 等场景下,PPO 的典型流程可以简化为四步:
- Actor(策略模型):根据
prompt生成response(rollout)。 - Reward 侧:对每个
(prompt, response)打分,得到标量 reward。 - Critic(价值网络):估计 value,结合 reward 计算 advantage。
- PPO 更新:利用 advantage 更新 Actor 与 Critic。
在 VeRL 中,第 2 步「对 rollout 打分」被抽象成一个独立的 “奖励计算子系统”,在配置文件中统一以 reward.* 为前缀管理。这个子系统包含:
- 要不要用 奖励模型(Reward Model, RM);
- 要不要用 规则 / 函数型 reward;
- 如何调度多个 Worker 并行打分;
- 是否需要通过 Sandbox Fusion 调用远程代码执行服务;
- 使用哪种 RewardManager 来组织与融合各类奖励源。
换句话说,reward.* 不是一个单独模型,而是一整套:
Actor 生成结果 → 奖励系统如何处理 → 最终交给 PPO 的 reward 标量
的配置入口。
二、两类 Reward:函数型 vs 模型型
VeRL 支持两大类奖励形式:
2.1 函数型(function-based)奖励
即自己写一个打分函数,在 Python 里根据 (prompt, response) 给出分数:
- 数学题(如 GSM8K):
- 解析模型最后给出的答案;
- 判断是否等于标准答案;
- 正确得 1 分,错误得 0 分,或加入格式奖励等。
- 代码题:
- 把模型生成的代码放进执行环境;
- 跑一组测试用例;
- 按通过用例的比例给分。
这类奖励不需要额外模型推理,只依赖任务逻辑,因此在“最标准”的 run_deepseek7b_llm.sh 例子中,我们没有看到 reward.reward_model.* 的配置,就是因为它完全用规则函数搞定奖励。
2.2 模型型(model-based)奖励:Reward Model
当需要模拟人类偏好或复杂评价标准时,规则往往不够,通常会单独训练一个 Reward Model:
- 输入:
(prompt, response); - 输出:一个标量打分(越大越好,或越大越安全)。
VeRL 中配置这一部分的字段是:
reward:
reward_model:
enable: true
model_path: deepseek-ai/deepseek-llm-7b-chat
rollout:
name: vllm
gpu_memory_utilization: 0.8
tensor_model_parallel_size: 4
prompt_length: 256
response_length: 128
这表示:
除了 PPO 在训练 Actor / Critic 时用到的推理外,再单独起一套 专门给 RM 用的推理引擎(这里是 vLLM),把
(prompt, response)拼成文本,送进 RM,拿到 reward。
三、关键配置参数逐项解释
下面以我们在脚本里看到的几组参数为例,逐个拆解。
3.1 reward.num_workers=8
- 含义:整个集群中用于计算奖励的并行 Worker 数量。
- 作用:
- PPO rollout 一次会产生大量
(prompt, response)对; num_workers=8表示可以并行启动 8 个 Worker 进程 / Actor;- 每个 Worker 会接收一部分数据、独立调用 RM 或规则函数打分。
- PPO rollout 一次会产生大量
这对 RLHF、代码执行等计算开销较大的奖励尤为重要。
在只用简单规则函数的 GSM8K 例子中,可能直接使用默认值(比如 1),所以配置中没显式写出来。
3.2 reward.reward_model.enable=True
True:开启 模型型奖励路径;False:完全不用 RM,所有奖励源来自规则函数或其他逻辑。
RLHF 相关脚本基本都会打开这个开关,因为偏好建模的核心就是 RM。
3.3 reward.reward_model.model_path=deepseek-ai/deepseek-llm-7b-chat
- 指向一个已经训练好的 Reward Model 的权重:
- 可以是本地目录:
~/models/my-rm-v1/; - 也可以是 HuggingFace 仓库路径:
org/model-name。
- 可以是本地目录:
- VeRL 在 PPO 流程中只负责加载并推理,并不会训练这个 RM。
也就是说,训练 Reward Model 是一个前置步骤:
- 在别的代码中(如 TRL 的 RewardTrainer)用 human feedback 数据训练好 RM;
- 把 checkpoint 放到某个路径;
- 在 VeRL 配置中把
model_path指向这个路径。
如果直接用 deepseek-ai/deepseek-llm-7b-chat 作为 RM,那就是把一个通用 LLM 视作“黑盒打分器”,具体打分逻辑则在 reward 函数里组织。
3.4 reward.reward_model.rollout.*:RM 推理引擎配置
以这组为例:
reward.reward_model.rollout.name=vllm
reward.reward_model.rollout.gpu_memory_utilization=0.8
reward.reward_model.rollout.tensor_model_parallel_size=4
reward.reward_model.rollout.prompt_length=256
reward.reward_model.rollout.response_length=128
这几个字段的含义可类比于「给 Actor 配 rollout 引擎」:
name=vllm
使用 vLLM 作为 RM 的推理引擎,适合大规模高吞吐推理。gpu_memory_utilization=0.8
每张 GPU 上,vLLM 占用可用显存的 80%。比例越大,可支持的 batch / 序列越长,但也更容易 OOM。tensor_model_parallel_size=4
Tensor Parallel = 4,把一个较大的 RM 拆到 4 张卡上做张量并行。prompt_length=256、response_length=128
给 RM 的输入会先被 tokenizer tokenize,并按这两个上限截断:prompt_length:prompt对应的 token 最大长度;response_length:response对应的 token 最大长度。
整体直觉:RM 有自己独立的一套 vLLM 服务,我们可以单独为它调优显存、并行度与长度上限,而不用和 PPO 主 Actor 的配置绑死。
3.5 Sandbox Fusion 与 reward.reward_manager.name=prime
在代码任务中,常见做法是:让 LLM 写出代码,再实际执行,根据执行行为和结果给奖励。
VeRL 提供了一套与 远程代码执行服务(Sandbox Fusion) 集成的机制,对应参数:
reward.sandbox_fusion.url='https://xxxx.apigateway-cn-beijing.volceapi.com/run_code'
reward.sandbox_fusion.max_concurrent=128
reward.reward_manager.name=prime
-
reward.sandbox_fusion.url- 指向一个 FaaS 服务的 HTTP 接口;
- 模型生成的代码将被发送到此 URL 执行;
- 返回 stdout、错误信息、测试用例结果等,再转换为 reward。
-
reward.sandbox_fusion.max_concurrent- 控制对该接口的最大并发请求数;
- 防止一轮 PPO 中产生大量代码执行请求,直接把后端服务打垮。
-
reward.reward_manager.name=prime-
指定使用 PRIME RewardManager;
-
相比简单的 naive 管理器,prime 更适合:
- 大量代码执行 / 复杂验证;
- 多进程并行、融合多种 reward 源(RM+规则+Sandbox 等)。
-
在纯数学任务中不需要代码执行,自然就不会设置这些字段。
四、Reward Model 在 VeRL 中的“真实工作流”
下面聚焦回答三个问题:
- RM 从哪来?
- 与 RM 的“交互协议”是什么?
- PPO 如何消费 RM 输出的 reward?
4.1 Reward Model 的来源:VeRL 不负责训练,只负责推理
在 VeRL 的 RLHF / 代码 RL 训练中:
- 配置中的
reward.reward_model.model_path必须指向一个已经训练好的 RM; - VeRL 并不包含 RM 训练逻辑,只在 PPO 期间调用 RM 推理;
- 如果我们希望用自定义 RM,需要在外部先完成如下步骤:
- 准备人类偏好数据(pairwise 或打分);
- 用 TRL、Transformers 等工具训练 RM;
- 将权重保存,并在 VeRL 中配置好路径。
因此,VeRL 内部把 RM 抽象成一个:
输入
(prompt, response),输出 reward 标量的黑盒打分服务。
4.2 输入给 Reward Model 的数据格式
在逻辑上:
- 每一个 rollout 样本包含:
question/prompt;model_response/answer。
在实现上,Reward Loop 会把它们打包成一个数据结构(可以理解为一个 DataProto)并传给 Worker。在 Worker 中:
-
将二者按固定模板拼接为一段文本,例如:
Question: {question} Answer: {model_response}或 Chat 模板:
<user> {question} </user> <assistant> {model_response} </assistant> -
使用 RM 对应的 tokenizer 编码;
-
按
prompt_length与response_length截断 token; -
送入 vLLM / HF 模型前向推理。
所以,可以把 RM 的逻辑输入看作是:
一条由
question与response拼接得到的、长度受限的文本。
4.3 Reward Model 的输出格式与 PPO 的使用方式
Reward Loop 的接口约定为:每条数据返回一个字典 (dict),其中包含至少一个 reward 标量字段。
几种典型情况:
-
纯规则奖励(无 RM)
{"score": float_value} -
判别式 Reward Model(DisRM)
模型输出一个或多个 logit,通过简单变换得到 reward:
{"reward_score": rm_score} -
生成式 Reward Model(GenRM)
在自定义 reward 函数里:
-
给 RM 一个“评审 prompt”(如“请在 0–10 分打分并只输出数字”);
-
让 RM 生成一段文本;
-
自己解析文本中的分数;
-
返回:
{"score": parsed_score}
-
上层 PPO 不关心这个 dict 里具体字段名叫什么,它只会在 RewardManager 里把对应字段抽出来,拼成一个 reward_tensor,与 Critic 输出的 value 一起计算:
- advantage;
- PPO loss;
- 进而更新 Actor / Critic 参数。
五、从用户视角看完整训练链路
把上述所有内容串起来,从“写配置”到“PPO 更新”可以用下面这条线来理解:
-
事先准备好 RM(可复用现有模型,也可自己训练)。
-
在 VeRL 的配置中写入:
reward: num_workers: 8 reward_model: enable: true model_path: ~/models/my-rm-v1 rollout: name: vllm gpu_memory_utilization: 0.8 tensor_model_parallel_size: 4 prompt_length: 256 response_length: 128 # 如果用生成式 RM,还可能配置自定义 reward 函数 # custom_reward_function: # path: path.to.my_reward_fn -
启动 PPO 训练时:
- Actor 使用自己的 rollout 配置生成一批
(prompt, response); - 这批数据被送入 Reward Loop,分发给
num_workers个 RewardLoopWorker。
- Actor 使用自己的 rollout 配置生成一批
-
每个 RewardLoopWorker:
- 将
(prompt, response)拼接为文本; - 经 tokenizer 变成 token 序列;
- 按长度上限截断;
- 调用 RM 推理(vLLM / HF 等);
- 解析输出得到标量 reward;
- 返回格式为
{"reward_score": float}或{"score": float}。
- 将
-
RewardManager 将这些 reward 按 batch 整合;
-
PPO 拿到 reward 后,结合 value 估计计算 advantage,完成一次更新。
如果任务还启用了 Sandbox Fusion:
- 中间在 Reward Loop 中还会多一步:
- 从模型生成中解析出“代码调用”;
- 将代码发到
sandbox_fusion.url; - 根据执行结果更新或修正 reward;
prime管理器负责调度多进程执行与奖励融合。
六、总结
从 PPO 的视角看,VeRL 通过 reward.* 配置构建了一套高度模块化的奖励计算子系统:
- 支持 规则型 与 模型型 奖励;
- 支持额外的 代码执行与工具调用;
- 通过
RewardManager管理不同奖励源的并发、融合与调度; - 通过
reward.reward_model.rollout.*为 Reward Model 配置独立的高性能推理后端。
理解这些之后,reward.num_workers、reward.reward_model.enable、model_path、rollout.*、sandbox_fusion.*、reward_manager.name=prime 等参数就不再是“黑盒魔法”,而是整个系统设计中清晰可解释的一部分。
这也是大型语言模型 RL 系统工程的一个重要趋势:用清晰的配置接口,把策略、奖励、工具调用分离出来,既便于研究,也便于工程落地。
更多推荐



所有评论(0)