第 5 讲:多步推理与规划——树搜索、按需分解与"往宽还是往深"

Self-Improving AI Agents · Lecture 05。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应:Stanford CS329A Autumn 2025 Lecture 5(Mon 10/6,Multi-step Reasoning/Planning)。阅读材料:SWiRL: Synthetic Data Generation & Multi-Step RL for Reasoning & Tool Use(Goldie et al. 2025)、Language Agent Tree Search(LATS,Zhou et al. 2023)、SPRINT: Enabling Interleaved Planning and Parallelized Execution in Reasoning Models(2025)、ADaPT: As-Needed Decomposition and Planning with Language Models(Prasad et al. 2024)、Wider or Deeper? Scaling LLM Inference-Time Compute with Adaptive Branching Tree Search(AB-MCTS,Inoue et al. 2025)。幻灯片没有公开,本讲依据这五篇论文编写。 配套代码:code/lecture05/(只用 Python 标准库,每个文件 1 秒以内) 预计阅读时间:3 小时(含运行代码)


0. 本讲导航

0.1 学完本讲,你应该能够

  1. 说出多步任务难在哪里:错误累积、需要在多个可能的路径之间选择、任务复杂度超出单次调用的能力。
  2. 把”规划”理解为在部分解答的空间里搜索;说出 MCTS 的五个步骤(选择、扩展、评估、模拟、反向传播),以及 LATS 加上的两样东西:LM 的价值估计和反思。
  3. 解释树搜索为什么能比独立采样省预算(共享前缀),以及为什么预算很大时独立采样又会追上来(多样性)。
  4. 说出 ADaPT 的思想:做不了的时候才分解,分解的粒度自动适应 executor 的能力和任务的复杂度;和 plan-and-execute 的区别。
  5. 说出 AB-MCTS 的问题——每一步该”往宽走”(生成新候选)还是”往深走”(改进已有候选)——以及它用 Thompson 采样自适应地做这个决定的方法。
  6. 说出 SPRINT 怎样让 reasoning model 在推理中并行地执行独立的子任务,减少串行的 token 数。
  7. 说出 SWiRL 怎样用合成的多步轨迹做逐步的 RL;为什么”过程过滤”比”结果过滤”好,连最终答案错误的轨迹也有用。

0.2 先修知识

知识点用在哪里最低要求
第 1~4 讲全讲toy world、revise、PRM 的 step_prob、第 4 讲的 repair(排除错误值)、ReAct
树和递归第 2、3 节知道”树""父节点 / 子节点""递归函数”是什么
老虎机问题(bandit)第 4 节探索与利用的权衡;Thompson 采样的直觉(CS234 第 11 讲;CS329H 第 11、12 讲)
强化学习入门第 6 节状态、动作、奖励、策略梯度的直觉(第 6 讲会详细讲)

0.3 本讲地图

第1节  多步任务为什么难;规划 = 在部分解答的空间里搜索
第2节  LATS:把 MCTS、LM 价值估计和反思放在一起             ← 代码 01 演示 1
第3节  ADaPT:做不了的时候才分解                          ← 代码 02
第4节  AB-MCTS:往宽走还是往深走                          ← 代码 01 演示 2
第5节  SPRINT:在推理中并行地执行
第6节  SWiRL:用合成的多步轨迹做逐步的 RL
第7–10节 小结、练习、延伸阅读、下一讲预告

0.4 本讲的 toy world

继续使用第 1 讲的算术题和 ToyLLM(10B 生成器,temperature = 0.7)。几个约定:

  • 环境的反馈:有两种。一种只告诉你一份完整的解答”通过测试没有”(像代码的 unit test 或 HotpotQA 的标准答案);另一种给出部分分数:“从第一步开始连续做对了几步”(像”通过了多少个测试用例”),于是也就知道了第一个错误在哪里。
  • 预算按生成的步数计算(相当于 token 数):从头写一份 kk 步的解答花 kk,从第 ii 步续写花 k−ik - i。这样”共享前缀”省下的预算就能体现出来。
  • ADaPT 的 executor 用 direct 模式(不写中间步骤),一次调用能可靠完成的串行步数有限(第 1 讲第 3.3 节:1B 约 2 步,10B 约 3 步,100B 约 4 步)。这对应”任务太复杂,executor 一口气做不完”。

关于本讲的数字:论文里的数字注明出处;模拟实验的数字都来自 01、02 号代码的实际输出(固定随机种子,Python 3.9 与 3.13 逐字相同),说明的是机制,不代表真实模型。


1. 多步任务为什么难

1.1 三个困难

第 1 讲第 6.5 节的”可靠性的算术”已经说明了第一个困难:

  1. 错误累积:每步成功率 pp,nn 步全对的概率是 pnp^n。

此外还有两个:

  1. 分叉:很多任务在中途有多个可能的方向(先查 A 还是先查 B?用哪种算法?),选错了方向,后面做得再好也没用。走一步看一步(ReAct 那样的”贪心”决策)一旦走错,很难回头。
  2. 复杂度超出能力:有些子任务对模型来说”一口气做不完”(第 1 讲 direct 模式的串行上限),必须拆小。

1.2 规划 = 在部分解答的空间里搜索

经典 AI 里,规划(planning)是指在行动之前,在可能的动作序列里搜索一条能达到目标的路径。对 LLM agent 来说,可以把它理解为:

把”部分解答”(已经写了几步的推理、已经执行了几个动作的轨迹)看成状态,把”下一步写什么 / 做什么”看成动作,在这棵树上搜索。

这棵树的根是题目,每条从根到叶子的路径是一份完整的解答。第 2、3 讲的方法都可以放进这个框架:

  • 重复采样:从根出发,独立地走很多条完整的路径。
  • beam search(第 3 讲):一层一层地往下走,每层只保留分数最高的几个节点。
  • 顺序修改(第 2 讲):沿一条路径走到底,再回到某个位置改写。

本讲介绍更系统的搜索(LATS)、按需的分解(ADaPT)、自适应地分配”宽”和”深”(AB-MCTS),以及两个把规划和训练结合起来的方法(SPRINT、SWiRL)。


2. LATS:MCTS + LM 价值估计 + 反思

2.1 背景:MCTS

蒙特卡洛树搜索(Monte Carlo Tree Search,MCTS)是 AlphaGo 的核心。它在一棵搜索树上反复做四件事:

  1. 选择(selection):从根出发,按某个规则选子节点往下走,直到一个”还可以展开”的节点。规则要平衡两件事:去平均回报高的节点(利用),也去访问次数少的节点(探索)。常用的是 UCT:
UCT(c)=WcNc⏟平均回报+Cln⁡NparentNc\text{UCT}(c) = \underbrace{\frac{W_c}{N_c}}_{\text{平均回报}} + C \sqrt{\frac{\ln N_{\text{parent}}}{N_c}}

AlphaGo 用的变体 PUCT 还乘上一个先验 P(c)P(c)(神经网络认为这一步好的概率):WcNc+C⋅P(c)⋅Nparent1+Nc\frac{W_c}{N_c} + C \cdot P(c) \cdot \frac{\sqrt{N_{\text{parent}}}}{1 + N_c}。

  1. 扩展(expansion):在选中的节点上添加一个或几个子节点。
  2. 模拟(simulation,也叫 rollout):从新节点出发,快速地走到终点,看结果好不好。
  3. 反向传播(backpropagation):把结果沿路径往上更新每个节点的 NN 和 WW。

反复做很多轮之后,访问次数最多的那条路径就是搜索的结论。MCTS 的好处是把计算集中在有希望的分支上,同时保留一定的探索。

2.2 LATS 怎样把 MCTS 用在 LLM agent 上

LATS(Language Agent Tree Search,Zhou et al. 2023)把 MCTS 的每一步都换成了 LLM 能做的事:

MCTS 的步骤LATS 的做法
状态到目前为止的轨迹(问题 + 已经写的思考、动作、观察)
扩展让 LLM 从当前状态采样 nn 个可能的下一步(思考 + 动作)
评估让 LLM 给每个新状态打分(LM 价值函数),并结合 self-consistency 分数
模拟从选中的新状态继续执行到终点,从环境得到反馈(测试通过没有、答案对不对)
反向传播把回报沿路径更新
反思(新增)失败的轨迹交给 LLM 写一段自我反思(“上次失败是因为……”),存进记忆,作为之后生成时的上下文

两个关键的设计:

  • 价值函数由 LLM 自己提供,不需要训练(和第 3 讲的 self-evaluation 一样,它也有盲点)。
  • 环境的反馈 + 反思:把失败变成可以利用的信息,避免在同样的地方反复犯错。这一点继承自 Reflexion(Shinn et al. 2023)。

结果:LATS 在 HumanEval 上用 GPT-4 达到 pass@1 = 92.7%(当时的最好成绩),在 WebShop 上用 GPT-3.5 达到平均分 75.9——和需要梯度训练的方法相当,而 LATS 不需要任何训练。论文也在 HotpotQA 上验证了它。代价是成本:每道题要调用 LLM 很多次(扩展、评估、反思)。

2.3 toy world 里的 LATS

01_tree_search.py 演示 1 实现了一个简化版的 LATS(只有”通过 / 不通过”的反馈):从根沿 PUCT 下降到叶子;在叶子上让生成器写 3 次”下一步”,评估模型给每个新的一步打先验分数(第 3 讲的 step_prob);从先验最高的子节点续写到底,交给测试;失败的完整解答记进父节点的”记忆”,之后扩展时不再写这个值。

比较的对象:

  • 重复采样:一份一份地从头写。
  • Reflexion 式修改:不通过就让模型自己低温复查、修改(第 2 讲的 revise)。

预算内做对的比例(150 道 5~8 步题,每题跑 2 次):

预算(份)重复采样Reflexion 式修改LATS(先验 = 10B 自评)LATS(先验 = 100B)
20.5830.6930.6900.677
40.7670.8000.8200.830
80.8670.8970.9200.913
160.9500.9170.9400.940
  • 预算小到中等时,LATS 好于重复采样。 主要原因是共享前缀:树上已经写好的前缀不用重写,每次新的尝试只从分叉处开始,同样的预算能做更多次尝试;反思又让它不再重复已知失败的那一步。
  • 预算大时,重复采样追了上来并略微反超。 树把预算集中在少数分支附近,多样性不如独立采样。这和第 2 讲 Snell et al. 对 beam search 的发现一致:搜索在小预算下占优,大预算下 best-of-N 追上来。
  • 评估模型用 10B 自评还是 100B,这里几乎没有差别。 先验只决定”先试哪个子节点”,而每次扩展的 3 个候选里多半已经包含了正确的一步;真正起作用的是”失败了就换一个兄弟节点”。这和第 3 讲 beam search 的结果不同——那里 PRM 用来剪枝,评估模型的强弱就很关键。
  • Reflexion 式修改在小预算下很强(低温复查能修好手滑),但大预算下停滞:它修不了模型自己的误解。

编写时的一个教训:第一版 LATS 规定”一个节点要有 3 个不同的子节点才往下走”。但 toy 模型每一步的分布很集中,根节点很少能扩展出 3 个不同的值,算法一直停在根部,结果比重复采样还差。改成”一次扩展 3 个候选、从中选一个往下走”之后才正常。真实系统里,搜索的细节(什么时候往下走、扩展几个)对结果影响很大,同一个算法换一套超参数可能就从”有效”变成”无效”。


3. ADaPT:做不了的时候才分解

3.1 两种常见的 agent 结构

Prasad et al. 把当时的 LLM agent 分成两类:

  • iterative executor(迭代执行者):一步一步地决定下一个动作(例如 ReAct)。问题是任务一复杂,就容易迷失或做不完。
  • plan-and-execute(先规划再执行):先让 planner 把任务拆成子任务,再让 executor 依次执行。问题是计划是固定的:如果某个子任务对 executor 来说仍然太难,执行失败,整个任务就失败了,计划也不会调整。

两者的共同问题是:不知道该拆多细。拆得太粗,executor 做不了;拆得太细,浪费调用、还会在交接中引入错误。合适的粒度取决于 executor 的能力和任务的复杂度,而这两者事先都不知道。

3.2 ADaPT 的做法

ADaPT(As-needed Decomposition and Planning for complex Tasks)的想法很简单:

先让 executor 直接做;做不了,才分解。

ADaPT(任务, 深度):
    结果 = executor 直接做(任务)
    if 成功(结果) or 深度 == 最大深度:
        return 结果
    子任务们, 逻辑 = planner 分解(任务)       # 逻辑:AND(都要完成)或 OR(完成一个就行)
    对每个子任务:ADaPT(子任务, 深度 + 1)
    按逻辑组合子任务的结果
  • “成功”怎样判断:ALFWorld 这类环境会告诉你任务完成没有;论文也让 executor 自己生成判断成功的启发式。
  • 递归:子任务还做不了,就继续拆,直到 executor 能做为止(或者达到最大深度)。
  • 逻辑运算:planner 不只输出子任务列表,还说明它们怎样组合——AND(都要完成)或 OR(试一个,不行再试下一个)。

结果:在 ALFWorld、WebShop 和他们新提出的 TextCraft(按 Minecraft 的配方合成物品,天然需要多层分解)上,ADaPT 的成功率比强基线最多分别高出 28.3%、27% 和 33%。更重要的分析是:ADaPT 的分解深度会随 executor 的能力和任务的复杂度自动调整。

3.3 toy world 里的 ADaPT

02_adapt.py 的设定:任务是 kk 步算术链;executor 一次调用就要交出结果(direct 模式);planner 把任务对半拆(AND),有 2% 的概率拆错(漏掉一步);环境的成功信号有 2% 的误报和漏报。三种策略:

  • iterative executor:直接做整个任务,失败了重试,最多 3 次。
  • plan-and-execute:固定地拆成每块 2 步,每块最多尝试 2 次,任何一块失败整个任务就失败。
  • ADaPT:每个(子)任务先直接做(最多 2 次),还是失败才拆成两半,递归,最多 3 层。

成功率 / 平均 LLM 调用次数:

步数 kk1B:plan-and-execute1B:ADaPT10B:plan-and-execute10B:ADaPT100B:plan-and-execute100B:ADaPT
20.927 / 2.20.993 / 1.40.993 / 2.11.000 / 1.11.000 / 2.01.000 / 1.0
40.260 / 3.60.520 / 9.80.833 / 3.50.907 / 5.80.973 / 3.11.000 / 1.2
60.467 / 4.20.667 / 13.70.947 / 4.30.913 / 5.10.987 / 4.10.987 / 2.9
80.113 / 5.50.220 / 20.10.620 / 5.70.807 / 12.20.973 / 5.30.953 / 5.0
100.000 / 3.80.000 / 24.60.160 / 5.20.360 / 18.50.653 / 6.20.893 / 8.6

(iterative executor 一超过串行上限就接近 0:例如 100B 做 8 步时 0.027,见代码输出。)

ADaPT 的平均最大分解深度(同样的任务长度,executor 越弱拆得越深):

步数 kk1B10B100B
41.671.070.02
82.782.140.95
102.952.701.63
  • iterative executor:任务一超过 executor 的能力,重试也救不回来——不是运气不好,是任务太复杂。
  • plan-and-execute 的固定粒度对短任务够用,但计划不会调整;对强 executor 又是浪费:100B 做 4 步的任务,它要调用 3.1 次,ADaPT 只要 1.2 次。
  • ADaPT 简单的任务一次做完,难的任务才拆,拆到 executor 能做为止。多数情况下它的成功率明显更高(例如 10 步任务:10B 0.36 vs 0.16,100B 0.89 vs 0.65);强 executor 做中等长度的任务时两者相当。
  • 分解的粒度自动适应了 executor 的能力:同样做 4 步的任务,1B 平均拆到 1.67 层,100B 几乎不拆。
  • 代价:弱 executor 做长任务时,ADaPT 要调用很多次(不断地尝试、失败、再拆)。计算花在了需要的地方——和第 2 讲”按难度分配 test-time compute”是同一个思想。

编写时遇到的两个问题:(1) 最初按”最终数字对不对”判断成功,结果 1B 做 6 步题反而比 4 步题成功率高。原因是 direct 模式下 bug 很多,加法的 bug(少 10)和减法的 bug(多 10)互相抵消,“碰巧做对”大量出现。ALFWorld 这类环境检查的是真实的状态,不存在碰巧成功,所以改成按”过程是否真的做对”判断。(2) 最初 ADaPT 每个节点只试 1 次,而 plan-and-execute 每块试 2 次,比较不公平,ADaPT 反而更差;统一成 2 次后才是上表的结果。比较 agent 结构时,要确保它们的重试预算、成功判断方式是一致的。


4. AB-MCTS:往宽走还是往深走

4.1 问题

第 2 讲第 2.2 节提出过两种扩展计算的方向:

  • 往宽走(wider):生成新的候选——探索不同的解法。重复采样就是”只往宽”。
  • 往深走(deeper):拿一个已有的候选,根据反馈改进它——利用已有的进展。顺序修改就是”只往深”。

哪个更好?取决于任务和模型:

  • 如果反馈能精确地指出错误、而且修好这一处就能继续前进,往深走很划算。
  • 如果整个思路就是错的(例如选错了算法),在错误的思路上修修补补没用,必须重新采样一个新的思路——这时往宽走更好。

问题在于事先不知道是哪种情况。Inoue et al. 2025(Sakana AI)指出:重复采样很有效,但它不利用外部的反馈信号;标准的 MCTS 又用固定的分支数。他们提出 AB-MCTS(Adaptive Branching MCTS):在搜索树的每个节点上,自适应地决定是往宽走(新增一个子节点)还是往深走(在已有的子节点上继续改进)。

4.2 怎样自适应地决定?Thompson 采样

在每个节点上,“生成一个新的子节点”被当作一个特殊的动作(论文里叫 GEN 节点),和”选择一个已有的子节点继续深入”放在一起比较。每个选项的”好坏”用一个贝叶斯模型的后验分布来描述(根据它们之前带来的分数),然后用 Thompson 采样选择:从每个选项的后验里各抽一个数,选数值最大的那个。

Thompson 采样的直觉(CS329H 第 12 讲):

  • 一个选项过去表现好,它的后验集中在高处,被抽中的机会大——利用;
  • 一个选项尝试得少,它的后验很宽,偶尔会抽到很大的数——探索;
  • 随着证据积累,探索自动减少。

论文提出了两种贝叶斯建模方式(AB-MCTS-M 用混合模型、AB-MCTS-A 用节点聚合),在 LiveCodeBench、CodeContests、ARC-AGI、MLE-Bench 等代码和工程任务上,用前沿模型做实验,AB-MCTS 稳定地胜过重复采样和标准的 MCTS。核心结论是:要把 LLM 回答的多样性(宽)和多轮的改进(深)结合起来。

4.3 toy world 里的”往宽还是往深”

01_tree_search.py 演示 2 用的是部分分数的反馈(“从第一步开始连续做对了几步”):

  • 往宽:从头采样一份新的解答(花 kk 步)。
  • 往深:拿当前最好的解答,在第一个错误的那一步排除错误值重算,往后续写(第 4 讲的 repair,花 k−ik - i 步)。
  • 自适应:为两个动作各维护一个 Beta 分布,记录”这个动作有没有带来更好的分数”,用 Thompson 采样决定每一次做哪个(只在根部决策,是 AB-MCTS 的简化)。

预算 = 4 份完整解答:

题目只往宽只往深交替自适应(Thompson)
3~4 步0.9030.9870.9330.943
5~6 步0.8300.9630.8800.893
7~9 步0.6370.9370.7970.803

7~9 步的题,不同预算下:

预算(份)只往宽只往深交替自适应
40.6200.9130.7800.800
80.8000.9800.9200.920
160.8871.0000.9931.000

结果和预想的不一样:在这个 toy world 里,往深走在每种题长、每种预算下都是最好的,自适应策略落在两者之间,随预算增大逐渐逼近往深走。

  • 为什么往深走总是赢? 因为反馈精确地指出了第一个错误,“排除错误值”又让模型跳出了自己的误解(第 4 讲 RLEF 的机制),而且修好这一步就能继续前进。只往宽每次从头写,前面做对的部分全部浪费,题目越长越吃亏。
  • 为什么自适应策略没有达到往深走的水平? 它不知道往深走更好,要从”哪个动作带来了进步”里慢慢学。预算小时只能做几次决策,试错的代价占比很大。
  • 这个 toy world 缺了什么? 它没有”整个思路错了”的情况:每一步都可以单独修好。真实的代码、工程任务里,“思路错了、必须重来”很常见,而哪种情况更多事先不知道。AB-MCTS 的价值正在于”不需要事先知道”——在这个 toy world 里体现不出这一面,但它的代价(试错的开销)体现出来了。

这个结果提醒我们:自适应的方法买的是”稳健”——在不知道哪种策略更好时,不至于选错;代价是在”某种策略明显更好”的环境里,它比那个最好的固定策略差一点。


5. SPRINT:在推理中并行地执行

5.1 问题:长 CoT 太慢

reasoning model(o1、R1)的长 CoT 是串行的:一个 token 接一个 token 地生成。一道难题可能要写上万个 token,用户要等很久。但很多推理过程里其实有互相独立的子任务:例如”分别计算这三种情况的概率""分别验证这四个候选答案”。它们可以同时做。

5.2 做法

SPRINT 是一个”后训练 + 推理”的框架,让 reasoning model 学会在推理过程中动态地识别可以并行的部分:

  1. 数据整理:把已有的长推理轨迹重新组织成若干”轮”,每一轮由一个规划(这一轮要做哪几件独立的事)和若干个并行执行的子任务组成。
  2. 微调:用少量这样整理过的数据微调 reasoning model。
  3. 推理:模型写出一个规划后,几个子任务同时生成,结果汇总后再进入下一轮规划。

5.3 结果

在数学等复杂任务上,用 SPRINT 微调的模型和原来的 reasoning model 准确率相当,但在需要超过 8000 个输出 token 的问题上,串行 token 数最多减少 39%;迁移到 GPQA 和 Countdown 这两个分布外的任务上,长推理轨迹的平均串行 token 数分别最多减少 45% 和 65%。

5.4 意义

SPRINT 把第 2 讲”并行 vs 顺序”的维度带进了单个回答的内部:reasoning model 的 test-time compute 不一定要完全串行。从规划的角度看,它要求模型先想清楚”哪些事互相独立”——这正是规划的核心能力。


6. SWiRL:用合成的多步轨迹做逐步的 RL

6.1 问题:RLHF 把问题当成”单步”

RLHF、RLAIF 都把一次回答当作一个整体打分(单步)。但 agent 的任务是多步的:多次推理、多次调用工具、多次读取结果,才得到最终答案。只在最后打一个分数,模型很难知道是哪一步做得好、哪一步做得差(第 3 讲的 credit assignment 问题)。而且多步、带工具的高质量训练数据很少。

6.2 做法

SWiRL(Step-Wise Reinforcement Learning,Goldie et al. 2025,作者包括讲师 Azalia Mirhoseini 和 Christopher Manning)分两部分:

合成数据:

  1. 让 Gemma 2 27B 带上工具(搜索引擎、计算器),对一批问题生成多步轨迹:每一步写推理,然后调用工具或给出最终答案;工具的结果放回上下文,进入下一步。
  2. 逐步分解:一条有 kk 个动作的轨迹,拆成 kk 个子轨迹,每个子轨迹是”从开头到第 jj 个动作”的上下文 + 第 jj 个动作。
  3. 过滤:比较了四种:不过滤;过程过滤(每一步都被一个模型判断为合理的轨迹才保留);结果过滤(只保留最终答案正确的);两者都要。

逐步的 RL:对每个子轨迹,用一个生成式的 reward model(Gemini 1.5 Pro)判断”在这个上下文下,这一步做得好不好”,优化”逐步奖励之和”的期望。这不需要标准答案。

6.3 主要发现

  • 过程过滤最好,好于结果过滤,也好于两者都要——即使保留了最终答案错误的轨迹。论文的说法是:SWiRL 可以从最终答案错误的轨迹中学习。
  • 在 GSM8K、HotPotQA、CofCA、MuSiQue、BeerQA 上,相对准确率分别提高了 21.5%、12.3%、14.8%、11.1% 和 15.3%。
  • 跨任务的泛化:只在 HotPotQA(文本问答)上训练,在 GSM8K(数学)上的零样本表现相对提高了 16.9%。模型学到的似乎是一般的”多步推理 + 使用工具”的能力,而不只是某个任务的知识。

6.4 为什么”过程过滤”比”结果过滤”好?

这和第 3 讲的结论一脉相承:

  • 结果过滤会丢掉有价值的步骤:一条轨迹最后答错了,前面几步可能都很好(查对了资料、拆对了问题)。只看结果,这些好的步骤也被扔掉了。
  • 结果过滤会保留”蒙对”的轨迹:最后答对了,中间可能有错误的步骤(第 3 讲演示 2:弱模型答对的解答有 10% 推理有错)。
  • 逐步的奖励更精确:每一步单独打分,好的步骤被奖励,坏的步骤被惩罚,不会因为”最后答对了”就把坏步骤也奖励了。

这也是第 3 讲 Math-Shepherd 的 SE 标签、第 6 讲 RL 里”advantage”的共同思想:评价一个动作,要看它本身带来了什么,而不是只看整条轨迹的结局。


7. 小结

  1. 多步任务的三个困难:错误累积、分叉(选错方向难回头)、复杂度超出单次调用的能力。规划 = 在部分解答的空间里搜索。
  2. LATS:把 MCTS 用在 LLM agent 上——LLM 负责扩展、价值估计和反思,环境负责最终的反馈。HumanEval 上 GPT-4 达到 92.7%。toy world 显示:共享前缀让树搜索在小预算下胜过独立采样,但预算大时独立采样的多样性又追了上来(和 Snell et al. 对 beam search 的发现一致);搜索的细节对结果影响很大。
  3. ADaPT:做不了的时候才分解。分解的粒度自动适应 executor 的能力和任务的复杂度:强 executor 少拆、弱 executor 多拆。比固定的 plan-and-execute 更稳,也把计算花在需要的地方。比较 agent 结构时要统一重试预算和成功判断。
  4. AB-MCTS:在每个节点上用 Thompson 采样自适应地决定”往宽走”还是”往深走”,把多样性和多轮改进结合起来,在代码和工程任务上稳定地胜过重复采样和标准 MCTS。toy world 里反馈太精确,往深走总是最好;自适应策略买的是”不知道哪种更好时的稳健”,代价是试错的开销。
  5. SPRINT:让 reasoning model 在推理中规划并并行执行独立的子任务,准确率不变,长推理的串行 token 最多减少 39%(数学)、45%(GPQA)和 65%(Countdown)。
  6. SWiRL:合成多步、带工具的轨迹,逐步分解,用过程过滤和逐步的生成式奖励做 RL。过程过滤好于结果过滤,连最终答案错误的轨迹也有用;在 HotPotQA 上训练能迁移到 GSM8K。

8. 练习

1. UCT 和 PUCT(第 2.1 节) 一个节点访问了 100 次,有三个子节点:A 访问 60 次、平均回报 0.5;B 访问 30 次、平均回报 0.6;C 访问 10 次、平均回报 0.3。设 C=1C = 1。 (a) 用 UCT 算每个子节点的分数,下一次选哪个? (b) 如果 C 的先验 P=0.6P = 0.6,A、B 的先验都是 0.2,用 PUCT(WN+C⋅P⋅Nparent1+Nc\frac{W}{N} + C \cdot P \cdot \frac{\sqrt{N_{\text{parent}}}}{1+N_c})呢?

参考答案

(a) ln⁡100≈2.146\sqrt{\ln 100} \approx 2.146。A:0.5+2.146/60≈0.7770.5 + 2.146/\sqrt{60} \approx 0.777;B:0.6+2.146/30≈0.9920.6 + 2.146/\sqrt{30} \approx 0.992;C:0.3+2.146/10≈0.9790.3 + 2.146/\sqrt{10} \approx 0.979。选 B(C 很接近)。 (b) A:0.5+0.2×10/61≈0.5330.5 + 0.2 \times 10/61 \approx 0.533;B:0.6+0.2×10/31≈0.6650.6 + 0.2 \times 10/31 \approx 0.665;C:0.3+0.6×10/11≈0.8450.3 + 0.6 \times 10/11 \approx 0.845。选 C:先验高、访问少的节点得到更多探索。

2. 共享前缀省了多少(第 2.3 节) 一道 8 步的题。重复采样每次花 8 步。LATS 的一次迭代:在深度 dd 的叶子上扩展 3 个候选(花 3 步),再从深度 d+1d+1 续写到底(花 8−d−18 - d - 1 步)。 (a) d=0,3,6d = 0, 3, 6 时,一次迭代各花多少步? (b) 在什么深度以下,LATS 的一次迭代比重复采样的一次还贵?这说明了什么?

参考答案

(a) d=0d = 0:3+7=103 + 7 = 10;d=3d = 3:3+4=73 + 4 = 7;d=6d = 6:3+1=43 + 1 = 4。 (b) 3+8−d−1>8  ⟺  d<23 + 8 - d - 1 > 8 \iff d < 2。树还很浅的时候,扩展的开销让 LATS 比重复采样还贵;只有当树长深了,共享前缀才开始省钱。所以树搜索在”每道题只给很少预算”时未必划算,在中等预算时最划算。

3. ADaPT 的递归(第 3.2、3.3 节) 一个 executor 一次能可靠完成 3 步。用 ADaPT(对半拆)处理一个 10 步的任务,假设”超过 3 步一定失败、3 步以内一定成功”。 (a) 画出分解树。一共调用 executor 多少次?planner 多少次? (b) 如果一开始就固定地拆成每块 2 步(plan-and-execute),调用多少次? (c) 如果 executor 一次能做 5 步呢?

参考答案

(a) 10 → 失败,拆成 5 + 5;5 → 失败,拆成 2 + 3;2、3 都成功。executor:1(10)+ 2(两个 5)+ 4(2、3、2、3)= 7 次;planner:1 + 2 = 3 次。 (b) planner 1 次,executor 5 次(5 块),共 6 次——这里固定计划更省,但前提是”2 步一定能做”;如果 executor 一次只能做 1 步,固定计划就会失败。 (c) 10 → 失败,拆成 5 + 5,都成功。executor 3 次,planner 1 次。固定计划仍然是 6 次。executor 越强,ADaPT 越省。

4. Thompson 采样(第 4.2 节) 往宽走成功(带来进步)了 2 次、失败 5 次;往深走成功 4 次、失败 1 次。用 Beta(成功 + 1, 失败 + 1) 描述两个动作。 (a) 两个 Beta 分布的均值各是多少? (b) 为什么 Thompson 采样仍然会偶尔选择往宽走?这有什么好处? (c) 在第 4.3 节的 toy world 里,自适应策略在预算小时明显不如”只往深”。如果你事先知道”反馈能精确地指出错误”,你会怎样设置 Beta 分布的先验?

参考答案

(a) 往宽:Beta(3, 6),均值 3/9≈0.333/9 \approx 0.33;往深:Beta(5, 2),均值 5/7≈0.715/7 \approx 0.71。 (b) Beta(3, 6) 有一定的宽度,偶尔会抽到比 Beta(5, 2) 的抽样更大的数。好处是:如果往宽走其实没那么差(只是早期运气不好),还有机会被重新发现;任务的性质在搜索过程中也可能变化(例如修到后面,剩下的错误修不动了)。 (c) 给往深走一个乐观的先验,例如 Beta(5, 1),给往宽走 Beta(1, 2)。先验相当于”事先的经验”,能减少早期的试错。

5. SWiRL 的过滤(第 6.3、6.4 节) (a) 为什么”过程过滤 + 结果过滤”反而不如只用过程过滤? (b) 只用过程过滤时,保留下来的、最终答案错误的轨迹里,有哪些东西值得学?举一个多跳问答的例子。 (c) 过程过滤依赖一个”判断每一步是否合理”的模型。如果这个模型有偏差(例如偏爱调用搜索),SWiRL 会学到什么?

6. 动手改代码 (a) 在 01 号文件里把 LATS 的 n_expand 改成 1 和 5,结果怎样变化?为什么 n_expand = 1 会卡住? (b) 在 01 号文件演示 2 里,让”往深走”不排除错误值(只是从错误的那一步重新采样)。往深走还会总是赢吗? (c) 在 02 号文件里把 ENV_FPR 改回 0.05,ADaPT 和 plan-and-execute 谁受影响更大?为什么? (d) 在 02 号文件里给 planner 加上”三等分”的选项(当任务长度 ≥ 6 时拆成三块)。分解树会变浅吗?调用次数呢?

7. 设计题 你要为一个”根据需求文档实现一个小网站”的 coding agent 选择搜索策略。可用的反馈有:编译是否通过、单元测试通过了几个、一个 LLM judge 对界面截图的评分。你会怎样组合 LATS、ADaPT、AB-MCTS 的思想?什么时候往宽、什么时候往深、什么时候分解?


9. 延伸阅读

本讲的阅读材料

  • Zhou et al. 2023. Language Agent Tree Search Unifies Reasoning, Acting, and Planning in Language Models.(LATS)
  • Prasad et al. 2024. ADaPT: As-Needed Decomposition and Planning with Language Models.
  • Inoue et al. 2025. Wider or Deeper? Scaling LLM Inference-Time Compute with Adaptive Branching Tree Search.(AB-MCTS)
  • SPRINT: Enabling Interleaved Planning and Parallelized Execution in Reasoning Models.(2025)
  • Goldie et al. 2025. Synthetic Data Generation & Multi-Step RL for Reasoning & Tool Use.(SWiRL)

相关工作

  • Yao et al. 2023. Tree of Thoughts: Deliberate Problem Solving with Large Language Models.(把推理组织成树,用 BFS / DFS 搜索)
  • Hao et al. 2023. Reasoning with Language Model is Planning with World Model.(RAP:LLM 同时当世界模型和策略,用 MCTS 规划)
  • Shinn et al. 2023. Reflexion: Language Agents with Verbal Reinforcement Learning.
  • Silver et al. 2016 / 2017. Mastering the game of Go with deep neural networks and tree search / Mastering the game of Go without human knowledge.(AlphaGo、AlphaGo Zero 的 MCTS)
  • 同目录 CS224V 第 3 讲(计算思维引擎与递归分解)、CS329H 第 11、12 讲(老虎机与 Thompson 采样)。

10. 下一讲预告

第 6 讲:训练时扩展——用强化学习扩展推理

本讲的搜索都是在 test-time 进行的,每道题都要重新搜一遍。能不能把搜索得到的好经验训练进模型,让它以后一次就做对?第 6 讲讨论:

  • STaR:用自己生成并答对的推理来训练自己;做不对的题,给出答案提示后再生成推理(rationalization)。
  • GRPO(DeepSeekMath):不需要价值网络的策略梯度——用同一道题的一组回答互相比较。
  • DAPO:大规模 RL 训练中的四个关键技巧:clip-higher、动态采样、token 级的 loss、超长回答的奖励整形。
  • 一个持续的争论:RL 是让模型学会了新的推理能力,还是只是把 pass@k 变成了 pass@1?
← 返回课程目录