对应: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 学完本讲,你应该能够
- 说出多步任务难在哪里:错误累积、需要在多个可能的路径之间选择、任务复杂度超出单次调用的能力。
- 把”规划”理解为在部分解答的空间里搜索;说出 MCTS 的五个步骤(选择、扩展、评估、模拟、反向传播),以及 LATS 加上的两样东西:LM 的价值估计和反思。
- 解释树搜索为什么能比独立采样省预算(共享前缀),以及为什么预算很大时独立采样又会追上来(多样性)。
- 说出 ADaPT 的思想:做不了的时候才分解,分解的粒度自动适应 executor 的能力和任务的复杂度;和 plan-and-execute 的区别。
- 说出 AB-MCTS 的问题——每一步该”往宽走”(生成新候选)还是”往深走”(改进已有候选)——以及它用 Thompson 采样自适应地做这个决定的方法。
- 说出 SPRINT 怎样让 reasoning model 在推理中并行地执行独立的子任务,减少串行的 token 数。
- 说出 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 数):从头写一份 步的解答花 ,从第 步续写花 。这样”共享前缀”省下的预算就能体现出来。
- 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 节的”可靠性的算术”已经说明了第一个困难:
- 错误累积:每步成功率 , 步全对的概率是 。
此外还有两个:
- 分叉:很多任务在中途有多个可能的方向(先查 A 还是先查 B?用哪种算法?),选错了方向,后面做得再好也没用。走一步看一步(ReAct 那样的”贪心”决策)一旦走错,很难回头。
- 复杂度超出能力:有些子任务对模型来说”一口气做不完”(第 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 的核心。它在一棵搜索树上反复做四件事:
- 选择(selection):从根出发,按某个规则选子节点往下走,直到一个”还可以展开”的节点。规则要平衡两件事:去平均回报高的节点(利用),也去访问次数少的节点(探索)。常用的是 UCT:
AlphaGo 用的变体 PUCT 还乘上一个先验 (神经网络认为这一步好的概率):。
- 扩展(expansion):在选中的节点上添加一个或几个子节点。
- 模拟(simulation,也叫 rollout):从新节点出发,快速地走到终点,看结果好不好。
- 反向传播(backpropagation):把结果沿路径往上更新每个节点的 和 。
反复做很多轮之后,访问次数最多的那条路径就是搜索的结论。MCTS 的好处是把计算集中在有希望的分支上,同时保留一定的探索。
2.2 LATS 怎样把 MCTS 用在 LLM agent 上
LATS(Language Agent Tree Search,Zhou et al. 2023)把 MCTS 的每一步都换成了 LLM 能做的事:
| MCTS 的步骤 | LATS 的做法 |
|---|---|
| 状态 | 到目前为止的轨迹(问题 + 已经写的思考、动作、观察) |
| 扩展 | 让 LLM 从当前状态采样 个可能的下一步(思考 + 动作) |
| 评估 | 让 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) |
|---|---|---|---|---|
| 2 | 0.583 | 0.693 | 0.690 | 0.677 |
| 4 | 0.767 | 0.800 | 0.820 | 0.830 |
| 8 | 0.867 | 0.897 | 0.920 | 0.913 |
| 16 | 0.950 | 0.917 | 0.940 | 0.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 的设定:任务是 步算术链;executor 一次调用就要交出结果(direct 模式);planner 把任务对半拆(AND),有 2% 的概率拆错(漏掉一步);环境的成功信号有 2% 的误报和漏报。三种策略:
- iterative executor:直接做整个任务,失败了重试,最多 3 次。
- plan-and-execute:固定地拆成每块 2 步,每块最多尝试 2 次,任何一块失败整个任务就失败。
- ADaPT:每个(子)任务先直接做(最多 2 次),还是失败才拆成两半,递归,最多 3 层。
成功率 / 平均 LLM 调用次数:
| 步数 | 1B:plan-and-execute | 1B:ADaPT | 10B:plan-and-execute | 10B:ADaPT | 100B:plan-and-execute | 100B:ADaPT |
|---|---|---|---|---|---|---|
| 2 | 0.927 / 2.2 | 0.993 / 1.4 | 0.993 / 2.1 | 1.000 / 1.1 | 1.000 / 2.0 | 1.000 / 1.0 |
| 4 | 0.260 / 3.6 | 0.520 / 9.8 | 0.833 / 3.5 | 0.907 / 5.8 | 0.973 / 3.1 | 1.000 / 1.2 |
| 6 | 0.467 / 4.2 | 0.667 / 13.7 | 0.947 / 4.3 | 0.913 / 5.1 | 0.987 / 4.1 | 0.987 / 2.9 |
| 8 | 0.113 / 5.5 | 0.220 / 20.1 | 0.620 / 5.7 | 0.807 / 12.2 | 0.973 / 5.3 | 0.953 / 5.0 |
| 10 | 0.000 / 3.8 | 0.000 / 24.6 | 0.160 / 5.2 | 0.360 / 18.5 | 0.653 / 6.2 | 0.893 / 8.6 |
(iterative executor 一超过串行上限就接近 0:例如 100B 做 8 步时 0.027,见代码输出。)
ADaPT 的平均最大分解深度(同样的任务长度,executor 越弱拆得越深):
| 步数 | 1B | 10B | 100B |
|---|---|---|---|
| 4 | 1.67 | 1.07 | 0.02 |
| 8 | 2.78 | 2.14 | 0.95 |
| 10 | 2.95 | 2.70 | 1.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 用的是部分分数的反馈(“从第一步开始连续做对了几步”):
- 往宽:从头采样一份新的解答(花 步)。
- 往深:拿当前最好的解答,在第一个错误的那一步排除错误值重算,往后续写(第 4 讲的 repair,花 步)。
- 自适应:为两个动作各维护一个 Beta 分布,记录”这个动作有没有带来更好的分数”,用 Thompson 采样决定每一次做哪个(只在根部决策,是 AB-MCTS 的简化)。
预算 = 4 份完整解答:
| 题目 | 只往宽 | 只往深 | 交替 | 自适应(Thompson) |
|---|---|---|---|---|
| 3~4 步 | 0.903 | 0.987 | 0.933 | 0.943 |
| 5~6 步 | 0.830 | 0.963 | 0.880 | 0.893 |
| 7~9 步 | 0.637 | 0.937 | 0.797 | 0.803 |
7~9 步的题,不同预算下:
| 预算(份) | 只往宽 | 只往深 | 交替 | 自适应 |
|---|---|---|---|---|
| 4 | 0.620 | 0.913 | 0.780 | 0.800 |
| 8 | 0.800 | 0.980 | 0.920 | 0.920 |
| 16 | 0.887 | 1.000 | 0.993 | 1.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 学会在推理过程中动态地识别可以并行的部分:
- 数据整理:把已有的长推理轨迹重新组织成若干”轮”,每一轮由一个规划(这一轮要做哪几件独立的事)和若干个并行执行的子任务组成。
- 微调:用少量这样整理过的数据微调 reasoning model。
- 推理:模型写出一个规划后,几个子任务同时生成,结果汇总后再进入下一轮规划。
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)分两部分:
合成数据:
- 让 Gemma 2 27B 带上工具(搜索引擎、计算器),对一批问题生成多步轨迹:每一步写推理,然后调用工具或给出最终答案;工具的结果放回上下文,进入下一步。
- 逐步分解:一条有 个动作的轨迹,拆成 个子轨迹,每个子轨迹是”从开头到第 个动作”的上下文 + 第 个动作。
- 过滤:比较了四种:不过滤;过程过滤(每一步都被一个模型判断为合理的轨迹才保留);结果过滤(只保留最终答案正确的);两者都要。
逐步的 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. 小结
- 多步任务的三个困难:错误累积、分叉(选错方向难回头)、复杂度超出单次调用的能力。规划 = 在部分解答的空间里搜索。
- LATS:把 MCTS 用在 LLM agent 上——LLM 负责扩展、价值估计和反思,环境负责最终的反馈。HumanEval 上 GPT-4 达到 92.7%。toy world 显示:共享前缀让树搜索在小预算下胜过独立采样,但预算大时独立采样的多样性又追了上来(和 Snell et al. 对 beam search 的发现一致);搜索的细节对结果影响很大。
- ADaPT:做不了的时候才分解。分解的粒度自动适应 executor 的能力和任务的复杂度:强 executor 少拆、弱 executor 多拆。比固定的 plan-and-execute 更稳,也把计算花在需要的地方。比较 agent 结构时要统一重试预算和成功判断。
- AB-MCTS:在每个节点上用 Thompson 采样自适应地决定”往宽走”还是”往深走”,把多样性和多轮改进结合起来,在代码和工程任务上稳定地胜过重复采样和标准 MCTS。toy world 里反馈太精确,往深走总是最好;自适应策略买的是”不知道哪种更好时的稳健”,代价是试错的开销。
- SPRINT:让 reasoning model 在推理中规划并并行执行独立的子任务,准确率不变,长推理的串行 token 最多减少 39%(数学)、45%(GPQA)和 65%(Countdown)。
- SWiRL:合成多步、带工具的轨迹,逐步分解,用过程过滤和逐步的生成式奖励做 RL。过程过滤好于结果过滤,连最终答案错误的轨迹也有用;在 HotPotQA 上训练能迁移到 GSM8K。
8. 练习
1. UCT 和 PUCT(第 2.1 节) 一个节点访问了 100 次,有三个子节点:A 访问 60 次、平均回报 0.5;B 访问 30 次、平均回报 0.6;C 访问 10 次、平均回报 0.3。设 。 (a) 用 UCT 算每个子节点的分数,下一次选哪个? (b) 如果 C 的先验 ,A、B 的先验都是 0.2,用 PUCT()呢?
参考答案
(a) 。A:;B:;C:。选 B(C 很接近)。 (b) A:;B:;C:。选 C:先验高、访问少的节点得到更多探索。
2. 共享前缀省了多少(第 2.3 节) 一道 8 步的题。重复采样每次花 8 步。LATS 的一次迭代:在深度 的叶子上扩展 3 个候选(花 3 步),再从深度 续写到底(花 步)。 (a) 时,一次迭代各花多少步? (b) 在什么深度以下,LATS 的一次迭代比重复采样的一次还贵?这说明了什么?
参考答案
(a) :;:;:。 (b) 。树还很浅的时候,扩展的开销让 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),均值 ;往深:Beta(5, 2),均值 。 (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?