Tree of Thoughts:当LLM学会"分叉思考"——从线性接龙到树状搜索的推理革命

阅读导航:这篇文章会从一道让CoT也束手无策的"24点游戏"开始,先让你看到Tree of Thoughts(ToT)的全貌(宏观),再逐层剥开"思维节点"、"评估函数"和"搜索算法"的内部结构(中观),最后落到单个token如何在分支间流转(微观)。如果你已经熟悉CoT的线性链条、Zero-shot-CoT的触发句,或者OPAR循环的反馈控制,我们会不断用它们作为锚点。准备好了吗?我们出发。


0. 从一个让CoT也头疼的问题开始

来看一道经典题:

用 4、9、10、13 这四个数字,通过加减乘除和括号,得到 24。

如果你用标准的Chain-of-Thought(CoT),模型会生成一条漂亮的线性推理链:

“First, try 13 - 9 = 4. Then 4 × 4 = 16. Then 16 + 10 = 26. Not 24. Hmm…”

然后呢?然后CoT就卡住了。因为它只有一条路,一旦开头选了"13-9",后面就只能在这条路上修修补补,没法回头。这就像你走进一条死胡同,但墙上的油漆还没干——你只能继续往前蹭。

但如果模型能像人类一样分叉思考呢?

“Option A: 13 - 9 = 4… Option B: 10 - 4 = 6… Option C: 13 + 9 = 22…”

然后在每个分叉口都竖一块路牌:“此路不通"或"前景看好”。最终沿着最有希望的分支走到终点。

这就是本文的主角——Tree of Thoughts(ToT, Yao et al., 2023)。别急,这个名字听起来像数据结构课,对吧?但如果我们把它画成图,你会发现它其实很像你在陌生城市里找餐厅的过程。让我们先站在山顶,看看全貌。


1. 宏观视角:ToT的全貌——如果画成一张交通地图

如果我们把模型解决问题的过程画成一张交通地图,会有三条并行的道路:

差异:
线性无分支
错误会累积

差异:
单路径探索
无显式评估

🌳 Tree of Thoughts
Yao et al., 2023
立交桥+导航系统

问题
根节点

分支1:
13-9=4

分支2:
10-4=6

分支3:
13+9=22

评估:
promising ✓

评估:
promising ✓

评估:
dead end ✗

4×10=40...

6×4=24 ✓

📝 可以回溯、
可以剪枝、
可以探索多条路径

🚦 Zero-shot-CoT
触发式单行道

问题 + Let's think
step by step

步骤1
尝试路径A

步骤2
继续路径A

答案
(可能错 /
无法验证中间步)

🛣️ Chain-of-Thought
单行道

卡死 /
无回头路

问题

步骤1
13 - 9 = 4

步骤2
4 × 4 = 16

步骤3
16 + 10 = 26 ❌

死胡同

如果画成图会是什么样子? CoT像一条单行道,一旦开上去就只能踩油门或刹车,不能掉头。Zero-shot-CoT是在单行道入口加了一个导航语音,告诉你"请保持直行",但本质上还是单行道。ToT则像一座立交桥——在每个路口都有多个匝道,而且每个匝道入口都有红绿灯(评估函数),告诉你"此路畅通"或"前方施工"。

关键认知:ToT不是"教"模型生成更多token,而是给模型一个"决策空间",让它能像人类一样在多个中间想法之间比较、选择、回溯。 它把LLM从"接龙选手"升级为"棋手"——每步都考虑多种走法。


2. 中观拆解:四个核心组件里究竟在发生什么?

现在我们已经了解了ToT的全貌,接下来看看它内部的四个核心组件。每节只解决一个认知疑点。

2.1 Thought Node:什么是"思维节点"?——不只是文本片段

我们先问一个直觉问题:在ToT里,“一个想法”(thought)到底是什么?是像CoT里的一句话,还是更像某种数据结构?

别急,答案是:一个thought节点是一个"状态"(state),它封装了从问题开始到当前步骤的所有历史。 用Yao等人的符号表示:

s = [x, z1, z2, …, zi]

其中x是原始问题,z1到zi是到目前为止生成的中间推理步骤。这个节点不是孤立的字符串,而是部分解的完整快照

渲染错误: Mermaid 渲染失败: Parse error on line 5: ...sub>1="13-9=4"]"] ROOT --> -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'STR'

锚定已知概念:这很像RNN中的隐藏状态ht。在RNN里,ht编码了从时间步1到t的所有输入历史。ToT中的thought节点si就是推理时间步i的"隐藏状态"——只不过它是显式的文本形式,而不是压缩的向量。不同之处在于,RNN的下一步只由ht决定,而ToT的下一步可以从同一个父节点生出多个子节点——就像RNN突然学会了"平行宇宙"分裂。

听起来抽象对吧?让我们看一个toy example。假设我们的问题极简到只有两个操作:

问题:从数字 2 开始,经过两步运算得到 8。
可用操作:×2 或 +3

根节点 s0 = [“从2开始”]。

第一层展开:

  • s1(1) = [“从2开始”, “×2 → 4”]
  • s1(2) = [“从2开始”, “+3 → 5”]

第二层从s1(1)展开:

  • s2(1,1) = […, “×2 → 4”, “×2 → 8”] ✅ 目标达成!
  • s2(1,2) = […, “×2 → 4”, “+3 → 7”] ❌ 未达成

很简单对吧?但在真实规模中,每个节点可能包含数百个token的上下文,而分支因子(branching factor)k可能达到5-10。原理一样,只是规模爆炸了。


2.2 Thought Generation:从"接龙"到"分叉"——Actor的角色

现在我们已经了解了节点结构,接下来看看一个关键疑点:模型怎么知道要生成哪些分支?是随机瞎猜吗?

别急,ToT把LLM当作一个Actor(行动者),通过特定的prompt让它生成候选thoughts。具体来说,有两种生成策略:

  1. i.i.d.采样:对同一个父节点,独立采样k次,每次生成一个候选thought。就像让模型"头脑风暴",快速列出k个想法。
  2. Propose Prompt:设计一个专门的prompt,明确要求模型"列出k个不同的下一步"。

⚡ Thought Generation
Actor 角色

父节点 st
包含历史路径

生成提示
Propose Prompt

LLM Actor
pθ(z | st)

候选1: z(1)
13 - 9 = 4

候选2: z(2)
10 - 4 = 6

候选3: z(3)
13 + 9 = 22

...

候选k: z(k)

子节点集合
{st+1(1), ..., st+1(k)}

视觉化描述:想象Actor是一位厨师,父节点是"当前已切好的食材"。厨师不看菜谱(不依赖确定性规则),而是凭经验和创意(概率生成)提出k种不同的下一步切法。每种切法都是一个候选thought。

这和全连接层有什么关系?如果把LLM的输出层看作一个巨大的Softmax分布,标准CoT只取argmax(贪婪解码)或top-p采样(一条路径)。ToT的Actor则在这个分布上独立采样k次,相当于从同一个概率云里提取k个不同的"量子态"。

渐进披露:先理解小词表的情况——模型只是从{×2, +3}中采样两次。再推广到真实规模:在Game of 24中,模型需要从当前四个数字的状态中,生成所有合法的加减乘除组合作为候选thoughts。分支因子k通常设为3-5,由计算预算决定。


2.3 State Evaluation:谁来做"路牌"?——Critic的角色

现在我们已经了解了如何生成分支,接下来看看一个更微妙的疑点:如果每个节点都生5个分支,深度为5层,那就有55 = 3125个叶节点。模型不可能全部算完。谁来决定哪些分支值得继续探索?

答案是:评估函数(Evaluation Function),也就是ToT中的**Critic(评论家)**角色。它给每个thought节点打分,决定这盏路灯是绿的(继续)还是红的(剪枝)。

🎛️ State Evaluation
Critic 角色

v ≥ θ

v < θ

候选节点 st+1(j)

方法1: 启发式打分
LLM自我评估
Rate 1-10

方法2: 投票评估
Self-Consistency
多数决

方法3: 学习验证器
Trained Verifier
V(s) → ℝ

v = 8/10
promising ✓

3/5票认为可行
promising ✓

V(s) = 0.85
promising ✓

决策阈值
θprune

保留 /
加入搜索队列

剪枝 /
丢弃子树

问题驱动:评估函数怎么打分?Yao等人提出了几种方案:

  1. LLM自评(Value Prompt):把thought丢回LLM,问"这个想法离解决目标有多近?请打分1-10"。这听起来像自己给自己看病,但 surprisingly 有效——因为LLM在预训练中见过大量"评估-反馈"文本。
  2. 投票评估:对同一个thought采样多次评估,取多数决。这利用了Self-Consistency的思想。
  3. 学习验证器(Learned Verifier):训练一个独立的模型V(s) → ℝ,专门评估thought质量。类似AlphaGo中的价值网络。

锚定已知概念:如果你熟悉神经网络中的分类器,评估函数就像一个二分类器(保留 vs 剪枝),只不过它的输入是一个文本状态s,输出是一个标量值。在强化学习的视角下,这个值就是状态价值函数V(s)——评估从当前状态出发,最终达成目标的期望概率。

在继续之前,让我们回到toy example。假设评估函数是一个简单的规则:“当前数字能否在剩余步数内到达8?”

  • s1(1) = […, “×2 → 4”]:还剩一步,4可以×2到8。评估 = promising
  • s1(2) = […, “+3 → 5”]:还剩一步,5无法通过×2或+3到达8。评估 = dead end

于是s1(2)被剪枝,模型不会继续探索它的子节点。这就是主动剪枝的力量——它把指数级爆炸的搜索空间压缩到可管理的范围。


2.4 Search Algorithm:BFS vs DFS——导航策略的选择

现在我们已经了解了节点生成和评估,接下来看看最后一个中观疑点:有了节点和评估函数,模型到底怎么遍历这棵树?是像排队买票一样一层层来(BFS),还是像钻地洞一样一条道走到黑再回头(DFS)?

别急,ToT框架提供了两种经典搜索策略,适用于不同类型的任务:

🔍 搜索策略对比

差异:
每层保留最优b个
类似 Beam Search

🕳️ DFS 深度优先
Yao et al., 2023
钻地洞+回溯

评估: 失败
回溯

评估: 成功
终止

节点A
探索到底

节点A-1
探索到底

节点A-1-1
到达叶节点

回到节点A-1

节点A-2
新分支

节点A-2-1
到达叶节点

🏁 输出答案

💡 适合: 深层树 /
需要快速验证完整路径
如 Mini Crosswords
(深度可达10+)

🌊 BFS 广度优先
Yao et al., 2023
排队安检

深度0
根节点

深度1
所有候选
{z(1), z(2), z(3)}

评估全部
保留Top-b

深度2
从Top-b扩展
所有候选

评估全部
保留Top-b

深度3
...

💡 适合: 浅层树 /
需要全局视野
如 Game of 24
(深度仅3-4)

视觉化描述

  • BFS像排队安检。所有人先过第一层安检,合格的进入第二层,再全部过第二层安检… 每层只保留最 promising 的b个节点(beam width)。Yao等人在Game of 24中使用BFS,因为树的深度很浅(通常3-4步就能完成24点),而且需要比较不同开局的优劣。
  • DFS像钻地洞。选一个洞一直钻到底,如果发现是死胡同,就退回到上一个分叉口,换另一个洞钻。在Mini Crosswords中,ToT使用DFS,因为填字游戏需要连续填10个以上的词,BFS会在中间层爆炸(每层的候选词太多)。

渐进披露:先理解极简情况——我们的"2到8"问题只有两层,BFS和DFS没区别。再推广到真实规模——Game of 24的BFS在每层评估5个候选,保留Top-3,深度3层,总共只探索约33 = 27个节点,而不是53 = 125个。这就是beam search的思想:用评估函数做概率剪枝。


3. 微观视角:Token与概率如何在树中流转?

现在我们已经了解了中观层面的四个组件,接下来看看最微观的层面:当模型生成一个thought节点时,token级别的概率流到底发生了什么变化?别急,这部分我们从一个toy example开始,再推广到真实规模。

3.1 Toy Example:极简算术树的概率展开

问题:用 2, 3 通过两步运算得到 10。可用操作:×2, +3, ×3。

不加ToT时,CoT的解码是一条直线:

输入: [Q, "Step 1:"]
→ "2 + 3 = 5" (P=0.4)
→ "Step 2: 5 × 2 = 10" (P=0.3 | 上一步)
→ 答案: 10 ✅

但如果第一步模型不幸采样到"2 × 3 = 6"(P=0.35),第二步就卡死了:

→ "2 × 3 = 6" (P=0.35)
→ "Step 2: 6 + 3 = 9" (P=0.5 | 上一步)
→ 答案: 9 ❌

CoT没有后悔药。ToT则不同。在ToT中,第一步不是只采样一个thought,而是并行采样k=3个候选

从根节点 s0 = ["用2,3得到10"] 展开:

候选 z<sup>(1)</sup>: "2 + 3 = 5"      P(z<sup>(1)</sup>|s0) = 0.40
候选 z<sup>(2)</sup>: "2 × 3 = 6"      P(z<sup>(2)</sup>|s0) = 0.35
候选 z<sup>(3)</sup>: "3 × 3 = 9"      P(z<sup>(3)</sup>|s0) = 0.15

评估函数(这里用一个简单规则:“当前结果能否在一步内到10?”)打分:

  • v(s1(1)) = 0.9(5可以×2到10)
  • v(s1(2)) = 0.2(6无法一步到10)
  • v(s1(3)) = 0.1(9无法一步到10)

BFS策略保留Top-b=1(只保留s1(1)),然后继续展开:

从 s1<sup>(1)</sup> = [..., "2+3=5"] 展开:

候选 z<sup>(1,1)</sup>: "5 × 2 = 10"    P = 0.80
候选 z<sup>(1,2)</sup>: "5 + 3 = 8"     P = 0.15

评估:v(s2(1,1)) = 1.0(目标达成!),终止搜索,输出10。

啊哈时刻:注意概率的变化!在标准CoT中,正确答案路径的整体概率是 P(z(1)) × P(z(1,1)|z(1)) = 0.40 × 0.80 = 0.32。但ToT通过显式展开和评估,确保即使某条路径的初始概率不是最高(比如0.40 vs 0.35),只要评估认为它promising,就会深入探索。这就像一个概率放大镜:把局部概率高但全局死胡同的路径过滤掉,把全局有希望的路径放大。

3.2 推广到真实规模:注意力头的"分叉"与"评估"

在真实LLM中,上述过程涉及数百亿参数。研究表明,ToT的"分叉生成"可能激活了Transformer中的特定机制:

  • 生成阶段:模型对同一个父节点做k次独立前向传播(或一次batch forward),每次用不同的随机种子或temperature。这相当于在解码空间的局部区域做蒙特卡洛采样
  • 评估阶段:当LLM作为Critic评估自身生成的thought时,它实际上在做条件概率判断:P(“yes” | “Is this thought promising?” + thought_text)。这个概率被用作价值分数。
渲染错误: Mermaid 渲染失败: Parse error on line 12: ...(j)) = P("yes" | prompt)"] -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'STR'

锚定已知概念:如果你熟悉束搜索(Beam Search),ToT-BFS本质上就是一种带有LLM评估器的自适应Beam Search。标准Beam Search用序列概率(log-likelihood)作为评分,ToT用LLM的语义评估作为评分。后者更灵活,但也更昂贵(需要额外的LLM调用)。


4. 结构化伪代码:ToT的精确描述

好了,现在我们已经了解了直觉和微观概率流,接下来看看如果用结构化伪代码描述ToT,会是什么样子。

4.1 ToT 通用主框架

算法 1: Tree of Thoughts 通用框架
输入: 问题 x, LLM Actor ℳ<sub>actor</sub>, LLM Critic ℳ<sub>critic</sub>,
      分支因子 k, 保留宽度 b, 最大深度 D<sub>max</sub>, 搜索策略 𝒮 ∈ {BFS, DFS}
输出: 最终答案 A, 最优路径 z<sup>*</sup>

 1: procedure TREE_OF_THOUGHTS(x, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, b, D<sub>max</sub>, 𝒮)
 2:     s<sub>0</sub> ← INITIALIZE_STATE(x)      ▷ 根节点仅包含问题
 3:     𝒯 ← {s<sub>0</sub>}                      ▷ 初始化搜索树
 4:     
 5:     if 𝒮 = BFS then
 6:         return BFS_SEARCH(𝒯, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, b, D<sub>max</sub>)
 7:     else if 𝒮 = DFS then
 8:         return DFS_SEARCH(𝒯, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, D<sub>max</sub>)
 9:     end if
10: end procedure

4.2 BFS 变体(广度优先+束剪枝)

算法 2: ToT-BFS 搜索
输入: 搜索树 𝒯, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, b, D<sub>max</sub>
输出: 最终答案 A

 1: procedure BFS_SEARCH(𝒯, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, b, D<sub>max</sub>)
 2:     𝒬 ← {s<sub>0</sub>}                      ▷ 初始化队列,含根节点
 3:     
 4:     for d ← 1 to D<sub>max</sub> do
 5:         𝒬<sub>next</sub> ← ∅
 6:         
 7:         ▷ ====== 第一步: 展开所有当前节点 ======
 8:         for each s ∈ 𝒬 do
 9:             if IS_TERMINAL(s) then
10:                 return EXTRACT_ANSWER(s)
11:             end if
12:             
13:             ▷ 从Actor生成k个候选thoughts
14:             𝒞 ← ℳ<sub>actor</sub>.GENERATE_CANDIDATES(s, k)
15:             
 16:            for each z ∈ 𝒞 do
17:                 s<sub>child</sub> ← EXTEND_STATE(s, z)
18:                 𝒬<sub>next</sub> ← 𝒬<sub>next</sub> ∪ {s<sub>child</sub>}
19:             end for
20:         end for
21:         
22:         ▷ ====== 第二步: 评估与剪枝 ======
23:         𝒱 ← ∅
24:         for each s<sub>cand</sub> ∈ 𝒬<sub>next</sub> do
25:             v ← ℳ<sub>critic</sub>.EVALUATE(s<sub>cand</sub>)
26:             𝒱 ← 𝒱 ∪ {(s<sub>cand</sub>, v)}
27:         end for
28:         
29:         ▷ 保留Top-b个最有希望的节点
30:         𝒬 ← TOP_B(𝒱, b)
31:         
32:         ▷ 可选: 将剪枝信息写回上下文
33:         LOG_PRUNING_INFO(𝒬<sub>next</sub> \ 𝒬)
34:     end for
35:     
36:     ▷ 达到最大深度,从队列中选最优
37:     s<sub>best</sub> ← argmax<sub>s ∈ 𝒬</sub> ℳ<sub>critic</sub>.EVALUATE(s)
38:     return EXTRACT_ANSWER(s<sub>best</sub>)
39: end procedure

注意看第30行。TOP_B操作是BFS的核心——它把指数增长的候选空间压缩到固定宽度b。这就像水库的闸门,只允许b股水流通过,其余全部截流。

4.3 DFS 变体(深度优先+回溯)

算法 3: ToT-DFS 搜索
输入: 搜索树 𝒯, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, D<sub>max</sub>
输出: 最终答案 A

 1: procedure DFS_SEARCH(𝒯, ℳ<sub>actor</sub>, ℳ<sub>critic</sub>, k, D<sub>max</sub>)
 2:     s<sub>current</sub> ← ROOT(𝒯)              ▷ 从根节点开始
 3:     
 4:     while NOT_EMPTY(STACK) do
 5:         if IS_TERMINAL(s<sub>current</sub>) then
 6:             if VERIFY_ANSWER(s<sub>current</sub>) then
 7:                 return EXTRACT_ANSWER(s<sub>current</sub>)
 8:             else
 9:                 ▷ 答案错误,回溯
10:                 s<sub>current</sub> ← BACKTRACK(STACK)
11:                 CONTINUE
12:             end if
13:         end if
14:         
15:         if DEPTH(s<sub>current</sub>) ≥ D<sub>max</sub> then
16:             s<sub>current</sub> ← BACKTRACK(STACK)
17:             CONTINUE
18:         end if
19:         
20:         ▷ ====== 生成与评估 ======
21:         𝒞 ← ℳ<sub>actor</sub>.GENERATE_CANDIDATES(s<sub>current</sub>, k)
22:         
23:         ▷ 按评估值降序排列,优先探索高分分支
24:         for each z ∈ 𝒞 do
25:             s<sub>child</sub> ← EXTEND_STATE(s<sub>current</sub>, z)
26:             v ← ℳ<sub>critic</sub>.EVALUATE(s<sub>child</sub>)
27:             PUSH(STACK, (s<sub>child</sub>, v))
28:         end for
29:         
30:         ▷ 选择栈顶最有希望的分支深入
31:         s<sub>current</sub> ← POP_MOST_PROMISING(STACK)
32:     end while
33:     
34:     return FAILURE
35: end procedure

注意看第10行的BACKTRACK。这是DFS的灵魂——当一条路径走到死胡同时,模型不是放弃整个任务,而是弹出栈顶,回到上一个分叉口。这和OPAR循环中的Reflect触发REPLAN非常相似,但ToT的REPLAN是结构化的、通过栈实现的,而不是通过上下文窗口的文本重写。

4.4 评估函数:LLM-as-Critic 的实现

算法 4: LLM-as-Critic 评估
输入: 候选状态 s, 评估提示模板 P<sub>eval</sub>, 阈值 θ<sub>prune</sub>
输出: 价值分数 v ∈ [0, 1], 决策标签 label ∈ {PROMISING, DEAD_END, TERMINAL}

 1: procedure LLM_CRITIC_EVALUATE(s, P<sub>eval</sub>, θ<sub>prune</sub>)
 2:     prompt ← RENDER_TEMPLATE(P<sub>eval</sub>, s)
 3:     ▷ 例如: "Evaluate if the following thought is promising to solve the problem.
Thought: {s}
Answer yes or no, then rate 1-10."
 4:     
 5:     response ← ℳ.GENERATE(prompt, temperature=0.0)
 6:     
 7:     ▷ 方法A: 从文本响应解析分数
 8:     if CONTAINS(response, "yes") then
 9:         v ← EXTRACT_NUMBER(response) / 10.0
10:     else
11:         v ← 0.0
12:     end if
13:     
14:     ▷ 方法B: 使用logits概率(更精确)
15:     ▷ v ← P<sub>ℳ</sub>("yes" | prompt)      ▷ 下一个token为"yes"的概率
16:     
17:     ▷ 决策逻辑
18:     if IS_COMPLETE_SOLUTION(s) then
19:         label ← TERMINAL
20:     else if v ≥ θ<sub>prune</sub> then
21:         label ← PROMISING
22:     else
23:         label ← DEAD_END
24:     end if
25:     
26:     return (v, label)
27: end procedure

注意看第15行被注释掉的方法B。这是RAP(Hao et al., 2023)论文中使用的高级技巧:不解析文本,而是直接看LLM输出"yes"的logit概率作为连续值评分。这比离散打分更细粒度,也更稳定。


5. 与已知概念的对话:ToT站在谁的肩膀上?

5.1 ToT vs CoT/Zero-shot-CoT:从单行道到立交桥

现在我们已经了解了ToT的内部机制,接下来看看一个关键的对比疑点:如果Zero-shot-CoT已经能让模型"逐步思考",为什么还需要ToT?

因为Zero-shot-CoT解决的是"怎么一步步想",ToT解决的是"想错了怎么回头"。这是两个维度的问题。

🔬 推理拓扑进化谱系

痛点:
错误累积 /
无法探索替代方案

痛点:
树结构无法表达
循环/聚合关系

CoT / Zero-shot-CoT
线性链
单路径
无回溯

Tree of Thoughts
树状拓扑
多路径
BFS/DFS搜索
显式评估+剪枝

Graph of Thoughts
Besta et al., 2024
有向图
聚合+精炼
循环依赖

锚定已知概念:如果你熟悉有限状态机(FSM),CoT就像一个确定性有限自动机(DFA)——每个状态只有一个出边。ToT像一个非确定性有限自动机(NFA)——每个状态有多个出边,搜索算法负责"模拟"NFA到DFA的转换。GoT则更进一步,允许状态之间有循环边(比如把两个子问题的答案聚合后再精炼)。

5.2 ToT vs OPAR循环:树搜索 vs 闭环控制

如果你读了OPAR循环的文章,你可能会问:OPAR有Observe-Plan-Act-Reflect的循环,ToT有树搜索,它们是什么关系?

答案是:OPAR是"时间维度"的循环,ToT是"空间维度"的展开。

🔄 OPAR × ToT 的互补关系

OPAR 循环
时间轴上的迭代
每一轮修正上一轮的错误
Reflect → Replan

联合视角:
OPAR的每个Plan阶段
可以用ToT做内部搜索

ToT 搜索
空间轴上的展开
同一时刻探索多条路径
Eval → Prune

混合架构:
Agent用OPAR控制任务节奏,
在Plan阶段调用ToT搜索
寻找最优子计划

视觉化描述:想象你在玩一个复杂的RPG游戏。OPAR是你的"宏观策略循环"——观察地图、制定战略、执行动作、反思战果。ToT是你打开背包后,面对"如何合成最强武器"时的内部配方搜索——你脑子里展开了一棵树:“用A+B合成C?不行,材料不够。用A+D合成E?评估一下, promising。继续深入…”

在生产级Agent中,这种混合架构已经出现:OPAR负责"做什么"(任务级),ToT负责"怎么做"(推理级)。


6. 边界与成本:ToT不是免费的午餐

6.1 组合爆炸:评估开销的隐藏账单

现在我们已经了解了ToT的强大,接下来看看它的致命弱点:如果每个节点生5个分支,深度5层,BFS每步评估所有候选,总共需要多少次LLM调用?

算一笔账:

  • Actor调用:每层每个保留节点生成k个候选。BFS中,第1层1个节点→5个候选,第2层保留b=3个→3×5=15个候选… 总Actor调用 ≈ O(bd-1 × k)。
  • Critic调用:每个候选都要评估。总Critic调用 ≈ O(bd-1 × k)。
  • 总成本:假设k=5, b=3, d=4,总调用 ≈ 33 × 5 × 2 ≈ 270次LLM前向传播

对比CoT的1次调用,ToT贵了两个数量级

渲染错误: Mermaid 渲染失败: Parse error on line 14: ...troke-width:2px end ----------------------^ Expecting 'SEMI', 'NEWLINE', 'SPACE', 'EOF', 'subgraph', 'acc_title', 'acc_descr', 'acc_descr_multiline_value', 'AMP', 'COLON', 'STYLE', 'LINKSTYLE', 'CLASSDEF', 'CLASS', 'CLICK', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', 'direction_tb', 'direction_bt', 'direction_rl', 'direction_lr', 'direction_td', got 'end'

渐进披露:先理解极简情况——我们的"2到8"问题只有两层,总调用 = 1(根) + 2(第一层Actor) + 2(第一层Critic) + 1(第二层Actor) = 6次。再推广到真实规模:Game of 24的论文中,ToT的成功率从CoT的7.3%提升到74%,但代价是数百倍的API调用。这就是**测试时计算(test-time compute)**的经典权衡:用计算换准确率。

6.2 评估的脆弱性:Critic也会犯错

另一个隐蔽的约束:如果Critic评估错了怎么办?

假设Critic给一条正确路径打了低分(假阴性),或者给错误路径打了高分(假阳性)。在BFS中,假阴性意味着正确路径被提前剪枝,永远找不到答案。在DFS中,假阳性意味着模型会沿着死胡同一路钻到底,浪费大量计算。

这和全连接层的分类误差完全类似。Critic本质上是一个二分类器(保留/剪枝),它的准确率直接决定了搜索效率。Yao等人的实验表明,即使使用LLM自评,Critic的评估也不是完美的——它只是比随机好得多,但仍有约10-20%的误判率。


7. 生产环境中的ToT:这到底意味着什么?

好了,原理和边界都讲完了。但"这在训练/实际使用中意味着什么?"

7.1 在训练时意味着什么

ToT是纯推理时技术(inference-time technique),但它创造了独特的训练机会:

  1. 过程监督数据(Process Supervision):ToT生成的完整搜索树——包括被剪枝的失败路径和保留的成功路径——是训练**过程奖励模型(PRM)**的绝佳数据。OpenAI的论文(Lightman et al., 2024)证明,用PRM替代最终答案奖励,能显著提升推理准确率。

  2. 策略蒸馏(Policy Distillation):用大模型(GPT-4)运行ToT生成的高质量推理路径,蒸馏到小模型(Llama-3-8B)中。让小模型学会"一步生成正确的thought",而不需要显式搜索。

  3. 验证器训练(Verifier Training):用ToT的评估日志训练一个轻量级验证器,替代昂贵的LLM-as-Critic。这类似于AlphaGo训练价值网络来替代昂贵的蒙特卡洛 rollout。

📊 训练视角的延伸

ToT 推理时搜索
生成成功/失败路径

过程监督数据
τ = (s0, z1, v1, s1, ..., A)

评估日志
{(s, v, label)}

训练 PRM
过程奖励模型
Lightman et al., 2024

训练轻量验证器
替代 LLM-as-Critic

小模型获得
过程级反馈能力

推理加速
评估成本降低10×

7.2 在实际使用中的最佳实践

如果你明天就要在生产环境部署ToT,这里有几个硬核建议:

生产要素 具体含义 最佳实践
任务选择 不是每个问题都需要ToT 简单算术用Zero-shot-CoT,创意写作用ToT-BFS,填字游戏用ToT-DFS。
预算控制 Token和API调用爆炸 设置全局调用上限Nmax;使用学习验证器替代LLM-Critic;启用缓存。
早期终止 找到答案后继续搜索是浪费 在DFS中,一旦VERIFY_ANSWER返回true,立即终止。
自适应束宽 不同深度需要不同粒度 浅层用宽束(b=5)探索多样性,深层用窄束(b=2)聚焦精细搜索。
评估一致性 Critic的随机性导致结果波动 对关键节点做多次评估取平均(类似Self-Consistency)。
与Agent集成 ToT作为子模块嵌入OPAR 在OPAR的Plan阶段调用ToT搜索子计划,Act阶段执行最优路径。

🏭 生产部署检查清单

简单任务 → CoT

超预算 → 强制终止

任务层
任务复杂度评估 /
ToT路由决策

预算层
Nmax上限 /
自适应束宽 /
缓存策略

搜索层
BFS/DFS选择 /
早期终止 /
评估一致性

集成层
OPAR Plan阶段 /
子计划搜索 /
结果回传

绕过ToT

安全熔断


8. 闭环总结与延伸阅读

让我们回到开头那个Game of 24的问题。现在你应该能看懂了:

模型不是"更聪明了"——它的权重一点没变。而是更会"逛街"了。CoT像一条直线商业街,你只能从街头走到街尾,遇到死胡同就傻站着。ToT像一座购物中心——每层都有多个店铺(thought节点),你在每个路口都看指示牌(评估函数),只进最有希望的店,遇到关门马上就退出来换一家(回溯)。

如果画成一张最终的总结图,ToT就像一台带有"多重宇宙导航仪"的推理引擎:Actor负责"制造平行宇宙",Critic负责"评估哪个宇宙有前途",Search算法负责"决定先探索哪个宇宙"。

渲染错误: Mermaid 渲染失败: Parse error on line 9: ...📝 记住: ToT不是让模型"变聪明",
而是给模型一个"可以后悔"的 -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'STR'

延伸阅读

如果你想深入这个领域,以下国外文献是极佳的起点:

  1. Yao et al., 2023, “Tree of Thoughts: Deliberate Problem Solving with Large Language Models” (NeurIPS 2023) —— ToT的奠基论文。核心贡献:将LLM推理建模为组合搜索空间上的树搜索,提出Actor-Critic-Search三元架构,在Game of 24上将成功率从CoT的7.3%提升到74%。必读。

  2. Wei et al., 2022, “Chain-of-Thought Prompting Elicits Reasoning in Large Language Models” (NeurIPS) —— 理解ToT的最佳背景。看清CoT的线性局限,才能理解ToT为何必要。

  3. Besta et al., 2024, “Graph of Thoughts: Solving Elaborate Problems with Large Language Models” —— ToT的直接进化版。将树结构扩展为有向图,支持聚合(Aggregation)、精炼(Refining)和循环(Cyclic)操作,适合需要多路径融合的任务。

  4. Hao et al., 2023, “Reasoning with Language Model is Planning with World Model” (RAP) —— 用蒙特卡洛树搜索(MCTS)替代BFS/DFS,LLM同时作为世界模型和推理Agent。展示了更高效的搜索策略。

  5. Lightman et al., 2024, “Let’s Verify Step by Step” (OpenAI) —— 过程监督的里程碑论文。证明用PRM(过程奖励模型)评估每一步比只评估最终答案更有效,为ToT的Critic设计提供了理论支撑。

  6. Long, 2023, “Large Language Model Guided Tree-of-Thought” —— 引入强化学习训练的"ToT Controller"动态调整搜索策略,而非固定使用BFS或DFS。

  7. Sel et al., 2024, “Algorithm of Thoughts” —— 探索在单次LLM调用中模拟算法搜索,试图用上下文内的"思维算法"替代显式的多轮API调用,是ToT的轻量化方向。


写在最后:Tree of Thoughts提醒我们一个深刻的道理——智能的本质不总是"知道更多",有时候是"知道如何尝试更多,并知道何时放弃"。ToT给LLM的礼物不是知识,而是选择的自由评估的智慧。下次当你面对一个复杂问题时,不妨也学学ToT:不要急着一条路走到黑,先在脑子里展开几棵树枝,看看哪片叶子最绿。


本文架构图使用 Mermaid 绘制,伪代码遵循结构化算法描述规范。数学上下标使用 HTML 标签(sub/sup)以确保跨平台兼容。如有错误,欢迎指出。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐