verl token级打分实现:规则奖励函数怎么写
在大语言模型的强化学习后训练中,奖励建模(Reward Modeling)长期是性能瓶颈和工程复杂度来源——需要额外训练一个参数量接近主模型的奖励模型,还要精心设计偏好数据、处理标注噪声、应对分布偏移。而verl框架所支持的GRPO(Generalized Reinforcement Learning with Policy Optimization)范式,直接跳过了奖励模型与评论家模型,转而用可解释、可调试、可复现的规则奖励函数(Rule-based Reward Function)对每个token进行细粒度打分。这种“token-level scoring”不仅是技术选择,更是工程落地的关键转折点:它让RLHF从黑盒调优变成白盒可控的系统工程。
本文不讲抽象理论,也不堆砌公式,而是聚焦一个最实际的问题:当你拿到verl框架,想为自己的业务场景写一个真正能用的token级规则奖励函数时,到底该怎么做?我们将从零开始,拆解reward_fn的签名约束、输入结构、输出规范、常见陷阱,并给出3个真实可用的代码模板——覆盖基础语法校验、内容安全过滤、多维度质量加权等典型需求。所有示例均可直接粘贴进verl配置中运行,无需魔改框架源码。
1. 理解verl中reward_fn的运行上下文
在verl的PPO/GRPO训练流水线中,reward_fn(batch)不是孤立存在的函数,而是整个数据流中的关键一环。它的输入batch是一个DataProto对象,封装了当前rollout批次的所有张量和元信息;它的输出必须严格满足verl调度器的预期格式,否则后续advantage计算会直接报错。
1.1 reward_fn的调用位置与时机
查看verl/verl/trainer/ppo/ray_trainer.py中的核心训练循环,reward_fn被明确调用在advantage计算前:
# 在 compute_advantage() 之前 reward_tensor = self.reward_fn(batch) # ← 这里! batch.batch['token_level_scores'] = reward_tensor这意味着:
reward_fn在每次训练step中被调用一次,但处理的是整个rollout batch(如前文所述,720条序列)- 它的输出
reward_tensor必须是形状为(B, T)的二维张量,其中B是batch size(720),T是序列最大长度(如8192) - 每个位置
(i, t)的值代表第i条序列中第t个token的即时奖励(reward at time step t)
关键提醒:verl不会对reward做任何归一化或clip。你输出什么,advantage就基于什么计算。因此,reward的数值范围、符号含义、稀疏性都由你完全定义。
