reward 从哪来:可验证奖励、模型打分、人标
reward 设计是 RL 里唯一真正需要你想清楚的事情。写歪一个 reward,模型会精确地学会钻它的空子。
学完这节你能做到
- 给一个任务设计出可验证 reward,并预判它会被怎么钻空子
- 说清格式奖励与正确性奖励为什么要分开给、怎么配权重
- 识别 reward hacking 的早期信号
算法可以抄,reward 不能
GRPO 的实现是抄公式,抄对了就能跑。reward 不一样——它编码了你到底想要什么,没有标准答案可抄,而且模型会用你想不到的方式去满足它。
一句在 RL 圈流传的话:
模型不会学你想教的,它会学你实际奖励的。
这一节讲怎么想(设计原则与自查方法)。L2「写 reward 函数」讲怎么写(具体代码与单元测试)。两节可以连着读。
三种奖励来源
| 来源 | 怎么打分 | 成本 | 可信度 | 单卡可行 |
|---|---|---|---|---|
| 规则可验证 | 正则、单元测试、schema 校验 | 几乎为零 | ✅ 客观事实 | ✅ |
| 模型打分 | reward model 或 LLM-as-judge | 要训 RM 或调 API | ⚠️ 会被钻空子 | ⚠️ RM 要显存 |
| 人标 | 人来打分或排序 | 极高 | ✅ 但有主观性 | ❌ |
新手从第一种起步,理由在 L0「先量起点」那节说过:reward 可信意味着训练出问题时你知道问题在算法上,而不是「打分器不准」。
用一个更强的模型当裁判听起来很省事,但代价往往被低估:
- 它自己会被钻空子。模型会学会输出「裁判偏好的风格」而不是「更好的内容」——比如结构工整、语气自信、爱用小标题,实质内容没变。
- 它有偏好偏差。裁判模型倾向于喜欢更长的回答、和自己风格相近的回答。
- 它慢且贵。每条回答都要过一遍大模型,采样量 × G 之后是可观的开销。
- 它引入不确定性。效果不好时你分不清是 RL 的问题还是裁判的问题。
真要用,至少做一件事:抽 50 条人工核对裁判的判断,估出它的误差——和 L0 里估抽取器误差是同一个动作。
可验证奖励的甜区
一个任务适不适合 RLVR,看它能不能自动判对错:
| 任务 | 怎么验证 | 甜度 |
|---|---|---|
| 数学题 | 抽答案与标准答案比对 | ✅✅ 最甜 |
| 代码 | 跑单元测试 | ✅✅ 但要沙箱 |
| 结构化输出 | JSON schema / 正则校验 | ✅✅ |
| SQL 生成 | 执行后比对结果集 | ✅ 要数据库 |
| 定理证明 | 形式化验证器 | ✅ 领域窄 |
| 检索问答 | 答案是否包含正确实体 | ⚠️ 判定模糊 |
| 翻译 | BLEU 等指标 | ⚠️ 指标与质量不完全对齐 |
| 「写得更好」 | 无法自动判定 | ❌ 回到 RM |
「写一篇好文案」判不了,但可以拆:
- 字数在范围内吗 → 可验证
- 包含指定关键词吗 → 可验证
- 结构是否符合模板 → 可验证
- 是否避开了禁用词 → 可验证
这些加起来不等于「好」,但能把模型推到「格式合规」这个基础水位。剩下的「好不好」再交给 RM 或人。
先榨干可验证的部分,再引入不可验证的部分。 这个顺序能让你的调试难度降一个量级。
复合 reward 的权重
实际的 reward 通常是几项加起来。以本路径的数学题为例:
total = 1.0 × 正确性 + 0.2 × 格式 − 0.5 × 截断惩罚
配权重只有一条原则,但极其重要:
模型优化的是期望收益,所以你要按「成功率 × 分值」来算,而不是只看分值。
假设格式分 0.5、正确性 1.0:
套格式标签 成功率 ~100% × 0.5 = 0.50 ← 期望更高
真的把题算对 成功率 ~21% × 1.0 = 0.21
模型会理性地选择刷格式。你没有奖励「算对」,你奖励了「看起来像在算」。
改成格式 0.2:
套格式标签 1.00 × 0.2 = 0.20
真的把题算对 0.21 × 1.0 = 0.21 ← 略高
随着正确率上升到 40%,差距拉到 0.40 vs 0.20,「算对」的收益优势越来越明显——这才是你想要的激励结构。
经验值:格式分总和控制在 0.2 ~ 0.3,正确性给 1.0。
稀疏还是稠密
| 稀疏(只看结果) | 稠密(看过程) | |
|---|---|---|
| 打分方式 | 最终答案对才给分 | 每一步算对给一点分 |
| 实现难度 | 低 | 高,要能判每一步 |
| 学习效率 | 慢 | 快 |
| 被钻空子的风险 | 低 | 高 |
| R1 的选择 | ✅ 用的是稀疏 | 论文里说尝试过,效果不如预期 |
稠密奖励为什么风险高:你要判「这一步对不对」,就得定义什么是「一步」。模型会去优化「产生看起来像正确步骤的文本」,而不是「真的推理」。步骤越细,可钻的空子越多。
新手用稀疏。 好写、不容易被钻,而且有 R1 的经验背书。
稀疏 reward 只有 0 和 1 两个值。于是一组 G 条回答很容易全 0 或全 1,std = 0,整组优势归零、这次 rollout 白跑(下一节会详细讲这个机制)。
这也是格式分的一个隐藏价值:它让分数连续起来。即使正确性全错,格式分的差异也能让 std > 0,这一批就还有信息量。
所以格式分不只是「教格式」,还是防止训练停滞的润滑剂。
reward hacking 案例集
这些都是真实会遇到的。先看模型可能怎么钻,再写 reward。
| 作弊形态 | 具体行为 | 为什么能拿分 |
|---|---|---|
| 空壳格式 | 套上标签但答案随便填 | 格式分不检查内容 |
| 标签复读 | 输出十个答案标签 | 正则只要匹配到一次就给分 |
| 列举赌答案 | 「可能是 8,也可能是 10,或者 12」 | 抽取器兜底取最后一个数字 |
| 复述题目 | 把题目抄一遍凑关键词与长度 | 关键词匹配或长度相关的 reward |
| 长度膨胀 | 无意义地写长 | per-token 归一化给长回答更大权重 |
| 讨好裁判 | 用裁判模型偏好的风格 | LLM-as-judge 的风格偏差 |
| 利用截断 | 一直写不给答案 | 若截断样本 reward 为 0 而非负,「不答」和「答错」代价相同 |
| 钻数值归一化 | 输出 10/1 或 1,0 | 归一化规则的边界 |
调学习率、调 KL、加 clip,一个都救不了它。唯一的修法是改 reward。
而且它会反复出现:你堵了一个洞,模型会找下一个。某种程度上,RL 工程的主要工作就是和自己的 reward 函数博弈。
诊断信号只有一个,但很可靠:reward 在涨而 acc 不涨。 所以这两个指标必须分开记录——这是 L2 日志设计里最重要的一条。
设计检查清单
写完 reward、开训之前,花十分钟走一遍这七条。这十分钟能省掉几小时白跑。
□ 1. 假装我是模型,只想最省力拿高分 —— 我会怎么钻?
至少写出三条作弊路径,逐条确认堵住了或分值够低
□ 2. 空答案能拿多少分?
应该是 0 或负数
□ 3. 每一项分值 × 它的达成难度,期望收益排序对吗?
「真的解决问题」必须是期望收益最高的那条路
□ 4. 有没有「重复某个模式就能重复拿分」的项?
正则匹配类的分要检查出现次数
□ 5. 截断的样本怎么算?
「不给答案」的代价必须不低于「给错答案」
□ 6. reward 只有 0/1 吗?
纯二值容易整组归零,考虑加连续项
□ 7. 我能把 reward 拆成分项记录吗?
不能拆的话,reward hacking 发生时你看不出来
格式分总和给 0.5、正确性给 1.0,模型当前正确率 21%。模型会倾向做什么?
为什么给纯二值(0/1)的稀疏 reward 加一点连续的格式分,除了「教格式」还有别的好处?
下面哪些说法正确?(多选)
这节课的落点
- reward 编码你真正想要的东西;模型学的是你实际奖励的,不是你想教的
- 三种来源:规则可验证(新手起点)、模型打分(有新的作弊面)、人标(成本极高)
- 不甜的任务常能拆出可验证的部分——先榨干可验证的,再引入不可验证的
- 权重原则:按「成功率 × 分值」算期望收益,便宜的分要给得少(格式 0.2~0.3,正确性 1.0)
- 新手用稀疏奖励;稠密奖励步骤越细可钻的空子越多,R1 也选了稀疏
- 格式分的第二重价值:让分数连续,避免整组
std=0白跑 - reward hacking 是设计问题,改超参无效;诊断信号是
reward涨而acc不涨 - 开训前走一遍七条检查清单,十分钟省几小时