【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (10)--- PRM
撰写本系列文章的目的,在于借助阅读OpenClaw-RL源码的契机,深入梳理强化学习中的关键概念与设计思路。因此,文中会穿插不少基础知识的扩展,且整个系列具有连贯性,部分概念会在不同章节中反复出现,敬请各位读者理解。
OpenClaw-RL 是一个专注于在线强化学习的框架,专门用于智能体工具使用场景。其核心思路是从环境反馈中提取过程奖励信号来训练语言模型,支持以下三种主要模式:
- openclaw-rl:基于二元奖励的强化学习(Binary RL / GRPO)
- openclaw-opd:基于后见之明提示的在线策略蒸馏(On-Policy Distillation, OPD)
- openclaw-combine:联合方法,在同一PPO更新中同时利用RL奖励和OPD教师信号
框架
OpenClaw-RL 采用了 PRM,但请注意,它并非传统意义上的“Process Reward Model”。代码中虽称之为“PRM”,实际上执行的是“LLM Judge”的功能,更类似于一个“Outcome Reward Model (ORM)”。
外部环境→AgentServing→SGLang→用户响应 ↓ RolloutCollection→样本构建 ↓ PRM/JudgeEvaluation→奖励生成 ↓ PolicyTraining←训练样本+奖励 ↓ 新策略模型→AgentServing(更新)
本章我们将对此进行详细拆解。
0x01 基础知识
1.1 PRM如何解决Agentic RL的稀疏梯度问题
1.1.1 稀疏梯度的根本原因
在不使用PRM的情况下,我们观察ORM的效果。假设一个包含5步的回合,仅在最后一步给予奖励+1,其余步骤均为0。
step1 step2 step3 step4 step5(终止) 0 0 0 0 r=+1
在反向传播时,只有第5步能接收到梯度信号,第1-4步的r=0导致优势值≈0,梯度也近乎为0。模型完全无法判断前几步执行得好坏。
1.1.2 PRM的解决思路
PRM本质上是一个函数r(s_t, a_t),用于评估当前步骤的即时质量。其理念是将稀疏信号转化为密集信号。
step1 step2 step3 step4 step5(终止) r1 r2 r3 r4 r5
PRM在每一步都进行评判:“这一步做得对不对?”这样一来,回合内的每一步都能获得梯度信号,从而变为密集奖励。
1.1.3 真正的PRM长什么样(数学题/Agent任务)
数学领域的PRM(如Math-Shepherd)会对推导过程的每一步进行打分:
- “第3步的推导方向正确” → r3=+0.8
- “第5步引入了错误假设” → r5=-0.6
- “第7步的计算正确” → r7=+0.9
Web Agent PRM:
- “点击搜索按钮是正确的操作” → r2=+0.7
- “点击了错误的商品类别” → r4=-0.3
1.1.4 PRM如何实现密集监督(具体机制)
训练数据的构建方式(以数学题为例):
方式1:人工标注
- 人工标注每一步是否正确 → 有监督训练PRM
方式2:蒙特卡洛采样(无监督)
- 在第t步之后,采样K条续写路径
- K条路径中有m条最终解答正确
- P_correct(step_t) = m/K → 这就是第t步的“过程奖励”
理论依据:P_correct(step_t) = V*(s_t) = E[最终成功 | 到达s_t]
1.1.5 PRM不能完全解决的问题
问题1:PRM本身需要训练数据
- 需要收集过程级别的标注,成本远高于ORM
问题2:PRM的分布偏移
- PRM在某个策略的数据上训练,当策略更新后,数据分布发生变化,PRM的打分可能不再准确,需要定期更新
问题3:PRM可能被“欺骗”(奖励黑客2.0)
- 模型学会在每个步骤都“表现得符合PRM的评判标准”,而非真正解决问题
1.1.6 PRM和ORM的数学关系
ORM(稀疏):
R_episode = r_terminal(仅回合末端) advantage_t = E[R_episode|s_t,a_t] - V(s_t) = 难以估计
PRM(密集):
R_step = r_PRM(s_t, a_t)(每步即时分数)
可以选择:
- 仅用即时分:advantage_t = r_PRM_t
- 折扣累积:advantage_t = Σγ^k r_PRM_{t+k}(GAE/TD)
- 过程+结果混合:advantage_t = r_PRM_t + γ*r_terminal(仅最后一步)
1.2 PRM与环境奖励的区别
简而言之,PRM是人工构造的评估机制,而环境奖励是自然产生的反馈信号。
PRM(过程奖励模型)定义
- 评估方式:基于助手响应和下一状态进行质量判断
- 信号来源:由专门的LLM模型(通常是同一基础模型)执行评估
- 评分标准:预定义的规则(+1/-1/0)判断任务是否成功完成
- 实现机制:通过构建特定提示模板,让LLM扮演评估者角色
环境奖励定义
- 评估方式:直接来自环境的状态变化或用户行为
- 信号来源:真实的系统响应、用户后续行为、任务完成状态
- 评分标准:环境本身的成功/失败指标(如工具返回码、任务完成度)
- 实现机制:直接观察环境状态变化,无需额外的评估模型
在MDP形式化中,Environment=(S, A, T, R, γ),其中R是奖励函数,通常被视为环境的一部分。因此,从纯理论角度,奖励模型也可以算作环境的组成部分。
但在现代LLM强化学习的工程实践中,环境(信息来自外部)和奖励模型(独立计算的评估)在系统架构上被明确分离。原因在于:
- 真实奖励(用户满意度)无法直接观测,奖励模型是对真实奖励的近似
- 环境是不可控的(真实用户),奖励模型是可设计的
- 两者的计算位置不同(GPU 4-5 vs GPU 6-7)
- 两者的作用时机不同(状态转移时 vs 回复完成后异步)
结论:在OpenClaw-RL的架构中,PRM/Judge明确属于奖励评判。它使用了环境(用户)产生的next_state作为评估依据,但评分计算本身是一个独立的奖励评判过程。
1.3 小结
OpenClaw的代码中虽然叫“PRM”,但实际上是“LLM Judge”或“Outcome Reward Model (ORM)”。
| 属性 | 传统PRM | OpenClaw “PRM” |
|---|---|---|
| 类型 | 训练好的奖励模型 | 零样本LLM评判器 |
| 粒度 | 步骤级(每步) | 响应级(整体) |
| 输出 | 连续分数 [0,1] | 离散 {-1, 0, +1} |
| 训练 | 需要标注+训练 | 不需要训练 |
| 评分依据 | 学到的特征 | 提示词指导 |
0x02 OpenClaw-RL 的PRM
OpenClawRL不直接使用传统意义上的环境奖励,而是主要采用PRM,将环境反馈作为PRM评估的输入。PRM/Judge属于奖励评判,而非环境本身。
这种设计体现了OpenClaw-RL的解耦思想:
- 环境无关性:训练算法不直接依赖特定环境的奖励机制
- 评估标准化:所有场景都通过统一的PRM接口生成奖励
- 灵活性:可以轻松调整评估标准,而不影响核心训练逻辑
通过PRM机制,OpenClaw-RL能够:
- 有效利用环境反馈:将真实的用户交互转化为高质量训练信号
- 保持训练稳定性:避免稀疏或噪声环境奖励导致的训练不稳定
- 支持复杂任务:处理需要语义理解的复杂交互场景
2.1 命名 vs 实际
2.1.1 位置
在OpenClaw-RL的四个阶段中,PRM/Judge属于奖励评判,而不是环境。
GPU4-5: PolicyServing (SGLang) ← 环境 → 为真实用户提供对话服务 环境 = 用户提供的状态转移 → 接收用户消息,生成模型回复 → 捕获next_state(下一条用户消息) GPU6-7: RewardJudging (SGLang PRM) ← 奖励评判 → 接收完成的对话轮次,独立计算奖励,不参与状态转移 → 调用LLM评判器评分×3(多数投票)→ 输出+1/0/-1,设置loss_mask GPU0-3: PolicyTraining (Megatron Actor) → 接收带奖励的样本,更新权重
2.1.2 vs 传统PRM
传统PRM (过程奖励模型):
- 收集人类偏好数据(chosen/rejected pairs)
- 训练一个奖励模型: R = f_Φ(prompt, response)
- 对推理过程的每一步打分(步骤级奖励)
- 需要标注数据训练
- 固定Φ,用R指导策略训练
- 特点:确定性、训练成本高、可能存在奖励黑客行为
OpenClaw的“PRM”:
- 本质是LLM评判器,用同族模型(Qwen3)做零样本评分
- 不需要训练,用自然语言提示词描述评分标准
- 对整个回答打分(响应级奖励)
- 输出boxed{1}/boxed{0}/boxed{-1}
- 多数投票 (m=3) 降噪
- 特点:随机性、零训练成本、通过提示词灵活调整标准、多数投票部分缓解随机性
2.2 设计思路
OpenClaw-RL采用“环境反馈 → PRM评估 → 奖励信号”的间接模式。虽然不直接使用环境奖励,但项目巧妙地利用环境反馈作为PRM评估的依据:
- 环境反馈作为输入:下一状态(用户/工具响应)作为PRM评估的输入
- PRM作为中介:将环境反馈转化为标准化的奖励信号
- 统一奖励接口:所有场景都通过相同的PRM机制生成奖励
response = sglang_inference(prompt) # 主策略推理 next_state = get_next_user_input() # 获取环境反馈 prm_score = prm_evaluate(response, next_state) # PRM评估 reward = prm_score # 间接环境奖励
接下来我们逐一分析,先来看看为何不使用环境反馈。
2.3 环境反馈
2.3.1 统一的环境概念
以下两种情况均被视为助手所处环境的反馈:
- 用户(User):提供语义层面的反馈(同意、否定、纠正等)
- 工具(Tool):提供执行层面的反馈(成功、失败、错误等)
用户(User)作为环境
- 用户反馈:用户对助手响应的直接回应,如“谢谢”、“不对,我要的是...”、“再试一次”等
- 环境信号:用户的反应直接反映了助手行为的好坏
- 正面信号:用户继续对话、表示感谢、任务完成确认,或工具成功返回
- 负面信号:用户要求重做、修改、纠正前一响应,或工具返回错误
- 中性信号:无关的后续问题或模糊反馈
工具(Tool)作为环境
- 工具返回值:当助手调用工具时,工具的执行结果成为“下一个状态”
- 关键说明:“This content was NOT a vailable before the assistant's action - it exists BECAUSE the assistant called the tool”
- 成功判断:“A successful, non-error tool output means the assistant's action worked correctly and should be scored positively”
- 环境信号:正面信号(工具成功执行)、负面信号(工具执行失败)、中性信号(工具执行成功但结果不明确)
2.3.2 关键区分
关键区分:环境提供状态,奖励评判提供评分。
OpenClaw的环境(真实用户):
- State(t) = 对话历史(到第t轮为止的消息)
- Action(t) = 模型的回复(策略的输出)
- State(t+1) = 用户的下一条消息(next_state)
- 状态转移 T(s, a) = s':模型发出回复 → 用户决定是否继续 → 用户消息 = 新状态
- 这是真正的环境:外部世界(用户)对动作的反应,PRM/Judge完全不参与这个状态转移
OpenClaw的奖励评判 (LLM评判器):
- 接收:conversation_history + model_response(已发送给用户)
- 输出:score ∈ {+1, 0, -1}(异步评估,不阻塞用户)
- 评估的是:“这个回复质量如何?”
- 不参与状态转移,不影响用户看到什么,是对已发生事件的独立评分,而非环境反馈
2.4 为什么选择PRM而非直接环境奖励?
通用性优势
- 跨环境适用:同一套PRM机制适用于不同类型的交互场景
- 标准化接口:无论环境如何变化,奖励信号格式保持一致
- 灵活调整:可以通过修改PRM提示模板调整评估标准
语义理解能力
- 上下文感知:PRM能够理解复杂的语义关系
- 意图判断:能够判断用户的真实意图是否被满足
- 模糊处理:能够处理不明确的环境反馈
实现复杂度平衡
- 避免环境耦合:不需要为每个环境定制奖励函数
- 简化架构:统一的评估机制降低系统复杂度
- 易于调试:PRM评估过程可观察、可解释
这种“环境反馈→PRM评估→奖励信号”的间接模式,是OpenClaw-RL在通用性和实用性之间找到的最佳平衡点。
2.5 PRM 的使用
过程奖励模型(PRM)会根据这些“下一个状态”来判断助手的响应是否成功实现了用户意图。
2.5.1 下一个状态 next_state
在OpenClaw-RL框架中,“下一个状态”是指来自用户(user)或工具(tool)的反馈,它们共同构成了助手所处的“环境”。在_build_prm_judge_prompt()函数中,明确区分了两种类型的“下一个状态”:
- “- role='user': A reply from the user.\n”
- “- role='tool': The return value of a tool the assistant invoked.”
过程奖励模型(PRM)会根据这些“下一个状态”来判断助手的响应是否成功实现了用户意图:
- 积极信号(评分+1):用户继续前进、表达感谢,任务按预期完成,或工具成功返回
- 消极信号(评分-1):用户要求重做、修改,用户重新表述相同请求,或工具返回错误
- 中性信号(评分0):状态模糊或信息不足判断成功与否,用户给出不相关的后续
msgs = _build_prm_judge_prompt(response_text, ns_text, ns_role) # next_state是来自环境的真实信号
但是,这里有一个容易混淆的地方:人们会误认为next_state用作奖励的来源。
OpenClaw的PRM评分中,next_state起了关键作用:这造成了混淆,但本质上:
- next_state是环境产生的(用户发送的真实下一条消息)
- 评判器使用它作为证据来判断这个回复是否导致了良好的后续对话
- 但评分计算本身是奖励评判(由GPU6-7的评判器LLM完成)
类比:法庭判决用了犯罪现场的证据(来自“现实世界”),但做出判决的是法官(奖励评判),而不是现实世界本身。
2.5.2 分支说明
分支说明(PRM扮演的角色不同)
- Binary RL分支
- PRM调用:评估提示词 → ±1/0
- 作用:直接作为奖励(标量)
- 粒度:序列级
- OPD分支
- PRM调用:hint-judge提示词 → 提示文本
- 作用:构建增强提示词给教师模型
- 粒度:被教师前向传播转换成token级对数概率后才成为训练信号
两条分支都通过self._prm_url(同一个SGLang评判器服务;部署在GPU6-7,与actor/rollout解耦)调用PRM模型。该模型本质是与策略同源的零样本LLM评判器,不是单独训练的奖励模型。区别仅在调用方式。
具体参见如下:
10-分支说明
同一个SGLang服务(GPU 6-7),不同提示词,不同信号路径。
2.6 OpenClaw-RL 的 PRM 本质
ORM:名义PRM,实为ORM
如1.4小结所述,OpenClaw的“PRM”名义上叫过程奖励模型,实际语义是“每轮的结果奖励模型”——它对整条响应的整体质量打分(+1/0/-1),并不对响应内部哪个句子或词有贡献进行评分。
OPD:教师对数概率是隐式PRM
OPD的教师对数概率实际上是一种“隐式PRM”:OPD的每个token的优势值 = teacher_lp[t] - rollout_lp[t],相当于“在提示的指导下,教师对第t个token的评分”。这在token粒度上实现了——正确推导方向的token → 教师高概率 → 优势值大;错误token → 教师低概率 → 优势值小/负。
换句话说,教师对数概率是一种软版本的过程奖励,在token级别而非步骤级别。因此OPD绕过了“如何训练PRM”的难题——教师的对数概率本身就是一个随时可用的过程级信号。
关键差异本质
| 对比项 | Binary RL 用 PRM | OPD 用 PRM |
|---|---|---|
| 提示词 | _build_prm_judge_prompt | _build_hint_judge_messages(提示生成提示词) |
| PRM输出直接是训练信号? | ✅ 是(±1即奖励) | ❌ 否(提示是中间产物,要再过教师前向传播) |
| 输出格式 | boxed{±1/0} | boxed{1} + [HINT_START]...[HINT_END] |
| 信号进入训练的方式 | ±1分数 → 奖励 → GRPO优势值 | 提示文本 → 注入用户消息 → 教师前向传播 → 对数概率差异 |
| 信号的信息量 | 1比特(±1)每条响应 | K比特每个token(教师分布) |
| PRM失效会怎样? | 奖励全0 → 无梯度 | 提示全废 → 无OPD样本,但教师仍可工作 |
| 同一句话能否同时被两路用? | ✅ 在Combine里 — 一次轮次并发跑两种提示词,分别决定是否发RL样本/OPD样本 | 同左 |
| 对PRM能力要求 | 判别能力(好坏二分类) | 生成能力(要写出更好的回答) |
| 失败模式 | 误判 → 错误奖励方向 | 提示偏离策略 → 教师-学生差距噪声大 |
为什么Combine会有效
PRM在两个分支扮演互补角色:
- 作为评分员时(RL):覆盖广,但只能告诉模型“这次答得对不对”
- 作为教练时(OPD):覆盖窄(要求PRM能生成可用提示),但能告诉模型“这个token应该怎么改”
Combine把同一PRM的“判别力”和“生成力”同时榨干:用判别得到密集的标量监督,用生成得到稀疏的token级方向监督。两条路径用到的PRM服务实例相同,但提示词、解析、聚合、入损失的方式完全不同。
2.7 PRM 模型
项目中的PRM不是传统训练好的奖励模型,而是用LLM(同款Qwen3)做零样本评判,通过提示词指导它输出boxed{1} / boxed{0} / boxed{-1}来评分。没有单独训练过奖励模型。
代码里self._prm_url是同一个SGLang评判器服务(GPU 6-7)。它同时承担两类调用:
| 调用类型 | 目的 | 服务于哪条路径 |
|---|---|---|
| 提示评判 (_query_judge_once) | 解析boxed{1}+[HINT_START]...[HINT_END]提取更优回答提示 | OPD路径(决定是否发OPD样本+注入提示) |
| PRM评估 (_prm_evaluate → _majority_vote) | 给当前回答打分+1/0/-1 | RL路径(生成奖励) |
两者共享同一个模型权重、同一个路由端口,只是提示词模板不同(_build_hint_judge_messages vs _build_prm_judge_prompt),并发执行m次投票。
2.8 Policy Server vs PRM Server
在OpenClaw-RL中,OPD(在线策略蒸馏)使用了两个关键的服务器组件:
策略服务器(Policy Server)
实现文件:openclaw-opd/openclaw_opd_api_server.py
功能:
- 推理服务器:作为FastAPI应用运行,监听端口30000(默认)
- 请求转发:接收来自训练系统的聊天请求,转发给底层的SGLang推理引擎
- 数据收集:在主要轮次类型时,收集模型的输出、对数概率等信息用于后续训练
- 会话管理:跟踪每个会话的状态和轮次数量,为OPD提供上下文信息
启动方式:
- 通过环境变量配置:HOST=“0.0.0.0”,PORT=“30000”
- 在训练脚本中作为自定义生成函数被调用
- 实际的推理由SGLang引擎处理,策略服务器主要负责数据记录和OPD逻辑
PRM服务器(过程奖励模型服务器)
实现方式:基于SGLangRouter的独立服务
功能:
- 提示提取:使用PRM模型分析(response, next_state)对,判断是否包含有用的后见之明信息
- 奖励评分:对智能体的响应进行过程奖励评估(评分: +1, -1, 0)
- 教师信号生成:当启用Top-K蒸馏时,PRM服务器还负责查询教师模型的top-K logits
- 多投票机制:默认进行3次(PRM_M=3)独立评估,取多数投票结果
技术架构:
- 独立进程:通过_start_router函数启动独立的SGLangRouter进程
- 资源配置:在运行脚本中分配专门的GPU资源(PRM_GPUS=2)
- 模型路径:可以使用与主模型相同的模型(PRM_MODEL_PATH),也可以指定不同的PRM专用模型
- 通信接口:通过HTTP POST请求到/generate端点进行交互
两者的关系数据流:
- 策略服务器收集主模型的输出和用户反馈,将(response, next_state)对发送给PRM服务器进行评估
- PRM服务器返回提示和奖励分数,策略服务器将这些信息打包成训练样本提交给SLIME训练系统
协同工作:
- 策略服务器负责在线数据收集和会话管理
- PRM服务器负责离线评估和教师信号生成
- 两者通过HTTP API进行通信,实现了松耦合的架构设计
扩展性:
- PRM服务器可以部署多个实例进行并行评估
- 策略服务器可以处理多个并发会话
- 支持Top-K蒸馏时,PRM服务器还需要提供完整的概率分布信息
这种架构设计使得OPD能够有效地利用延迟反馈(后见之明提示)来改进在线策略学习,同时保持系统的可扩展性和模块化。
0x03 PRM 流程
3.1 总体流程
10-总体流程
3.2 BinaryRL分支中的PRM
- 角色:评分员(评估者/批评者)
- 文件位置:openclaw-rl/openclaw_api_server.py
- 特点:
- 评分范围:+1(成功),-1(失败),0(中性)
- 评估逻辑:基于下一状态判断助手响应是否成功满足用户意图
- 触发时机:用户提供下一状态(反馈)时自动触发
- 使用场景:通用对话场景的BinaryRL训练
- 核心提示词:
You are a process reward model (PRM) evaluating an AI assistant. Your task: decide whether the assistant's output successfully fulfilled the user's intent at that step, using the next state as evidence. ## Scoring rules: - boxed{1} (good): ## next state shows task progressed as expected - boxed{-1} (bad): ## next state shows assistant output was wrong/incomplete - boxed{0} (neutral): ## insufficient information, cannot judge Think step-by-step, then give your final score inside boxed{}.
具体参见下表。
| 维度 | 内容 |
|---|---|
| 调用入口 | _build_prm_eval_prompt → _prm_eval_majority_vote |
| 输入 | (response, next_state) |
| 提示词类型 | “你是PRM,请评估AI回答的好坏” |
| 输出格式 | boxed{1} / boxed{0} / boxed{-1} |
| 聚合 | m次独立投票多数决;平票→0 |
| 用途 | 直接进入训练损失—作为GRPO的标量奖励 |
| 信号粒度 | 序列级标量(整条响应一个分数) |
| 信号性质 | 评估性(evaluative):“好/坏” |
| 数据密度 | 所有±1分样本都进训练;0分丢弃(除“at-least-one”保底) |
3.3 OPD分支中的PRM
角色:教练/提示提取器
文件位置:openclaw-opd/openclaw_opd_api_server.py
特点:双重功能,同时实现提示提取(+1/-1 Something wrong happened, please give me more information or retry)
PRM使用精心设计的提示模板确保评估一致性:
- 系统消息:明确评估规则和评分标准
- 用户消息:包含具体的助手响应和下一状态
- 输出格式:强制使用boxed{}包裹最终分数
- 角色区分:明确区分user和tool类型的下一状态
def _build_hint_judge_messages(response_text: str, next_state_text: str, next_state_role: str = “user”) -> list[dict]: system = ( “You are a process reward model used for hindsight hint extraction.\n” “You are given:\n” “1) The assistant response at turn t.\n” “2) The next state at turn t+1, along with its **role**.\n\n” “## Understanding the next state's role\n” “- role='user': A reply from the user (follow-up, correction, new request, etc.).\n” “- role='tool': The return value of a tool the assistant invoked.” “This content was NOT a vailable before the assistant's action—” “it exists BECAUSE the assistant called the tool.” “A successful, non-error tool output generally means the assistant's” “action was appropriate; do NOT treat it as information the assistant” “should ha ve already known.\n\n” “Your goal is to decide whether the next state reveals useful hindsight information\n” “that could ha ve helped improve the assistant response at turn t.\n\n” “Output format rules (strict):\n” “- You MUST include exactly one final decision token: boxed{1} or boxed{-1}.\n” “- If and only if decision is boxed{1}, provide a concise, information-dense hint in 1-3 sentences,\n” “wrapped between [HINT_START] and [HINT_END].\n” “- If decision is boxed{-1}, do not provide a hint block.\n” “- Hint must be concrete and actionable for improving the previous response.” ) user = ( f“## Assistant response (turn t)\n{response_text}\n” f“## Next state (turn t+1) [role: {next_state_role}]\n{next_state_text}\n\n” “Now output your decision and (if positive) the hint in the required format.” ) return [{“role”: “system”, “content”: system}, {“role”: “user”, “content”: user}]
具体参见下表。
| 维度 | 内容 |
|---|---|
| 调用入口 | _build_hint_judge_messages → _query_judge_once |
| 输入 | (response, next_state) |
| 提示词类型 | “若回答有问题,请给出更好的版本 [HINT_START]...[HINT_END]” |
| 输出格式 | boxed{1} + 文本提示 |
| 聚合 | m次投票,选出最长的有效正样本提示(>10字符) |
| 用途 | 不直接进入损失;提示文本被注入到用户消息,再喂给教师做前向传播,真正的训练信号是teacher_log_probs - rollout_log_probs |
| 信号粒度 | token级向量(响应中每个token一个优势值) |
| 信号性质 | 方向性(directional):“应该这样回答” |
| 数据密度 | 只有提示通过的轮次才进训练(更稀疏,但更精细) |
关键点:OPD路径本身的“教师信号”不来自PRM±1分。
OPD真正用于训练的方向性信号是教师模型对提示增强后,提示词的token级对数概率,再减去学生(rollout_log_probs)。PRM评分只起两个作用:
- 在OPD中:决定是否提取提示(提示评判角色)
- 在Combine中:额外提供RL标量奖励与OPD的token级方向梯度互补
所以:PRM模型权重在OPD路径里被调用(做提示抽取),但PRM的±1分数本身不进入OPD的损失函数——除非你跑的是Combine。
3.4 评分流程
接下来看看评分流程,和其中一些技术细节。
PRM完整评分流程如下。
10-PRM完整评分流程
多数投票
多数投票次数 = 3,等于对同一条响应独立发起m=3次异步评判调用,取众数(最常见分数)。如果三票各不相同(平局),返回0.0(中性/跳过)。
这3次评判调用的特点为:
- 不是自适应分配,但在单个轮次内做了“多次采样”
- 减少评判器噪声,相当于对奖励信号做了低方差估计
不足之处为:
- 不管轮次的学习价值高低,都用相同的评判预算
- 如果2/3评判意见一致,第3次调用是浪费
- 如果3/3完全不一致(高不确定性),应该增加m
多数投票算法细节:
def _majority_vote(scores: list[int|None]) -> float: valid = [s for s in scores if s is not None] # 过滤失败的查询 if not valid: return 0.0 # 全部失败→中性 counter = Counter(valid) top = counter.most_common(1)[0] # 关键:若有多个选项并列第一,返回0(保守策略) if list(counter.values()).count(top[1]) > 1: return 0.0 return float(top[0])
示例表格
| 投票结果 | 结果 | 原因 |
|---|---|---|
| [1, 1, 1] | +1 | 完全一致 |
| [1, 1, -1] | +1 | 多数票 |
| [1, -1, 0] | 0 | 三方平票 |
| [1, -1, None] | 0 | 2有效,平票 |
| [None, None, 1] | +1 | 唯一有效票 |
至少一个保障
- 至少一个是指当一个会话的所有轮次评分都是中性时,强制将第一条被评估的轮次的loss_mask设为[1]。
- 解决的问题:防止奖励全零导致的训练信号完全消失(信号缺失/奖励真空问题)。
# _submit_turn_sample()中的核心逻辑: exclude = not has_next_state or score == 0.0 # 正常情况:score=0 → exclude=True → loss_mask=[0,0,...,0] # 但是!特殊保障: if exclude and has_next_state and self._session_effective.get(session_id, 0) == 0: exclude = False # ← 强制参与训练! # “至少一个保障”
解决的问题场景如下:
用户发了5条消息,但每次都是中性反馈(score=0),导致:
- 所有轮次 loss_mask=[0] → 这个会话对训练没有任何贡献
- 分母增大但分子不变 → rollout_batch_size难以填满 → 训练停滞
保障机制如下:
第一个被PRM评过(has_next_state=True),但score=0的轮次 → 强制loss_mask=[1],参与训练 → 至少每个会话贡献一个样本。
异步提交
样本提交的异步状态机如下:
10-异步状态机
整体评分行为总结
10-整体评分行为
0x04 显式PRM vs OPD teacher log-prob
接下来看看显式PRM和OPD教师对数概率之间的比较。
4.1 两者的核心问题
显式PRM:“这一步(动作)对最终目标有多大贡献?”
r(s_t, a_t) = P(最终成功 | 经过了这一步)
OPD教师对数概率:“在看过提示后,教师对这个token的认可程度?”
adv(t) = logπ_T(a_t | a_1...a_{t-1}, hint) - logπ_old(a_t | ...)
这是两个不同的问题,只是恰好都能产生密集梯度信号。
4.2 差异一:评估的对象
显式PRM(理想情况):
- 输入:当前步骤的动作a_t和状态s_t
- 输出:这一步是否正确(与目标的对齐)
- 独立于:后续步骤是什么(步骤级马尔可夫性质)
OPD教师对数概率:
- 输入:a_1...a_{t-1}(所有之前token)+ 提示
- 输出:教师认为第t个token是a_t的概率
- 依赖于:所有之前的token(自回归,非马尔可夫)
因此:
- PRM评估的是“步骤”的价值
- OPD评估的是“在已有语境下,这个token和教师的偏好差异”
4.3 差异二:反事实能力
场景:response在step5犯了错误,即“the square root of 1764 is 43” ← 错误
显式PRM:
- step 5:r=-0.9(这一步是错的,后续几乎无法成功)
- step 6:“because...” → r ≈ 0(step5错了,step6无论对错都不重要了)
- PRM能识别出“错误发生在step 5”
OPD教师对数概率:
- 教师看到了提示,知道应该是42,但teacher_lp[step6]是P_teacher(“because” | “...is 43”, hint)
- = “给定学生说了‘43’,教师认为下一个词是‘because’的概率”
- = 级联污染!教师在step6的评分是条件于错误的step5的
因此:
- OPD无法做反事实推理
- PRM(理论上)可以在错误发生的那一步精确定位
4.4 差异三:信号的绝对性 VS 相对性
显式PRM:
r(step_t) = 0.8 → “这一步有80%的可能性是在正确轨道上” = 绝对质量分数,可以跨样本比较
OPD优势值:
adv(t) = teacher_lp - rollout_lp = “相对于当前策略,教师的偏好差” = 若教师和学生在此token上意见一致 → adv ≈ 0 = 即使这个token“很重要”,只要两者一致,梯度就是0
因此:
- PRM测量的是“当前步骤有多正确”
- OPD测量的是“需要改变多少”
4.5 差异四:提示带来的“上帝视角”
显式PRM(标准设计):
- 在step t只能看到s_0...s_t的信息
- 不知道“正确答案”是什么(否则就是作弊)
- 模拟真实智能体的局部视角
OPD教师(后见之明):
- 教师看过了提示(正确方向的提示)
- 提示是对整条响应评估后给出的 = 后见之明
- 优势:信号更精准(教师知道哪里错了)
- 劣势:训练数据来自“知道答案”的教师,推断时没有提示
0x05 显式PRM+OPD的理论结合方案
我们从理论角度看看,显式PRM+OPD的结合使用是否合理。
5.1 两者的互补性分析
优劣分析
- OPD的强项 = 精确到token的改进方向
- OPD的弱点 = 级联污染(错误步骤之后的token信号失真)
- PRM的强项 = 识别错误发生的步骤(反事实定位)
- PRM的弱点 = 步骤粒度粗,无法指导每个token如何改
| 维度 | 显式PRM | OPD教师对数概率 |
|---|---|---|
| 信号密度 | 密集 (每步) | 密集 (每个token, 更细) |
| 反事实推理 | √ 可以定位错误步骤 | × 级联污染 |
| 绝对质量 | √ 绝对分数 | × 只有相对差 |
| 训练成本 | 高(需要标注数据) | 零(教师直接推理) |
| 分布偏移 | 有(PRM本身需更新) | 无(每次实时计算) |
| 粒度 | 步骤级(语义) | Token级(子词) |
| 奖励黑客风险 | 中(模型游戏PRM) | 低(教师足够大且变化慢) |
优势互补
显式PRM回答“哪一步走错了”(诊断),OPD教师对数概率回答“每个词要往哪里改”(处方)。前者具备反事实定位能力,后者具备零训练成本的优势。两者测量的是不同问题,只是都能产生密集梯度这一性质让它们看起来相似。
因此:
- PRM可以告诉OPD:“从这里开始的token信号是被污染的,应该忽略”
- 在PRM确认“正确步骤”范围内,OPD提供精细梯度
5.2 方案一:PRM作为OPD的有效域门控
def combined_advantage(response_tokens, step_boundaries, prm_scores, teacher_lp, rollout_lp): adv = torch.zeros(len(response_tokens)) for step_idx, (start, end) in enumerate(step_boundaries): # PRM评估这一步是否正确 prm_score = prm_scores[step_idx] # e.g., +1/-1 if prm_score > 0: # PRM: 这步是对的 → 用OPD精细化内部token adv[start:end] = teacher_lp[start:end] - rollout_lp[start:end] else: # PRM: 这步是错的 → 均匀惩罚(不用被污染的教师LP) adv[start:end] = -1.0 # ← 关键:从这步开始后面的OPD信号都丢弃(级联阻断) break # 后续步骤优势值=0(不学习级联后的token) return adv
这解决了OPD的核心问题:PRM发现错误步骤后,后续步骤的OPD信号不再被计算,级联污染被切断。
5.3 方案二:层级式优势值(乘法结合)
advantage(t) = PRM_step(t) × (teacher_lp(t) - rollout_lp(t)) ↑ ↑ 步骤级“值不值得学习” Token级“往哪个方向学”
语义:PRM决定“这一步的梯度权重”,OPD决定“梯度的方向”。
正确步骤内的好token:PRM=+1 × OPD_adv=+0.5 = +0.5 ← 适度强化 正确步骤内的冗余token:PRM=+1 × OPD_adv≈0 ≈ 0 ← 不动 错误步骤内的token:PRM=-1 × OPD_adv=任意 ← 全部反转为负
5.4 方案三:和Combine的统一视角
当前Combine实际上已经是一种弱版本:
Combine: advantage = w_rl * GRPO_reward + w_opd * OPD ↑ 整条响应一个标量(相当于序列级PRM = GRPO) PRM+OPD: advantage = w_prm * PRM_step(t) + w_opd * OPD(t) ↑ 每一步一个分数(更细粒度的PRM)
PRM+OPD是Combine的自然升级:把序列级奖励换成步骤级奖励。
5.5 理论最优组合
完整组合的优势值计算流程:
Response: [step_1] [step_2] [step_3] ... [step_N] ↓ PRM识别出step_3开始出错
优势值分配:
- step_1 tokens: w_prm * (+1) × OPD_1 → 精细OPD信号
- step_2 tokens: w_prm * (+1) × OPD_2 → 精细OPD信号
- step_3 tokens: w_prm * (-1) × uniform → 均匀惩罚(OPD级联被阻断)
- step_4+ tokens: 0(完全忽略,避免级联学习错误)
5.6 实践挑战(为什么还没人做)
挑战1:PRM的训练数据
- 需要步骤级标注或蒙特卡洛rollout
- 对话领域没有现成的步骤级PRM数据
挑战2:步骤边界的定义
- 数学题:步骤边界清晰(换行/逻辑节点)
- 自由对话:边界模糊(哪里算“一步”?)
挑战3:PRM本身的分布偏移
- PRM在policy_t的数据上训练
- 策略更新后,PRM的评分可能不再准确
- 需要和策略同步更新(成本高)
挑战4:两个模型的推理成本
- PRM(一次前向传播)+ 教师(一次前向传播)= 原本OPD成本的2倍
5.7 一句话总结
显式PRM+OPD的结合是理论上最优的密集信号方案:PRM负责步骤级诊断和级联阻断,OPD负责步骤内的token级精细处方。这正是Combine方法的自然延伸方向,但工程成本和PRM训练数据是主要障碍。
TransFormer-封面
0xFF 参考
Your Efficient RL Framework Secretly Brings You Off-Policy RL Training
