clamp 的读取、编辑、测试和提交流程,最后由隐藏测试打分。要让模型学会这种行为,我们先得把问题说清楚:哪些选择由智能体控制?它能看到什么?哪些结果是随机的?一次操作的作用到几轮之后才显现,又该怎样评价?本章用强化学习的基本定义回答这些问题。
我们用一个修复 MDP(repair MDP)来具体解释这些定义:把 clamp 回合抽象为七个状态,再用几行 PyTorch 表示状态、动作、转移和奖励。由于这个 MDP 很小,我们可以用一次线性求解精确地计算价值,用采样来核对它们,找到最优策略,并用自动求导对目标求导。换成语言模型后,状态和动作多到无法枚举,这些精确计算就行不通了。理解这个限制,才能看懂第 6 章为何要改用采样估计梯度。
我们为全书其余部分保存两个函数 discounted_return 和 policy_evaluation,外加修复 MDP 的构建函数和 value_iteration,后续章节把它们用作精确参照。
2.1 马尔可夫决策过程
一个强化学习问题由两部分组成:选择动作(action)的智能体(agent),以及做出响应的环境(environment)。二者之间的接口是一个循环。在每一步 ,环境处于状态(state),智能体选择动作 ,环境返回奖励(reward) 和下一个状态 。当环境到达一个终止状态时,循环结束。 马尔可夫决策过程(Markov decision process,MDP)把这个循环形式化为一个元组 :- 是状态集合, 是动作集合。
- 是在 中采取 后转移到 的转移概率。
- 是在 中采取 的期望即时奖励。
- 是初始状态的分布。
- 是折扣因子(discount factor,见 2.4 节)。
修复 MDP
我们把clamp 回合抽象为七个状态。智能体从文件 unread 开始。读取后进入 read。编辑会产生 edited_ok 或 edited_bad,而编辑正确的概率取决于智能体是否掌握了信息:在读取文件之后、或在看到失败测试之后所做的编辑,成功概率为 0.8;其他任何编辑都是猜测,成功概率为 0.3。测试一个已编辑的文件会使其进入 passed 或 failed。提交会以 done 结束回合,如果文件正确则支付奖励 1,否则为 0。所有数字都是为教学而虚构的,并非在任何模型上测得。
repair_transitions 就是上面文字描述的规格:读取只有一次有用,测试只会改变已编辑的文件,每次编辑都是一次全新的随机抽取。在其他状态下读取或测试会使状态保持不变,这是一个耗费一步的自环。
表格型 MDP 把 存为形状为 [S, A, S] 的张量,把 存为 [S, A]。我们根据规格填充这两者。终止状态 done 在 中对应一个全零行:到达它的回合直接停止。这使 成为次随机(substochastic)矩阵(非终止状态的行和为 1,终止状态的行和为 0),这一约定让我们无需对终止做特殊处理就能求解价值。
submit 动作上。可选的 step_cost 对每个动作收费;2.9 节会用到它。我们来检查这些张量。
submit 列中 edited_ok 和 passed 对应的位置。图 2.1 画出了同样的张量。
unread 出发,一次猜测只有 30% 的概率进入 edited_ok。从 read 或 failed 出发,有信息的编辑以 80% 的概率成功。test 箭头并不改变文件是否正确;它们只是把智能体移到一个报告正确与否的状态。在这里的完全可观测情形下,报告智能体已经知道的事情没有任何价值。2.7 节表明,一旦智能体看不到状态,它就会获得价值。
2.2 策略、轨迹与回报
策略(policy) 是每个状态上关于动作的分布。在表格型 MDP 中,它是一个各行之和为 1 的张量policy: [S, A]。确定性策略在每个状态上只选择一个动作,其概率为 1。对语言模型而言,策略就是模型本身: 是模型在给定上下文时输出动作 的概率。
策略与 MDP 共同定义了一个关于轨迹(trajectory) 的分布:
这个分解把智能体控制的部分()与它不控制的部分( 和 )分开了。正是这种分离使策略梯度无需环境模型就能工作:第 6 章对 求导, 因子因为不依赖于 而消失。
一条轨迹的回报(return)是其奖励的折扣和,
而强化学习的目标是从初始分布出发的期望回报,。对参数化策略,我们写作 。计算回报是我们保存的第一个函数。
policy[s] 中抽取动作、从 P[s, a] 中抽取下一个状态来展开一个回合(episode),直到到达终止行。
deterministic_policy 把每个状态一个动作名的列表转换为一个独热(one-hot)的 [S, A] 张量。我们定义三个在整章中都会用到的策略:
- careful(谨慎):读取、编辑、测试,测试通过后提交,失败后重新编辑;
- read-edit-submit(读取-编辑-提交):读取、编辑一次,不测试就提交;
- blind(盲目):立即编辑并提交。
2.3 价值函数与贝尔曼方程
单个回合的回报是有噪声的。状态价值函数(state-value function)把噪声平均掉: 而动作价值函数(action-value function)还额外以第一个动作为条件: 把回报拆分为第一个奖励和其余部分。从 开始的其余部分是同一类型的回报,因此它的条件期望是 。这就得到贝尔曼期望方程(Bellman expectation equations): 把第一个方程代入第二个方程,消去 : 这是一个含 个未知数的线性方程组,。只要 可逆,它就有唯一解。对任意 这都成立,因为 是次随机的,其谱半径至多为 1。对 ,当且仅当策略从每个状态出发都以概率 1 到达终止状态(即保证最终终止的 proper policy)时它才成立。求解这个方程组就是精确策略评估(exact policy evaluation),也是我们保存的第二个函数。einsum 和求和这两行就是 和 的定义;求解就是贝尔曼方程。与蒙特卡洛结果比较一下。
read, edit, test, submit。careful 策略所采取动作的优势按定义恰好为 0。其他条目则很有信息量。在 edited_ok 中,提交的优势为 :文件已经修好,careful 却还要先测试。多等一步使最终奖励被折扣一次,损失恰好是奖励的 倍。在 edited_bad 中,提交的优势为 ,因为它丢掉了该状态的全部价值。一个依据这些数字行动的策略会在 edited_ok 中提交,在 edited_bad 中继续测试,因为在那里 test 的动作价值最高。这就是 2.5 节的策略改进步骤。最后一行在机器精度下验证了贝尔曼方程。
陷阱。 当 接近 1 时, 接近奇异,float32 下的 torch.linalg.solve 可能出现明显的漂移。修复 MDP 全程使用 float64。在大规模训练中,只要以低精度累加长时程回报或对数概率之和,就会出现同样的问题。
2.4 折扣
折扣因子扮演着两种不同的角色,把二者混为一谈是常见的困惑来源。- 一种建模选择。 表示 步之后的奖励只值当前同样奖励的 。几何折扣等价于一个在每一步都以概率 独立终止的回合,因此它的有效时间跨度约为 步。
- 一种数学上的便利。 保证 可逆,并保证即使对永不终止的策略,回报也是有界的。
submit 结束,或在轮数预算耗尽时结束。我们关心的是它是否成功,而在第 5 轮而不是第 3 轮找到的等价修复,对用户来说价值并不更低。这支持用 作为任务的模型。但折扣会改变哪个策略更受青睐。在一系列 下评估这三个策略。
2.5 最优策略,以及为什么我们不去计算它
评估告诉我们一个策略有多好。改进让它变得更好。策略改进定理指出:如果 相对于 是贪心的,即 ,那么对每个状态都有 。证明很简短。贪心性给出 ;在 下把贝尔曼方程一步一步展开,并在每一步应用同样的不等式即可。 交替进行评估和改进会收敛到一个最优策略 ,其价值满足贝尔曼最优方程: 价值迭代(value iteration)把右端作为更新反复应用,直到它不再变化。对 ,该更新在最大范数下是一个压缩映射,因此从任何起点出发都会收敛。edited_ok 中立即提交,在 edited_bad 中测试。测试一个已知有误的文件是有用的,因为它会通向 failed,而从这个状态出发,有信息的编辑有 80% 的成功率,而不是在 edited_bad 中做一次 30% 的猜测。并且它从不测试一个正确的文件,因为它能看到文件是正确的。careful 与最优策略之间的差距,就是在答案已知时仍然去测试的代价。
为什么这无法扩展到语言模型
价值迭代需要一张每个状态一个条目的表,以及对所有动作的遍历。对于 2.8 节 token 级建模下的语言模型,一个状态是一个 token 前缀,一个动作是一个 token。数一数它们。policy_evaluation 是可微的:它只是一个 einsum 和一次线性求解。
2.6 老虎机:单步情形
老虎机(bandit)是回合只持续一步的 MDP。没有下一个状态,因此 ,唯一的问题是哪个动作的期望奖励最高。上下文老虎机(contextual bandit)在开始时额外抽取一个上下文 :。 单轮 RLVR 就是一个上下文老虎机。上下文是提示,动作是整个回答,奖励是验证器对该回答的评分。回答是逐 token 生成的,但环境在 token 之间不做反应,若验证器是确定性的,除策略采样外,随机性就只来自提示。GRPO 等方法把每个提示当作一个小型老虎机问题:采样 个回答,观察 个奖励,再提高高奖励回答的概率(第 9 章)。 老虎机把表格型 MDP 所掩盖的问题单独拎了出来:探索(exploration)。一个动作的价值在尝试之前是未知的,而一个不再尝试某个动作的策略永远无法得知它其实是好的。比较一个贪心学习器(总是选择估计均值最高的臂)和 epsilon-贪心学习器(以概率 随机选一个臂)。我们并行运行 2,000 个独立副本。2.7 部分可观测
到目前为止,智能体能看到状态。真实的编程智能体看不到。它看到的是问题描述、工具的输出以及它自己的消息。它看不到将要为它评分的隐藏测试,看不到它没有读过的那部分仓库,也看不到它的编辑是否正确。部分可观测 MDP(partially observable MDP,POMDP)增加了一个观测函数 :环境的状态像在 MDP 中一样演化,但智能体只接收到一个观测(observation)。 POMDP 中的智能体应当以它的完整历史 为条件,或者以信念(belief) 为条件,后者是历史的充分统计量。一个只把当前观测映射到动作的策略可能严格次优。对语言模型而言,上下文窗口就是历史:模型以之前的每一条消息和工具输出为条件。这是一个优势,也正因如此,上下文截断(2.9 节)是一种建模上的改变,而不仅仅是一个工程细节。 在修复 MDP 中,让edited_ok 和 edited_bad 看起来完全相同:编辑之后,智能体只能看到 edited。其他每个状态都按其本身被观测。
edited 在两个隐藏状态中必须导向同一个动作。编辑后盲目提交的价值为 0.65;先测试的价值为 0.775。在部分可观测条件下,测试是更好的选择,因为测试的输出揭示了隐藏变量。完全可观测下的最优值 0.825 还要更高。0.825 与 0.775 之差,就是智能体无法直接观测、必须花一步去获取的那部分信息的价值。
同样的结构也出现在实际的大规模任务中。读取文件、运行测试和搜索仓库都是信息收集动作。它们本身不获得奖励,它们的价值之所以存在,只是因为智能体只能部分地观测它的世界。仅基于结果的奖励必须教会智能体去采取这些动作,而这是一个回报归因(credit assignment)问题(第 7 章、第 12 章)。隐藏测试按设计也永远不会被观测到。正是这一点使它们成为智能体无法直接拟合的奖励(第 11 章)。
2.8 把 LLM 智能体建模为 MDP 的三种方式
语言模型智能体可以用不止一种方式纳入 MDP 框架,而这一选择决定了代码中的“动作”“步”和“优势”分别指什么。取第 1 章中一个脚本化的回合,把它写成带归属的片段。<call> edit swap_minmax </call>,状态是到目前为止的对话。其概率是各 token 概率的乘积。时间跨度缩短为轮数,这是回报归因的自然尺度:轮级优势表达的是“这次工具调用是好的”。代价是一个组合爆炸式的巨大动作空间,以及一个由许多逐 token 比率相乘得到的比率 ,它可能会爆炸(第 8 章)。
回合级。 整条轨迹是一个动作,问题变成一个关于轨迹的上下文老虎机,任务是上下文,最终奖励是收益。这是 GRPO 类结果强化学习中隐含的建模方式(第 9 章):一条轨迹中的每个策略 token 都获得相同的轨迹级优势。它换来的是简单,并且不需要价值函数。代价是放弃了回合内部的全部回报归因:一次无用的 read 和决定性的 edit 得到相同的信号。
这些并不是相互竞争的理论。它们是对同一采样过程的三种视角,实际系统会混合使用它们。一种常见的组合是:在 token 级计算对数概率,在回合级计算优势,在轮级施加掩码。
2.9 实践中的设计问题
问题:为有限长度的编程回合选择折扣。 现象: 当 时,智能体学会跳过验证步骤。当 时,critic 的价值估计发散,或者一个永远循环的策略的价值没有定义。 原因: 使较晚的成功价值更低,从而改变最优策略(图 2.2 中的交叉)。 时,对任何能够避免终止的策略, 都是奇异的。 可选方案: (a) ,配合强制终止的硬性轮数或 token 预算;这与任务的成功标准相符,但预算成为环境的一部分,而被截断的回合需要一条处理规则(第 12 章)。(b) 让 略低于 1,以偏向短回合为代价保持价值有界。(c) 显式的每步代价(见下一个问题),以奖励单位而不是通过折扣来表达紧迫性。 建议做法: 本书使用 加上轮数预算,并把任何紧迫性都作为显式的、经过测量的代价来处理。这是一条建议,而不是普适规则。奇异的情形很容易复现。一个永远在读取的策略永不终止。
问题:终局奖励与每步代价。 现象: 为了抑制过长的回合而加入每步惩罚之后,智能体开始不做测试就提交,或者不做任何编辑就立即提交。 原因: 每步代价 会从每个策略的价值中减去 乘以期望回合长度,长度不同的策略损失的量也不同。超过某个阈值后,一个更短、更不可靠的策略会成为最优;在更高的阈值上,放弃会成为最优。 可选方案: (a) 只使用终局奖励,配合预算,这对成功率而言是无偏的,但不产生任何提高效率的压力。(b) 一个较小的每步代价,设定在远低于使最优策略发生改变的阈值处。(c) 单独报告代价,并在评测时按代价在成功的策略之间进行选择。 建议做法: 在训练早期只使用终局奖励;只有当效率重要时,才加入一个较小的每步代价,并且要先确认它不会在有代表性的任务上改变最优策略。
unread 直接 submit:智能体立即放弃。放弃只花费一个动作,因此一旦 ,即 ,它就成为最优,此时尝试修复的期望代价超过了其奖励 1。在 LLM 训练中,这就是第 12 章中“智能体学会立即提交”的病态现象,在这里用一张七状态的表格复现了出来。
问题:前缀是马尔可夫状态吗? 现象: 相同的可见上下文导致不同的结果,价值估计出现难以解释的波动,或者在一次上下文管理方面的改动之后行为发生了变化。 原因: 只有当 token 前缀包含了决定未来观测和奖励的全部信息时,它对智能体的决策过程而言才是马尔可夫的。有三种情况会破坏这一点。环境有隐藏状态,例如文件系统、隐藏测试和随机种子。上下文可能被截断或摘要,从而丢弃策略本可以利用的历史。状态抽象可能把未来不同的历史合并在一起;在修复 MDP 中,通过猜测到达的edited_bad和通过有信息的编辑到达的edited_bad之所以是同一个状态,只是因为我们声明了编辑不会记住自己是如何做出的。 可选方案: (a) 在上下文中保留完整历史,这在长时程下代价高昂;(b) 使用显式且忠实的状态摘要,例如让工具报告当前的 diff,使截断损失更少的信息;(c) 把问题当作 POMDP 处理,并接受价值只以可观测的历史为条件。 建议做法: 把智能体视为一个以完整上下文为条件的 POMDP 策略;让工具输出显式报告相关状态;并把截断或摘要方式的任何改动都视为策略输入分布的改变,需要重新评估。
小结
- MDP 把智能体控制的部分 与它不控制的部分 和 分开;轨迹分布按这些部分分解,这就是策略梯度不需要环境模型的原因。
- 价值函数满足线性的贝尔曼期望方程。对表格型 MDP,
policy_evaluation精确地求解它们,结果在误差棒之内与蒙特卡洛估计一致。 - 折扣和每步代价都不是中性的缩放:二者都可能改变哪个策略是最优的。对有限长度的编程回合,本书使用 加轮数预算。
- 价值迭代只有在状态和动作可以枚举时才能找到最优策略。语言模型做不到这一点,因此我们通过对 做梯度上升来优化参数化策略,在修复 MDP 上这仍然可以用自动求导精确完成。
- 单轮 RLVR 是一个上下文老虎机,探索受限于策略自身的采样分布。真实的编程智能体是部分可观测的,这正是信息收集动作具有价值的原因。
- LLM 智能体可以建模为 token 级、轮级或回合级的决策过程。实际系统按 token 计算对数概率,按回合或按轮计算优势,并按轮施加掩码。
练习
- 证明当 是次随机矩阵时,对任意 , 都可逆。(提示:用最大行和来界定谱半径。)然后构造一个在 时奇异的双状态例子。
- 把有信息编辑的成功概率从 0.8 改为 0.5。重新计算 2.4 节的价值表。careful 与 read-edit-submit 之间的交叉点会移到更高还是更低的 ?在运行代码之前先解释原因。
- 修改
make_repair_mdp,使在edited_ok上的test以 0.1 的概率失败(一个不稳定测试)。 和最优策略如何变化?这对针对不稳定验证器的训练有什么预示(第 11 章)? - 在 2.5 节中,把精确的 替换为由
mc_value计算的、每步 16 个采样回合的蒙特卡洛估计。为什么你不能再对它调用backward()?缺少了什么?(这正是第 6 章要回答的问题。) - 为
run_bandit扩展一个上置信界规则:选择 。将它与 的 -贪心进行比较。 - 扩充修复 MDP 的状态,使其记住智能体是否读过文件,并使从任何状态出发的编辑当且仅当文件已被读过时以 0.8 的概率成功。你需要多少个状态?哪个策略是最优的?
- 设计评审:你的团队提议对每次
test调用给予 的奖励,理由是“测试越多的智能体成功率越高”。利用 2.7 节和每步代价的结果,论证智能体会学到什么,并提出一种更好的方式来鼓励有用的测试。