规划 Agent 需要区分硬约束与软判断:预算、时间窗等可计算条件交给程序验证器,其余质量判断由奖励模型处理,并用留出评测核对奖励上涨是否对应任务改善。源码能说明分数如何组合,但不能证明验证器已覆盖全部漏洞,也不能独立证明文末的内部评测涨幅。
我在规划 Agent 上反复遇到这个问题:方案看起来合理,实际超了预算;路线看起来顺,时间窗却排不开。奖励模型(RM)有时会给这些方案高分,RL 随后就会利用这些误判。所以我把能用程序检查的约束写进 VerifierResult,其余判断才交给 RM。
这就是 古德哈特定律 (Goodhart’s Law) 在后训练里的样子:当一个度量变成目标,它就不再是一个好的度量。 Manheim 与 Garrabrant 在 Categorizing Variants of Goodhart’s Law (2018) 中将回归型、极值型、对抗型失效分开,这帮助我区分了后来遇到的 RM 失效。排查时,我关心的是策略偏离到什么程度,奖励就不再反映实际质量,以及能否在此之前停止优化。
程序验证器与模型评分的分工
验证器(RLVR)。一段固定的代码去检查输出。方案是否没超预算?时间窗是否真的排得开?最终的数是否正确?当正确性可被程序校验时,这是黄金标准。它的核心价值在于:只要检查是完备的,它没有可供利用的盲点。
奖励模型(RM)。当没有程序能判时,一个学出来的模型给质量打分。判断“方案合理且可执行吗”没有干净的 oracle。RM 给你一个验证器够不到的信号。但它本身是个拟合出的网络,必然存在决策边界的盲区,而策略会用极大似然去试探每一个盲区。
验证器与真实目标的相关性对优化压力是平坦的——它是一段确定性程序,真正没超预算的方案始终会被判为正确,不存在移出训练分布的问题。RM 正好相反:它是有限样本上拟合出的有限模型,与真相的相关性随着策略移出分布而急剧衰减。每一步优化,都是朝着 RM 从没见过、最可能出错的输入迈进。基于这种不对称,我的架构设计是:把所有可校验的逻辑下沉到验证器,只让 RM 兜底不可计算的模糊余项。
规划 Agent 的真实奖励被拆解为这样一条计算流:
[ 策略输出方案 ]
|
+---> (精确计算) 验证器 (Verifier) ---> [ 预算 / 时间窗 / 可行性 ] (硬约束信号)
|
+---> (统计推断) 奖励模型 (RM) ---> [ 语义合理性 / 语气 ] (软质量得分)
|
v
最终奖励 (Reward) = \lambda_1 * 验证器得分 + \lambda_2 * RM 得分
代码里的验证器实现
在 Orbit 项目里,验证器被收敛成一个协议(Protocol)。在 orbit/verifiers/base.py 中,它只负责把轨迹映射为结构化奖励。契约由两个 pydantic 模型承载:VerifierSpec 持有超参旋钮,VerifierResult 持有拆解后的输出:
class VerifierSpec(StrictModel):
kind: str = "static_trace"
gamma: float = 0.99
lambda_delta: float = 1.0 # 势函数塑形权重
lambda_g: float = 1.0 # 局部(每步)分数权重
lambda_env: float = 1.0 # 环境奖励权重
lambda_u: float = 1.0 # 终局效用权重
process_weight_max: float = 4.0
baseline_strategy: str = "trajectory_mean"
奖励并不是单一标量。在 orbit/verifiers/static.py 中,StaticTraceVerifier.verify 用四个加权项拼出每步的密集奖励:
reward = (
self.spec.lambda_delta * (phi_prefix[idx + 1] - phi_prefix[idx]) # 势函数差分
+ self.spec.lambda_g * local_scores[idx] # 单步即时奖励
+ self.spec.lambda_env * env_rewards[idx] # 外部环境反馈
)
if idx == len(local_scores) - 1:
reward += self.spec.lambda_u * terminal_score # 终局结算
第一项是基于势的塑形 (Potential-based Shaping)。根据经典强化学习理论,势函数 在两步之间的差分,可用于提供稠密引导,但策略不变性结论有折扣和边界条件。此处实现先取未折扣的势差,再计算折扣回报,不能仅凭这段代码宣称策略不变或能够规避 reward hack。随后对这些反馈进行折现计算,并用 process_weight_max 进行硬裁剪。裁剪限制了单步的异常优势梯度,避免它主导策略更新。
奖励过度优化:代理分数与真实质量
开发时我遇到过这样的背离:训练 Reward 持续上涨,留出集 Benchmark 却停滞甚至下降。模型过拟合了 RM 的评分方式,实际任务表现没有改善。如 DeepMind 收录的 Specification gaming 案例集 所示,Agent 总能找到违背精神却满足字面的漏洞。
Gao、Schulman 与 Hilton 在 Scaling Laws for Reward Model Overoptimization (2022) 中精确刻画了这种现象:代理 RM 分数单调上升,而真实金标准分数先升、见顶、然后回落。金标准奖励可以拟合为 KL 距离 的函数:
这个拟合意味着,存在一个最优 KL 距离,超过这个预算,每多 1 nat 的散度带来的都是真实性能的倒退。扩大 RM 规模能推迟这个顶点的到来,但无法消灭它。
另外,正如 Pan 等人在 The Effects of Reward Misspecification (2022) 中指出的,随着能力提升,策略会发生相变式跳变,骤然发现并利用 hack。
使用留出检查评估奖励过度优化
- 补全验证器。把所有可计算约束写进程序,这是我最优先处理的部分。
- 保留 KL 正则。带 KL 正则的目标具有闭式最优解: 决定了允许奖励倾斜参考先验的力度。那些为了刷分而产生的乱码或格式复读,正是由于 给出的先验概率近乎为零,所以可以通过调节 作为强力刹车。
- 对抗更新。策略学会的新把戏就是 RM 的 Out-of-Distribution 样本。必须将策略的失败模式持续打标并重训 RM,保持分布同步。
- 信评测,不信奖励。留出集的验证器 Benchmark 才是唯一的真相。
最终,我在规划 Agent 上拿到了复杂约束满足率 12% 的内部 Benchmark 涨幅。改进来自补全验证器、将硬约束完全移出 RM,以及持续处理策略产生的新 exploit,优化器本身没有变化。
验证器还决定后训练数据管线保留哪些样本,因此检查奖励漏洞也是数据质量控制的一部分。
评论