当评判器的“审美”与你的场景对齐,AI才真正懂得什么是“好”
引言:为什么需要专属PRM?
在上一篇中,我们用同一套RL代码同时跑通了终端、GUI、SWE、工具调用四大场景。但一个根本问题浮出水面:PRM(过程奖励模型)的评判标准,应该对所有场景一视同仁吗?
显然不行:
- 终端场景:退出码为0就是成功,报错就是失败——评判标准客观且明确
- GUI场景:界面状态变化是否符合预期?可能需要视觉理解
- SWE场景:代码修改后测试是否通过?需要理解代码语义
- 个人对话:用户满意与否?需要理解情感和意图
OpenClaw-RL的论文明确指出,PRM的定制化是提升强化学习效果的关键 。一个在数学推理上训练出来的PRM,无法理解GUI界面的“美观”与否;一个在终端命令上训练出来的PRM,也判断不了对话的“自然度”。
本文将带你完成:
- ✅ 理解PRM的三重角色:学生、教师、裁判的职责分工
- ✅ PRM评判器架构:从单次评判到多数投票
- ✅ 各场景的定制策略:终端用规则、GUI用VLM、SWE用代码理解
- ✅ 数据集构建:如何为特定场景采集训练数据
- ✅ 训练与部署:从微调基座模型到集成到RL流水线
一、PRM的三重角色:学生、教师与裁判
在OpenClaw-RL中,PRM实际上扮演了三个截然不同的角色 :
| 角色 | 英文 | 职责 | 对应方法 |
|---|---|---|---|
| 学生 | Student | 执行任务的策略模型,需要被优化 | 主模型(如Qwen3-4B) |
| 教师 | Teacher | 提供优化方向,告诉学生“应该怎么做” | OPD中的增强上下文教师 |
| 裁判 | Judge/PRM | 给出评分,告诉学生“做得好不好” | Binary RL中的PRM评判器 |
本文聚焦裁判角色——即专门负责给交互打分的PRM评判器。
1.1 裁判的职责
裁判PRM的输入输出非常简单 :
输入:动作 a_t(智能体的回复)+ 下一个状态 s_{t+1}(用户反馈/工具输出)
输出:评分 ∈ {+1(好), -1(差), 0(中性)}
但这个简单的函数背后,需要深刻理解特定场景的“好坏”标准。
1.2 裁判与教师的分工
| 维度 | 裁判(PRM Judge) | 教师(Teacher) |
|---|---|---|
| 输入 | a_t + s_{t+1} | s_t + hint(从s_{t+1}提取) |
| 输出 | 标量{-1,0,1} | Token级优势向量 |
| 覆盖 | 所有交互 | 仅含明确指导的交互 |
| 对应方法 | Binary RL | OPD |
| 本篇目标 | ✅ 定制化训练 | ❌ 下一篇 |
二、PRM评判器的核心架构
2.1 单次评判与多数投票
根据OpenClaw-RL论文,PRM的评判采用多数投票机制来提升鲁棒性 :
# prm_judge.py
class PRMJudge:
"""过程奖励模型评判器"""
def __init__(self, model, num_votes=3):
self.model = model # 可以是LLM API或本地模型
self.num_votes = num_votes
def _single_judge(self, action: str, next_state: str) -> int:
"""单次评判,返回-1/0/1"""
prompt = self._build_prompt(action, next_state)
response = self.model.generate(prompt)
return self._parse_score(response)
def judge(self, action: str, next_state: str) -> int:
"""多数投票最终评分"""
votes = [self._single_judge(action, next_state)
for _ in range(self.num_votes)]
# 多数投票
final_score = max(set(votes), key=votes.count)
return final_score
2.2 评判Prompt模板设计
评判Prompt的质量直接影响PRM性能。以下是论文中使用的通用模板 :
def _build_prompt(self, action, next_state):
return f"""你是一个AI交互质量评判器。请根据用户的反馈,判断AI的上一次回复质量。
AI的回复:{action}
用户的反馈:{next_state}
请从以下选项中选择一个:
+1:用户满意/任务成功(如用户说“谢谢”“很好”、工具执行成功)
-1:用户不满意/任务失败(如用户重复提问、工具报错)
0:中性(无法判断好坏)
请只返回数字:+1、-1或0"""
但对于不同场景,这个模板需要深度定制。
三、各场景的PRM定制策略
3.1 终端场景:规则优先
终端场景的特点是信号客观明确 :
| 信号 | 含义 | PRM评分 |
|---|---|---|
| 退出码=0 | 命令执行成功 | +1 |
| 退出码≠0 | 命令执行失败 | -1 |
| 输出为空 | 不确定 | 0 |
定制策略:规则优先,LLM辅助
# terminal_prm.py
class TerminalPRM:
"""终端场景专属PRM"""
def judge(self, action: str, next_state: dict) -> int:
# 1. 规则判断
exit_code = next_state.get('exit_code')
if exit_code == 0:
return 1
elif exit_code is not None and exit_code != 0:
return -1
# 2. LLM辅助判断(处理复杂情况)
prompt = f"""你是终端命令执行评判器。判断以下命令执行是否成功。
执行的命令:{action}
命令输出:{next_state.get('stdout', '')}
错误输出:{next_state.get('stderr', '')}
请判断执行状态:
+1:成功(正常输出结果)
-1:失败(有明显错误信息)
0:不确定"""
response = self.llm.generate(prompt)
return self._parse_score(response)
3.2 GUI场景:视觉语言模型(VLM)介入
GUI场景的核心是视觉状态变化 。论文中使用Qwen3VL-8B-Thinking作为GUI场景的基座模型,PRM也需要具备视觉理解能力。
# gui_prm.py
import base64
from PIL import Image
class GUIPRM:
"""GUI场景专属PRM(基于VLM)"""
def __init__(self, vlm_model):
self.vlm = vlm_model # 视觉语言模型
def judge(self, action: dict, next_state: dict) -> int:
"""
action: {"type": "click", "x": 100, "y": 200}
next_state: {"screenshot": base64, "diff": {...}}
"""
# 将截图转为图像
screenshot = Image.open(
io.BytesIO(base64.b64decode(next_state['screenshot']))
)
# 构建多模态Prompt
prompt = f"""你是GUI操作评判器。判断以下操作是否成功。
执行的操作:{action['type']} at ({action.get('x')}, {action.get('y')})
操作前的期望:{action.get('expected', '')}
请观察操作后的截图,判断:
+1:操作成功(界面按预期变化)
-1:操作失败(无变化或出现异常)
0:无法判断
请只返回数字。"""
# VLM同时接收图像和文本
response = self.vlm.generate(prompt, images=[screenshot])
return self._parse_score(response)
3.3 SWE场景:代码理解优先
SWE场景的核心是代码修改后测试是否通过 。PRM需要理解代码语义和测试输出。
# swe_prm.py
class SWEPRM:
"""SWE场景专属PRM"""
def judge(self, action: str, next_state: dict) -> int:
"""
action: 修改后的代码
next_state: {"test_output": "...", "passed": bool, "error": "..."}
"""
# 1. 测试结果优先
if next_state.get('passed'):
return 1
# 2. 错误信息分析
error = next_state.get('error', '')
if 'AssertionError' in error or 'SyntaxError' in error:
return -1
# 3. 代码质量评估(需要LLM理解)
prompt = f"""你是代码修改评判器。判断以下代码修改的质量。
修改后的代码:{action[:500]}...(截断)
测试输出:{next_state.get('test_output', '')}
请判断:
+1:代码正确,测试通过
-1:代码有明显错误
0:无法确定"""
response = self.llm.generate(prompt)
return self._parse_score(response)
3.4 工具调用场景:返回值分析
工具调用场景的评判相对简单,主要看返回值 :
# tool_prm.py
class ToolPRM:
"""工具调用场景专属PRM"""
def judge(self, action: dict, next_state: dict) -> int:
"""
action: {"name": "calculator", "params": {...}}
next_state: {"status": "success", "result": "...", "error": None}
"""
status = next_state.get('status')
if status == 'success':
return 1
elif status == 'error':
return -1
else:
return 0
四、训练专属PRM的数据集构建
4.1 数据来源
训练专属PRM需要三类数据 :
| 数据来源 | 示例 | 获取方式 |
|---|---|---|
| 历史交互日志 | 真实用户的对话记录 | OpenClaw日志系统 |
| 人工标注 | 对历史交互的评分 | 少量人工标注 + 模型扩展 |
| 规则生成 | 终端退出码、测试结果 | 自动生成 |
4.2 数据集格式
每条训练样本的格式如下:
{
"action": "AI的回复或操作",
"next_state": "用户反馈或工具输出",
"scene": "terminal/gui/swe/tool",
"score": 1,
"reason": "退出码为0,命令执行成功"
}
4.3 数据增强策略
针对样本稀疏的场景,可以采用数据增强:
# data_augmentation.py
class PRMDataAugmentor:
"""PRM训练数据增强"""
def augment_terminal(self, samples):
"""终端场景增强:通过规则生成变体"""
augmented = []
for sample in samples:
# 原始样本
augmented.append(sample)
# 变体1:修改退出码
if sample['next_state']['exit_code'] == 0:
# 成功→失败的变体
neg = deepcopy(sample)
neg['next_state']['exit_code'] = 1
neg['score'] = -1
augmented.append(neg)
# 变体2:修改输出内容
# ...
return augmented
def augment_dialogue(self, samples, llm):
"""对话场景增强:通过LLM生成语义相似的变体"""
# 略
4.4 训练代码示例
# train_prm.py
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
def train_prm(scene="terminal"):
"""训练场景专属PRM"""
# 1. 加载数据集
dataset = load_dataset(f"openclaw/prm-{scene}-2026")
# 2. 加载基座模型
model = AutoModelForCausalLM.from_pretrained("Qwen2.5-7B")
tokenizer = AutoTokenizer.from_pretrained("Qwen2.5-7B")
# 3. 构建训练数据(转为文本生成任务)
def format_sample(sample):
prompt = f"""你是{scene}场景的交互质量评判器。
动作:{sample['action']}
下一状态:{sample['next_state']}
请输出评分(+1/-1/0):"""
target = str(sample['score'])
return {"prompt": prompt, "target": target}
# 4. 微调
trainer = PRMTrainer(
model=model,
train_dataset=dataset['train'].map(format_sample),
learning_rate=1e-5,
epochs=3
)
trainer.train()
# 5. 保存
model.save_pretrained(f"prm-{scene}-v1")
五、PRM集成到RL流水线
5.1 配置文件示例
# config_prm.yaml
prm:
scenes:
terminal:
type: "rule_based" # 终端可用规则
fallback_model: "prm-terminal-v1" # 复杂情况用模型
gui:
type: "vlm"
model: "prm-gui-v1" # 视觉语言模型
num_votes: 3
swe:
type: "llm"
model: "prm-swe-v1"
temperature: 0.1
tool:
type: "rule_based" # 工具调用规则简单
fallback: null
5.2 统一调用接口
# unified_prm.py
class UnifiedPRM:
"""统一PRM调用接口"""
def __init__(self, config):
self.prms = {}
for scene, cfg in config['prm']['scenes'].items():
if cfg['type'] == 'rule_based':
self.prms[scene] = RuleBasedPRM(scene, cfg)
elif cfg['type'] == 'vlm':
self.prms[scene] = VLMBasePRM(cfg['model'])
else:
self.prms[scene] = LLMBasePRM(cfg['model'])
def judge(self, scene: str, action, next_state) -> int:
"""统一评判接口"""
prm = self.prms.get(scene)
if not prm:
raise ValueError(f"Unsupported scene: {scene}")
return prm.judge(action, next_state)
六、实验验证:定制PRM的效果
6.1 论文数据
根据OpenClaw-RL论文,集成定制化PRM后,各场景的提升效果 :
| 场景 | 通用PRM | 定制PRM | 提升 |
|---|---|---|---|
| 工具调用 | 0.17 | 0.30 | +76% |
| GUI | 0.31 | 0.33 | +6% |
| SWE | 0.15 | 0.26 | +73% |
GUI场景提升较小,是因为其本身信号就较丰富;而工具调用和SWE场景依赖过程奖励,定制PRM的效果显著。
6.2 消融实验
# ablation.py
def run_ablation():
"""对比有无定制PRM的效果"""
results = {}
for scene in ['terminal', 'gui', 'swe', 'tool']:
# 用通用PRM
generic_prm = GenericPRM()
acc_generic = evaluate(scene, generic_prm)
# 用定制PRM
custom_prm = load_custom_prm(scene)
acc_custom = evaluate(scene, custom_prm)
results[scene] = {
'generic': acc_generic,
'custom': acc_custom,
'improvement': (acc_custom - acc_generic) / acc_generic
}
return results
七、下一步预告
恭喜!你已经掌握了PRM定制化的完整流程——从理解裁判角色,到各场景定制策略,再到数据集构建和训练部署。现在,你的RL系统拥有了真正“懂行”的评判器。
下一篇文章,我们将聚焦OPD教师模型的训练——如何训练一个能够从用户反馈中提取高质量指导信号、并提供Token级监督的教师模型,实现“后悔引导的同策略蒸馏”。
敬请期待:《OpenClaw-RL 实战 09|OPD教师模型训练:如何让AI从“后悔”中学会“聪明”?》
附录:核心命令速查
# 训练终端场景PRM
python train_prm.py --scene terminal --data data/terminal_prm.jsonl
# 训练GUI场景PRM(需要VLM)
python train_prm_vlm.py --scene gui --data data/gui_prm.jsonl
# 集成测试
python test_prm.py --scene swe --model prm-swe-v1
# 查看各场景PRM效果对比
python ablation.py
文章发布于稀土掘金
(本文为「OpenClaw-RL实战」系列第八篇,共12篇。欢迎关注、收藏、转发,与更多开发者一起探索AI的“边用边学”新范式!)