
如果你尝试过用强化学习去训练一个智能体完成多步操作的任务大概率经历过这种至暗时刻环境跑了几十万步回报曲线纹丝不动智能体像一只刚睁眼的雏鸟完全不知道自己该往哪儿走。问题往往不在算法而在奖励太稀疏。大部分时间步拿到的都是0只有最终成功才有一个正信号整个学习过程等于闭着眼睛在高维空间里乱撞。这两年我一直在关注一个思路最近在学术社区里讨论度上升得很明显用大语言模型构建进展奖励模型Progress Reward Model把“有没有变好”变成一个即时的、平滑的、可学习的信号塞进强化学习循环里。这个方向不直接判断“你成功了没有”而是判断“这一步是否比上一步离目标更近”。听起来很朴素真做起来有不少门道状态怎么变成文字、LLM怎么打分才算稳、分数怎么跟环境真值奖励混在一起、会不会引入偏置、会不会被智能体钻空子。这篇文章我会把这个方向从动机到实现完整拆开讲结合我自己复现和调试的经验给正在做RL算法、机器人操控落地、游戏AI开发的读者一些可参考的结论。1. 进展奖励模型到底在解决什么问题1.1 稀疏奖励是强化学习实践者的共同痛点先举一个很常见的例子。假设你有一个机械臂任务是抓取散落在工作台上的螺丝再把螺丝拧到电路板对应位置。整个过程至少需要十几个连续动作移动、定位、抓取、抬升、对准、下压、旋转。如果环境只在最终成功时给一个1奖励其他步骤全是0那么策略优化算法在绝大多数时间步里完全得不到反馈。数学上看这个问题更直观。设一个episode长度为T仅终态s_T有奖励R1。于是对所有中间状态-动作对(s_t,a_t)的蒙特卡洛回报几乎处处是0除非某个偶然轨迹最终成功。价值函数几乎没有梯度信号可以被利用策略只能在随机探索中碰运气。我在实际项目里见过太多类似的失败案例训练日志上loss曲线正常下降但评估指标纹丝不动最后查下来不是算法bug而是奖励本身就没给够信息。这也是为什么近年来好奇心驱动、内在动机、课程学习这些方向会被反复拿出来讨论。大家本质上都在做同一件事把稀疏的、延迟的反馈变成稠密的、即时的信号。进展奖励模型也是这条思路的延续只不过它把“如何定义进展”这个最头疼的问题交给了大语言模型。1.2 从终点奖励到过程信号奖励塑形的老传统如果只追求“让中间步也有奖励”最直接的方案是奖励塑形reward shaping。经典做法是potential-based shaping给每个状态定义一个势能Φ(s)然后额外奖励设为γΦ(s) - Φ(s)。理论上有保障只要势能函数合理最优策略不会改变。但问题在于谁去定义这个势能函数。在机器人任务里你得依赖领域专家手工评估每个状态的好坏程度工作量大不说还很容易出错。更麻烦的是reward hacking。势能函数设计得不够周全时智能体会找到捷径比如朝势能升高的方向来回乱动虽然每一步都能拿到一点塑形奖励但整体任务根本完不成。这类案例在真实项目中屡见不鲜尤其是那些势能定义依赖坐标距离的任务智能体经常学会在目标点附近振荡而不是真正完成任务。进展奖励模型PRM本质上做的还是塑形这件事但它把“设计势能函数”这个环节转移给了LLM。LLM不直接生成奖励数值而是负责判断“当前状态相对上一步状态是否更接近目标”再由外部代码把这个判断转化为奖励信号。好处很明显对每个新任务不需要重新设计势能函数只需要写一段任务描述然后准备一个状态转文字的适配器。1.3 为什么偏偏是大语言模型你可能会想为什么不单独训练一个“进展评估网络”理论上当然可以但落地成本很高需要为每个新环境标注大量轨迹数据来训练专用评估器并且它在分布外场景下很容易失效。环境稍一变评估器可能给出完全错误的结果。LLM有一个别人不容易替代的优势跨任务的语义理解能力。你不需要为每个任务重新训练评估器只需修改提示词里的任务描述。对大量连续控制、导航、游戏环境来说状态本来就可以描述成文本——位置、朝向、物品状态、任务进度。LLM像一个场外裁判盯着智能体的行动轨迹判断它是在靠近目标还是在瞎转悠。为了更直观我整理了一个对比表格方案人工成本通用性信号密度可解释性最大的坑手工塑形函数高差中好诱导刷分学习型奖励模型高差高差分布外失效LLM进展评估低好高中判断偏差从工程角度看判断偏差这种问题虽然存在但远比诱导刷分和分布外失效更容易由人来干预修正。你可以通过改提示词、改文本化方式、加校验规则来控制LLM的行为这种可干预性非常重要。2. 核心设计思路与技术拆解2.1 三种典型的进展信号建模方式具体实现上进展信号大致有三种建模方式各有适用场景。方式A是直接打分式。把当前状态描述和上一步状态描述一起丢给LLM让它输出一个1到10的整数表示“更接近目标的程度”。这种方式最简单也是大多数初版实验的首选。优点是快速验证可行性缺点是分数绝对值漂移较大需要额外的归一化处理。方式B是子目标生成式。先让LLM根据当前状态输出“接下来最合理的子目标”然后用当前状态与子目标在状态表示空间中的距离作为进展信号。比如在一个导航任务中LLM判断“你下一步应该移动向门口”如果状态表示是二维坐标那么离门口越近进展分数就越高。这种方式把进展度量转化为空间距离信号平滑但有一个隐含前提状态表示必须与LLM输出的子目标可以对齐否则会引入不可控的误差。方式C是奖励函数生成式。让LLM直接输出一个奖励函数的代码片段由环境在线调用。这种方式工程化程度最高但调试也最麻烦。代码里的一个隐式错误可能导致训练完全崩溃而且很难定位是奖励函数的问题还是强化学习算法本身的问题。我的经验是方式A适合快速验证方式B适合状态有明确几何意义的环境导航、机械臂运动方式C适合长期工程化和推理型任务。目前社区讨论最热、也最容易复现的其实是方式A加上各种校准技巧。2.2 文本化状态把状态翻译成LLM能懂的话LLM只懂文字环境状态必须被转成文本这一步直接决定了进展信号的质量。常见做法有两类。第一类是结构化描述尽量保留关键数值。比如“智能体位于(3.2, 7.8)目标位于(5.0, 9.0)当前持有钥匙true门状态锁住”。这种描述信息密度高但token开销大上下文过长后LLM的判断稳定性也会下降。第二类是语义摘要用自然语言概括整体局势。比如“智能体已经走出起始房间正在穿过走廊远处能看到目标房间的标志”。这种描述更贴合LLM的语义理解能力适合长程任务但数值精度容易丢失。我推荐的是混合式方案关键数值和简短语义描述同时保留。例如“位置从(2.1, 3.0)移动到(2.3, 3.4)距离目标(5.0, 5.0)由3.6缩短为3.1正在向目标方向靠近”。这样LLM既能看到明确的数值变化又能理解语义上下文判断的可靠性会明显提升。还有一个我踩过坑后总结出来的原则不要把计算任务留给LLM。比如让LLM去计算两点之间距离再判断远近往往不够稳定。更好的做法是提前算好距离差直接把“距离从3.6缩短到3.1”这个结论写进文本里。LLM擅长阅读结论不擅长做算术这一点在实际调试中极其重要。2.3 绝对分数不靠谱从进展分数到相对优势直接把LLM给出的分数当作奖励用效果通常不好。原因是LLM在没有明确锚点的问题上分数的绝对值漂移很大。同一个状态换个措辞描述可能5分变8分。这种漂移反映到强化学习里相当于给奖励信号注入环境噪声会让价值函数的收敛变得很不稳定。我在实际测试中发现相对比较比绝对打分稳定得多。与其问“这个状态有多接近目标”不如问“状态A和状态B哪个更接近目标”然后根据对比结果换算成相对分数。这种配对比较可以减少LLM对分数尺度的依赖因为它只需要做“更”与“不更”的定性判断。另一个常用技巧是batch内归一化。把同一批LLM评估的分数做min-max标准化或z-score标准化消除不同批次间的基线漂移。如果用在PPO这类基于advantage的算法里我建议直接用“进展差分”progress_t - progress_{t-1}。它刻画的是“这一段短时间内变好了多少”语义上更接近奖励信号的定义比直接使用绝对分数干净得多。2.4 进展奖励与环境真值奖励的合成策略纯用LLM进展信号有风险。LLM不可能永远正确它的错误判断可能把智能体带去错误方向。所以我的建议一直是把进展奖励当作辅助信号而不是唯一信号。最常见的混合方式是加权相加R λ * R_progress (1-λ) * R_truth。训练初期λ取大一些比如0.7到0.8让智能体主要靠LLM信号引导探索方向随着训练进行λ线性退火到0.2左右让环境真值奖励逐步接管主导地位。这个策略我会强烈推荐。它的本质是让进展信号当“教练”在前期带智能体走上正确的探索方向真值奖励当“评分员”在后期保证最终策略与真实任务目标对齐。这样做的好处是即使进展信号偶尔出错也只影响早期探索而不影响最终策略的收敛质量。3. 实操要点与全流程实现3.1 提示词模板设计提示词是进展奖励模型里最关键的工程参数之一。我用过的比较稳定的模板如下你是强化学习环境的进展评估器。你的任务是判断智能体是否正在向最终目标靠近。 任务描述{task_description} 最终目标{goal} 当前状态{current_state_text} 上一步状态{previous_state_text} 请根据状态变化判断智能体距离完成目标的进展程度。 输出一个1到10的整数10表示非常接近完成1表示完全没有进展。 只输出数字不要输出其他内容。有几个细节值得注意。第一个细节是措辞要强调“完全没有进展”而不是“失败”。区别非常大前者是跟踪相对变化后者是分类终态两种措辞会引导LLM输出不同的分布。第二个细节是要求“只输出数字”这避免了输出结果解析的问题训练流水线上直接取整就行。第三个细节是你也可以让LLM先输出一句简短推理再输出分数这种方式能降低幻觉概率但会增加token消耗实际取舍看任务的重要程度。3.2 批量并发与缓存策略每次LLM调用都存在网络延迟和推理延迟。如果在训练循环里同步等待训练速度会被拖垮。我习惯的做法是采样频率降低比如每3步取一次进展信号把一批状态描述并发发送出去用Python的线程池或异步IO实现对几乎相同的状态做缓存如果当前状态与某条已评估轨迹的状态距离足够小直接沿用上一次的分数。这几个策略叠加后一轮千步级别训练里的LLM调用次数可以降到原来的十分之一以下。对预算敏感的实验尤其有用成本控制效果立竿见影。3.3 与主流RL算法的整合一个PPO训练循环示例下面的伪代码展示了进展奖励如何嵌入一个标准PPO训练循环。核心是已经实现好的get_progress_by_llm()函数以及每N步才触发一次评估的逻辑。import numpy as np def train_one_episode(env, policy, llm_evaluator, lambda_progress0.7): obs env.reset() prev_state_text state_to_text(obs) last_progress_score 0.0 trajectory [] reward_buffer [] for step in range(episode_limit): action policy.sample_action(obs) obs, sparse_reward, done, info env.step(action) if step % 3 0: current_state_text state_to_text(obs) progress_score llm_evaluator.evaluate( current_state_text, prev_state_text ) progress_reward progress_score - last_progress_score last_progress_score progress_score reward_buffer.append( lambda_progress * progress_reward (1 - lambda_progress) * sparse_reward ) else: reward_buffer.append(sparse_reward) trajectory.append((obs, action, reward_buffer[-1], done)) prev_state_text state_to_text(obs) if done: break # 用PPO更新policy这里略去 # policy.update(trajectory)需要注意的一点是进展差分奖励的时机步差。因为LLM每几步才评估一次差分信号在时间维度上覆盖的是一个小窗口语义上是“这一小段是否变好”。这种设置比每步都给绝对分数更符合奖励信号的语义PPO的advantage估计也更稳定。3.4 训练阶段与参数选择参数这块我给出保守的经验值方便少走弯路LLM温度0到0.2。温度过高会让分数不稳定这种场景不需要创造性。进展采样间隔2到5步。太密只会增加成本未必提升信号质量。状态文本长度控制在200到300 token以内。过长上下文会稀释关键信息。λ初始值0.6到0.8训练中后期衰减到0.2左右。归一化方式对每批次LLM分数做min-max缩放或z-score消除漂移。这些参数在不同任务上可能需要微调但大致方向是一致的进展信号要足够平滑、足够稀疏调用频率、最终权重不能压过真值奖励。3.5 算力开销控制成本是一个容易被低估的问题。假设一次训练要跑10000步每3步调一次LLM那就是3333次调用。用商用API的话开销很快会积累到让人肉疼的程度。我的建议是试跑阶段优先用开源7B级别的小模型做本地部署性价比高验证效果足够等确认整个流程跑通、有效果再换成更强的模型做最终实验。还有一个省钱技巧是做模板缓存同一类轨迹上的状态描述往往相似命中缓存的话直接返回历史分数能省下大量调用。4. 一个具体Demo用进展奖励训练网格导航Agent4.1 环境设计写再多的理论不如动手搭一个最小复现环境。我在本地实验时搭的是10x10的网格世界智能体从(1,1)出发目标是在某个位置拾取钥匙再移动到出口(9,9)。原始奖励非常稀疏只有到达出口才给1。这是最典型的稀疏奖励导航任务。状态表示很简单当前坐标、是否持有钥匙、出口坐标。动作空间是上下左右四步移动。4.2 状态文本化与PromptPrompt写法直接影响效果。我当时用的是这个形式任务在一个10x10网格中导航到出口。 你已经获得钥匙true 当前位置x2, y3 上一步位置x1, y2 离出口的距离从10.2减少到9.0。 你正在靠近出口吗输出1-10的分数。注意到没有距离变化已经在文本里写好了。这是我反复强调的“不要让LLM做算术”输出结论比让LLM自己推导要可靠得多。4.3 实测观察到的几个现象这个Demo虽然简单但几个现象很有代表性。第一个是探索行为显著改变。没用进展奖励的Agent在稀疏奖励下基本是原地打转偶尔靠运气才移动几步加了进展奖励之后Agent会更主动地朝钥匙方向移动因为LLM会给它正的进展分。第二个是LLM误判情况确实会发生。比如Agent连续朝错误方向走但每步距离只变化0.1左右这种微小的变化可能被LLM误认为是进展。我的解决方式是在文本描述中加入显式规则“如果距离增大了一定要给低分”。第三个是收敛速度的差异。在这个简单环境里加了进展奖励的Agent收敛速度比纯稀疏奖励大约快2到3倍。这个数字在简单环境中不算夸张但如果是更长的任务差距会拉得更明显。4.4 最小验证实验建议如果你想在现有项目里快速验证这个方向我建议做这个最小实验选一个你手头正在跑的稀疏奖励环境把奖励改成“稀疏真值奖励 LLM进展奖励”的混合形式跑50个episode对比回报曲线。计算量很小但足够让你判断这条路值不值得继续走。5. 常见问题与避坑手册5.1 LLM分数飘忽不定怎么排查如果同一个状态换一种描述方式分数就明显不同先检查状态文本化是否“精确且无歧义”。比如把“靠近目标”这种模糊说法替换成“距离目标从3.2变为3.0”这种精确描述。另一个有效手段是多轮采样取中位数同一对状态连续请求三到五次把结果的中位数当成最终分数稳定性提升非常明显。5.2 进展信号把Agent带偏了这是最让人头疼的问题本质是LLM对任务目标的解读与真实目标不一致。举个例子一个任务要求先取钥匙再出门但LLM认为只要接近门就是进展Agent就会跳过取钥匙直接冲向门口然后卡死。解决办法是把目标序列写清楚“请先判断智能体是否朝钥匙方向移动再判断是否朝出口移动”而不是只给一个笼统的最终目标。5.3 文本化丢失数值精度如果状态转成文本时只保留一位小数你其实人为压缩了环境的原始信息进展信号就会失真。最好的做法是数值和语义同时保留。“距离goal从3.42变为3.30”比“离goal更近”可靠得多因为前者给出了精确变化的证据后者依赖LLM的主观推断。5.4 成本高到无法接受训练几万步LLM调用几千次这笔账很快会变得很难看。最有效的四个方案是降低采样频率、批量并发调用、用便宜的开源小模型、把LLM评估器蒸馏成一个小型MLP。蒸馏的具体做法是先用LLM给一批轨迹打分生成数据集再训练一个轻量回归模型来近似LLM的判断。这套流程落地后推理成本可以降到接近于零。5.5 注意LLM幻觉风险LLM会在某些情况下给出无依据的进展分数比如环境描述中存在它不理解的符号时。我的经验是在提示词里要求LLM输出简短理由是一种有效的护栏机制。强迫模型先进行推理再打分会显著降低幻觉概率。另外不要在高频调用场景里使用过长提示词上下文过长会降低模型的稳健性。当然最核心的原则是把LLM当作弱信号而不是强信号用多提示词投票或多次采样来综合判断。我个人在实际操作中的体会是进展奖励模型最适合的场景是那些真值奖励极度稀疏、但人类可以轻松判断“有没有变好”的任务。它相当于给智能体配了一个场外教练虽然这位教练偶尔会看走眼但至少能在黑暗中给出一个方向。如果你也想在自己的项目里试建议先做一个最小实验对比一下加了进展奖励前后的回报曲线。通常十几个episode就能看出它到底有没有用。