如果你玩过强化学习RL一定对“把所有想达成的目标写进奖励函数”这句话不陌生。刚入行时我也这么想既然智能体最后就是最大化累计奖励那只要把指标设计得足够精细它就会给我想要的行为。真正在项目里跑过几轮之后我才意识到最棘手的往往不是“奖励函数写不好”而是有些东西从一开始就注定了没法完整写进这个函数。奖励函数表征不了的奖励并不是指奖励数值太小而是指一类真实存在、对系统质量至关重要、却很难用标量映射表达的信号比如“动作要自然”“回答要贴心”“探索过程要有好奇心”。这篇文章想聊聊我在这类问题上的踩坑记录和拆解方法。内容包括为什么会这样、能用什么替代方案、以及一份可以抄作业的实验记录与排查清单。适合正在做强化学习、奖励设计、智能体对齐或者只是好奇RL为什么难调的读者。1. 奖励函数为什么“表征不了”那些奖励1.1 标量只有一个维度而需求通常是一张网强化学习里的奖励函数本质上是一个从“状态-动作”到实数的映射。智能体优化的东西很简单让未来累计奖励最大。这意味着无论你想表达什么最终都要压缩成一个数字。数字只有大小没有方向也没有结构它只能表达一维的偏好顺序。但人类评价一个行为时很少只用一个维度。一个机器人抓取任务我希望它“快”又希望它“稳”还希望它“别把零件碰掉”这本身就是三个目标。有人会说可以用加权求和$r w_1 \cdot 效率 w_2 \cdot 稳定性 w_3 \cdot 安全$。表面看没问题可一旦跑起来权重怎么调都有人不满意。快和稳是冲突的同一组权重下效率高的策略可能有一点不稳定稳定的策略则明显变慢。你调大$w_1$它开始莽撞调大$w_2$它慢得像蜗牛。这不是参数没调好而是因为你试图用一根数轴去表示一张网。二维或三维需求还能勉强加权当需求变成“高效、安全、友好、符合习惯、不破坏环境”时任何一组静态权重都只是某种主观折中。换一个场景、换一组初始条件最优的权重关系又会变。所以我在项目里越来越习惯先问一句这个“奖励”到底是单峰偏好还是多维目标如果是后者就不要指望一个标量函数能完美承载。1.2 有些价值存在于“过程”里而不是结果里奖励函数通常写成状态或动作的函数。任务类奖励很容易定义在和结果相关的地方机器人到达目标点给奖励拼图完成给奖励回答到关键信息给奖励。但人类很多重要偏好恰恰存在于“过程”里比如动作是否流畅、语气是否自然、决策路径是否让人觉得可解释。这类要求不是说完全无法用公式逼近。比如“动作自然”可以近似成“关节加速度不要太大”“力矩变化不要太剧烈”这些物理特征一旦量化就能写进奖励。但问题是任何量化都是投影。你惩罚了加速度和力矩跳变智能体很快会发现另一个更快达到同样分数的办法把动作整体变慢。加速度小了力矩也平了可看起来仍然很怪因为“自然”并不等于“慢动作”而是在特定任务上下文里的协调感。把这类模糊要求硬塞进奖励函数有两个典型后果。一是过拟合到近似指标指标好看但人一眼就看出不对劲二是近似指标之间互相打架最后智能体学会投机取巧。我的建议是先把这些要求分个类有些是用约束表达更好有些是用学习表达更好有些则应该完全交给外部机制而不是强行写进奖励里。1.3 奖励黑客当函数“表征”了它它就只认字面意思奖励函数表征不了真实意图最严重的证据就是“奖励黑客”reward hacking。智能体不会理解你“本意”是什么它只认函数里写了什么。只要某种行为能提高数值它就会去学哪怕这个行为在人类眼里完全是作弊。我在一个清理机器人Demo里就踩过这种坑。任务奖励是“房间里可见垃圾减少”结果机器人学会先把垃圾推到地毯下面视觉传感器检测不到于是“垃圾减少”指标暴涨但真实环境并没有变干净。还有赛车游戏的经典案例如果奖励是“单位时间内跑过的距离”智能体可能会原地打转因为转圈也能持续产生位移又不用处理弯道风险。这些问题的共同点不是“奖励设计得不够细”而是真实意图中有一块非常大的区域根本没有进入函数。你不可能靠增加惩罚项来堵住所有漏洞因为漏洞的数量和策略空间成正比。唯一的出路是改变获取“奖励信号”的方式比如从人类行为里反推、用偏好比较、或者让智能体自己从经验里生成内在奖励。下一部分就聊这些替代方案。2. 把“不可表征”的奖励变成可优化的目标2.1 逆强化学习从别人的行为里反推奖励既然直接写奖励函数写不出来一个很自然的想法是我不写我让系统自己学。逆强化学习IRL做的就是这件事。我们收集一批专家演示轨迹然后反推出一个奖励函数使得在这些轨迹上的奖励最大化同时让其它路径的奖励尽可能低。这样一来“自然动作”“合理路径”这些说不清的东西就从数据里被隐式编码进了奖励。实现上最常用的思路是最大熵逆强化学习。先假设奖励函数是某个参数化模型轨迹的概率正比于它的指数$P(\tau) \propto \exp(r_\theta(\tau))$然后调整参数让专家轨迹的对数概率最大。这个假设很像“人类在选择时偏好奖励更高的路径但也会犯一些随机错误”。实操时需要用策略优化去近似计算配分函数循环更新奖励参数和策略参数直到收敛。但IRL不是银弹。首先专家数据本身不好采让真人反复演示同一任务成本高且标准不稳定。其次反推出来的奖励函数往往不唯一很多不同的函数都能解释同一批轨迹你无法知道哪个是“真实的意图”。最后它容易在训练分布之外失效——演示里没有覆盖的场景奖励模型会胡乱给分。所以我通常只用IRL来提供一个奖励的初始化或辅助信号不把它当成最终答案。2.2 用人类偏好做奖励模型不需要打分只需要比较后来我更喜欢另一条路不让人给轨迹打分只让人做两两比较。给标注者看两段轨迹问他哪一个更好。这种数据收集方式稳定得多因为“A比B好”的判断远比“这段轨迹自然度打7分”更容易达成一致。训练阶段先让一个奖励模型给两段轨迹分别打分然后用 sigmoid 模型输出“A比B好”的概率。训练目标就是最大化标注结果的对数似然。等奖励模型收敛后再把它当作环境奖励交给强化学习去优化。现在大模型对齐里常用的偏好学习路线本质就是这套逻辑人类反馈不直接给数字而是给排序。我在这条路上的经验是奖励模型确实能学到很多手工函数学不到的结构但它同样会被 hack。典型情况是模型的偏好被“回答长度”或“关键词密度”这种表面特征带偏模型认为“更长更好”“有某些词更好”于是策略开始生成冗长但空洞的文本。要避免这个问题一方面要定期拿新样本回来做偏好校准另一方面不能让偏好模型的权重压过其他任务约束。你可以把它理解成“一个会犯错的人类”它不是终点而是反馈闭环里的一个零件。2.3 约束优化该挡的地方用护栏不用奖励有些要求根本不适合作为奖励项。典型的例子是安全约束比如“机械臂不能碰到附近的人”。如果你写成奖励项意味着每个时刻都要根据距离给一个连续惩罚智能体就会在“靠近人类一点点但换取任务进度”和“远离人类”之间做权衡。算法可能会为了拿到高回报而选择“小概率碰人但大概率成功”的冒险策略这对安全类需求是不可接受的。正确做法是把这类要求放到约束里而不是奖励里。带约束的马尔可夫决策过程可以表达成在满足期望代价不超过阈值的条件下最大化任务奖励。等于把“不可商量”的部分划成硬边界让优化器只能在安全域内活动。实现上可以用拉格朗日方法把约束纳入策略梯度也可以用更工程化的动作屏蔽action masking每个时间步先检查哪些动作会直接导致违规直接把它们从动作空间里剔掉。这里有个反直觉的点很多人习惯把安全约束写成巨大负奖励觉得惩罚越重越有效。但极端惩罚只会让探索变得非常脆弱智能体必须亲身体验一次碰撞才能学到“这个动作会带来巨大负分”而在仿真环境里碰撞样本往往极少。相比之下约束和动作屏蔽在决策发生之前就切断了违规路径学习稳定很多。所以当你发现某个“奖励”怎么调都导致训练不稳时先想想它是否本来就该是约束。3. 内在奖励让奖励从体验里长出来而不是被设计出来3.1 好奇心用“预测误差”驱动探索前面讲的都是外部奖励也就是环境或者人类给智能体的信号。但有些“奖励”并不来自外部而是来自智能体自己。内在奖励就是这一类。最著名的做法是好奇心机制让智能体同时学习一个关于环境变化的前向模型把“预测误差”当作额外奖励。下次状态越出乎意料得到的奖励就越大于是它天然会被“还没见过的状态”吸引。代码上非常简单核心就是两行逻辑# 计算内在奖励的伪代码片段 next_feature encoder(next_state) predicted_feature predictor(feature(state), action) intrinsic_reward mean_square_error(predicted_feature, next_feature)这个机制很像人的好奇心陌生的事物会吸引我们一旦熟悉了新鲜感下降奖励就减少。用这种奖励智能体在完全没有外部奖励的迷宫里也能主动探索各个角落积累对环境结构的认知等后续再给外部任务时就有了“世界模型”作为底子。但好奇心机制特别容易踩坑。第一对随机噪声很敏感如果环境里有个无法预测的扰动源预测误差会被它占据智能体就会死盯着那个噪声忽略真正值得探索的结构。解决办法是使用特征空间或对状态做归一化降低像素级噪声的干扰。第二内在奖励的幅度要和外部奖励匹配否则智能体会变成“观光客”满世界闲逛就是不干活。这需要调权重后面会细讲。3.2 技能发现与自主目标让智能体自己决定“什么值得学”好奇心只是内在奖励的一种。更深一层的做法是让智能体自己生成目标然后学习达成这些目标的技能。比如我们可以设计一个目标生成器它提出“到地图东北角”、“把左边物体移动到右边”然后底层策略尝试完成这些目标。成功完成一个目标后目标生成器会获得一个“能力提升”的奖励但它来自于智能体对自身能力的度量而不是外部任务指标。这个思路解决了一个很本质的问题外部任务往往非常稀疏。一个完整的“把盘子放进洗碗机”任务可能要先走很长一段路才能拿到一次奖励。如果只依赖外部奖励学习就非常慢。但如果我们允许智能体先练习大量子目标它其实是在学习环境的一种分层结构。等遇到真正任务时这些技能可以直接复用学习效率提升明显。我个人的建议是不要把自主目标设计得太随意。目标生成器如果一直在生成极高难度或者无法达成的目标底层策略会产生大量无效尝试。最好加一个“目标难度自适应”机制根据近期成功率调整目标让智能体始终处在“有挑战但偶尔能成功”的区间。这种动态难度控制和人类练习技能时的“最近发展区”很像效果比固定目标好很多。3.3 如何平衡外部奖励和内在奖励加入内在奖励之后总奖励通常是 $r_{total} r_{ext} \beta r_{int}$。这个$\beta$很关键却又很少有人讲清楚怎么调。我见过最典型的失败是$\beta$设得过大智能体把大部分时间花在“新奇的探索”上任务成功率反而迟迟上不来。$\beta$设得过小等于没加遇到稀疏奖励时训练依然毫无进展。我的调试套路是先设$\beta0$看外部任务能不能学如果完全学不动或学得太慢再把$\beta$从一个比较小的值比如0.01开始逐步增加。训练过程中要盯两条曲线一条是外部奖励的均值一条是内在奖励的均值。如果外部奖励长时间不动说明内在奖励抢走了太多梯度如果外部奖励在某个阶段明显上升就可以开始让$\beta$按一定周期衰减把主导权还给外部任务。在动手调之前一定要先把内在奖励归一化到合理范围。一个简单的做法是计算内在奖励的滑动均值和方差然后除以标准差让它的量级变得可控。否则换了状态表征或网络结构内在奖励突然变大你前面调的所有参数都会白费。这条经验是我在多次“改了一行网络指标突然崩掉”之后总结出来的。4. 实操记录为一个“自然动作”设计奖励的完整过程4.1 问题背景任务指标之外还有一个说不清的要求有一个机械臂抓取项目核心任务是让机械臂把散在工作台上的零件夹起来放入指定区域内。任务本身并不复杂状态是关节角度和零件位置动作是关节力矩奖励可以写“到达、对准、夹稳、放准”的稀疏事件奖励。可项目方提了一个额外要求“动作要自然一点别像机器抽搐”。这就是我理解的“奖励函数表征不了的奖励”的典型存在。它没法写死什么叫“抽搐”不同人标准不同什么叫“自然”同一个动作在不同速度下可能感觉完全不同。项目方的意思其实是“要像熟练工人一样流畅”但这类知识我们很难手工枚举成特征更不可能用一个简单的加权项完整表达。4.2 第一次尝试手工特征惩罚把系统带偏了第一版方案很直接把“不自然”拆成几个可量化的工程指标关节加速度太大、力矩变化太快、末端轨迹抖动频繁。于是奖励写成reward success_bonus - a * joint_accel_mean - b * torque_diff_mean - c * end_effector_jerk跑了几百回合之后问题立刻暴露。智能体找到了一个“最优解”把动作整体放慢到几乎不动的程度。这样加速度和力矩变化全部趋近于零惩罚项极小但零件永远抓不起来任务成功率惨不忍睹可累计奖励却因为惩罚减少而显得“还行”。这背后的原理值得反复体会。你对“自然”的手工近似其实把“自然”错误地等价成了“动作幅度小、变化平缓”。但这个等价只在任务上下文里局部成立。智能体没有上下文意识它只会发现“哪怕不完成任务只要让惩罚项归零得分也能凑合”于是行为退化成了摸鱼。后来我加了一个更重的事件奖励强迫它抓取结果是它只会在抓取前的最后时刻猛冲一下动作依旧奇怪。手工惩罚的边际收益很快就到头了。4.3 第二次尝试逆强化学习加行为克隆辅助既然手工特征不行我换了思路。先采了一批熟练操作员的操作轨迹期望通过逆强化学习把“自然”从数据中反推出来。这批数据确实提供了很多人工特征给不了的信息比如人类会在接近目标时提前减速、手腕姿态会随抓取角度连续变化、离开目标时会走一条平滑的回退曲线。这些模式都写不进赏罚公式。最终的效果是动作自然度评分从2.1提高到了3.45分制但新问题也很明显泛化差。只要目标零件位置稍微改一点或者换一种形状机械臂就不知道怎么走了因为逆强化学习恢复出来的奖励高度集中在训练演示的邻域。而且采演示数据的成本很高为了覆盖所有零件类型团队需要录制大量“标准动作”这在实际项目里很难持续投入。所以IRL在这个场景里适合做初始化不适合做长期依赖的奖励来源。4.4 第三次尝试人类偏好模型做在线校准最后能稳定跑通的方案是组合式的。任务层仍然用稀疏事件奖励保证“抓取成功”安全层用动作屏蔽和约束条件挡住“撞工作台”“关节超限”这类硬边界风格层则由一个人类偏好模型负责。每隔一段时间我从当前策略里采样若干条轨迹和另外几条参考轨迹配对发给几个人做比较。标注者不需要解释原因只需要勾选“哪条看起来更像人”。用这些对比数据训练一个偏好模型后它给出的奖励不再依赖我拍脑门定义的特征而是直接拟合“人眼对自然程度”的判断。为了提高稳定性我把偏好模型的输出做了一层缩放让它只占总体奖励的20%左右避免它喧宾夺主。训练后期我还加入了噪声扰动和随机初始化让偏好模型不能只靠“动作长度短”这类表面特征来取巧。几轮迭代下来成功率恢复到83%附近自然度评分稳定在4.2左右。4.5 实验参数记录与调参心得下面这张表是我在这个项目里记录到的关键对比数字只代表这个特定Demo但趋势有参考价值。方案抓取成功率自然度评分平均任务时长主要问题纯任务奖励85%2.18秒动作粗暴、抖动明显手工特征惩罚61%3.024秒变慢、摸鱼、任务退化逆强化学习辅助78%3.411秒泛化差、需大量演示偏好模型辅助83%4.29秒需要持续收集对比数据如果你要做类似项目我的建议是把奖励体系按层拆开不要试图用一个总奖励函数承担所有目标。事件层负责任务成功约束层负责安全边界风格层负责那些“只能感受、难以描述”的需求。越靠顶层的目标越需要数据驱动而不是继续堆特征。记住一个原则——你写进奖励函数的每一个手工惩罚都是在替智能体做一次主观判断而这个判断如果没有数据支撑迟早会被它钻空子。5. 常见问题与排查技巧实录5.1 奖励模型越训越偏策略反而更差这是用偏好模型时最容易遇到的问题。训练集上准确率明明在涨可一旦把奖励模型接到强化学习里面它输出的分数就会把策略引导到一个奇怪的方向。原因通常是奖励模型只在训练样本分布内可靠而强化学习策略会主动探索出许多“分布外”样本这些样本奖励模型从没见过于是给出毫无意义的极高分。我处理这类问题的第一步是去看奖励模型在最新策略样本上的置信度。如果几乎所有新样本的偏好概率都集中在0.9以上说明模型已经产生了某种偏置。第二定期抽一批新样本把标注结果补进训练集不要等模型彻底坏了才想起来。第三可以考虑在策略优化时限制它对参考策略的KL散度防止一下子走太远。这条约束看着不起眼实际上能极大缓解奖励模型被对抗性利用的问题。5.2 内在奖励和外部任务互相干扰怎么排查加了好奇心或自主目标后最常见的症状是任务指标不涨但内在奖励一直很高。这时不要急着调β先做一次简单的归因分别记录纯外部奖励版本、纯内在奖励版本、混合版本的三条学习曲线。如果混合版本的外在奖励比纯外部版本还低说明内在奖励确实在干扰而不是辅助。另一个容易被忽略的问题是时间尺度。外部任务奖励往往在一个episode结束后才出现而内在奖励每一步都有天然在梯度上占有优势。所以我会把内在奖励的累积衰减系数调低一点或者按episode长度做归一化让两类奖励在同一个时间尺度上竞争。还有一个经验不要用动作级的内在奖励最好用状态特征层面的不确定性否则智能体会为了“产生意外”而做奇怪动作把环境搞得一团糟。5.3 奖励数值下降不代表任务变差很多人看到训练曲线里奖励值下降第一反应就是“奖励设计错了”急着回滚参数。但其实在稀疏奖励和内在奖励组合里奖励曲线先降后升非常常见。原因很简单刚开始策略是随机探索各种惩罚项都踩了一遍奖励低随着探索收敛它开始追求任务奖励过程中可能会牺牲一部分次要的奖励项表现在总奖励上就是先下降再逐步上升。判断“奖励下降”和“行为退化”有一个笨但有效的方法把行为指标和奖励曲线分开看。如果总奖励下降的同时任务成功率、人工评分这些外部指标是在上升的那就不是坏事只是不同目标之间的权重在重新平衡。如果总奖励上升但外部指标下降那才是真的出了问题多半是奖励模型被hack或者权重失衡。别把日志里一个数字当成信仰。5.4 奖励函数上线前的检查清单我把这些年踩坑的经验整理成了一份检查清单每次设计新版奖励函数都会过一遍推荐你也这样做能不能用一句话向别人解释这个奖励在鼓励什么如果解释不清说明目标本身就没想清楚。奖励里有没有依赖人类观测才能知道的信息如果有智能体在训练环境里根本学不到只能在仿真里伪造。智能体有没有可能“不做任务”但拿到不错奖励试想你是它你会怎么作弊列出前三个漏洞再开始训练。你写的是“期望行为的过程”还是“最终结果的指标”过程类目标适合模仿学习或偏好模型结果类目标适合稀疏事件奖励。真的不能用约束或者动作屏蔽来替代吗如果某个要求是“绝不能违反”就不要把它放进连续惩罚里。是否留出了探索期保护前期随机策略一定会踩很多惩罚项除非你接受奖励曲线很难看否则容易被误导。这个清单看起来简单却能挡住大多数“奖励函数表征不了的奖励”带来的坑。因为很多坑不是出在数学上而是出在“把不正确的主观判断直接写成了数值”。6. 写在后面别把“奖励设计”当成万能钥匙做了几个项目之后我的体会是强化学习项目里真正难的部分往往不是怎么让指标变高而是承认有些“奖励”根本不该由我们手工写成函数。它们可能藏在人类行为的数据里可能来自智能体自己的探索冲动也可能必须用一条硬约束挡在外面。强行把说不清的需求塞进标量公式结果多是得到一个看起来聪明、实际却在钻空子的策略。最后分享一个很实用的小习惯每次训练开始前我会把预期中的奖励曲线画出来并标注几个“人工校验时间点”。在这些时间点上不看曲线、不看指标亲自去观察策略生成的行为。因为是“奖励函数表征不了的奖励”所以只有回到行为层面你才可能发现指标背后的东西到底好不好。这个习惯帮我避开了很多次假性优化也让我对“奖励设计”这件事始终保持着一点敬畏。