跳到主要内容
Cowers://
全部文章
推理范式

ToT 思维树 Tree of Thoughts

ToT = Tree of Thoughts(思维树)。把 CoT 的一条线性推理链,扩展成一棵可以分叉、评估、剪枝的树,并用经典搜索算法(BFS / DFS)来遍历它。 关键在于节点是什么:不是一个孤立的 though…

ToT:Tree of Thoughts 思维树

阅读提示 面向了解 CoT(思维链)并对传统搜索算法(BFS / DFS / Beam Search)有印象的学习者。 本篇的主线是:ToT 就是把经典搜索算法搬到「思考步骤」这种节点上。 ⚠️ = 常见陷阱 🆚 = 对比说明 💡 = 选择建议

目录


核心概念 ToT = Tree of Thoughts(思维树)。把 CoT 的一条线性推理链,扩展成一棵可以分叉、评估、剪枝的树,并用经典搜索算法(BFS / DFS)来遍历它。

关键在于节点是什么:不是一个孤立的 thought,而是一个 state(部分解)——原论文定义为 s = [x, z₁…zᵢ],即「原始问题 + 到目前为止的整条 thought 序列」。边才是一个新的 thought。这一点决定了评估器评的是「当前这个局面有没有希望」,而不是「这句话说得好不好」。

一、一句话定义

不要只沿着一条思路推理,而是同时铺开多条思路,评估后保留好的、淘汰差的,再继续展开。

二、最小示例:一棵被剪过枝的树

             Problem
                |
       -------------------
       |        |        |
     思路A     思路B     思路C
       |        |        |
      A1       B1       C1
      A2       B2
               |
              B3

实际运行时每个节点都会被打分,低分分支直接剪掉:

ToT 思维树搜索

读图顺序:从顶部「问题」出发,第一层生成三个候选思路并各自打分,思路 C(0.2)当场剪掉;沿保留的分支继续展开,B2 得分最高,最终在 B3 拿到答案。实线框是活跃分支,灰虚线框是被评估函数剪掉的分支。

一轮循环固定是四步:

生成候选思路(Propose)

评估(Evaluate)

保留好的 / 淘汰差的(Prune)

继续展开(Expand)

三、机制:四个必备组件

实现一个 ToT,缺一不可的是这四样:

组件 作用 常见做法
Thought 定义 一个「思考步骤」的粒度是什么 一行算式、一个中间方案、一句话
Generator 从当前节点生成 k 个候选 高温度采样,或一次性让模型列 k 个方案
Evaluator 给节点打分或排序 模型自评(打分 / 两两比较)、规则校验、跑代码
搜索策略 决定展开顺序和保留数量 BFS(保留 top-b 层层推进)、DFS(走到底再回溯)、Beam Search

它本质上是把传统搜索搬到语言推理上,但节点的含义没有变——两边都是「状态」:

传统搜索的节点:状态(棋盘局面、地图位置)
ToT 的节点:    状态 = 原问题 + 已经走过的全部 thought,即一个「部分解」
ToT 的边:      一个新的 thought(一个推理步骤)

⚠️ 把节点理解成「一个孤立的 Thought」 这是读 ToT 最常见的偏差,也是本笔记旧版本犯的错。如果节点只是一句孤立的想法,评估器就只能评「这句话听起来靠不靠谱」——那正是第五节要批判的失效方式。

原论文里节点是 s = [x, z₁…zᵢ]带着完整历史的部分解。以 24 点为例,走完 4 + 9 = 13 之后,节点不是「4+9=13」这句话,而是「剩余数字 13, 5, 6」这个局面。评估器拿到的是局面,才能判断「用 13、5、6 还凑不凑得出 24」。

实现时的检查清单:你的 Generator 的输入是不是完整的部分解?Evaluator 评的是不是局面而不是最后一步?如果答案是否,你实现的就不是 ToT。

Thought 粒度决定成败 粒度太粗(「思路 A:用动态规划」)→ 评估器无法判断好坏,因为还没落地。 粒度太细(每个 token 一个节点)→ 树爆炸,成本失控。 经验规则:一个 Thought 应该是「独立可评估、且推进了实质进度」的最小单位。以 24 点游戏为例,一个 Thought 就是一次算式(4 + 9 = 13),既能立刻校验合法性,又确实缩小了问题。

四、🆚 和 CoT、Self-Consistency 的区别

三者常被混淆,差别在分支发生的时机有没有中途评估

维度 CoT Self-Consistency ToT
路径数量 1 条 N 条完整链 1 棵树,动态增删
分支时机 从头就分叉,各走各的 每一步都可分叉
中途评估 无(只在末尾投票) 每步都评估
能否回溯 取决于搜索策略(DFS 会显式回溯,BFS 不回溯)
走错了怎么办 一路错到底 靠多数票稀释 当场剪掉,换分支
成本 高,且随深度和分支数增长

一句话区分:

  • CoT:一条路走到黑。
  • Self-Consistency:N 条路各走到黑,最后投票。
  • ToT:边走边评估,走不通的当场剪掉,换分支。

「回溯」和「并行」都是可选项,不是 ToT 的定义 两个常见的过度概括:

  • 不是每种 ToT 都回溯。 原论文同时用了 BFS 和 DFS:24 点和创意写作用 BFS——一层一层往下推、每层只留 top-b,走不通的分支直接被剪掉,并没有「退回上一步」这个动作;填字游戏用 DFS——才有显式的回溯。
  • 不是每种实现都物理并行。 「同时铺开多条思路」说的是搜索结构上同时存在多个候选,不代表工程上必须并发调用模型。串行地把 b 个候选逐个生成、逐个评估,同样是 ToT,只是慢一些。

五、⚠️ 核心陷阱:评估函数是整个方法的命门

⚠️ 用 LLM 自评当评估器,却没有校准 错误操作: 直接让模型给每个思路打 0~1 分:「请给这个思路的可行性打分」。

实际结果: 打分密集分布在 0.7~0.9,几乎区分不出好坏;剪枝退化成随机剪枝。更糟的是,模型倾向于给表述流畅的思路高分,而不是给真正可行的思路高分——最后剪掉的往往是写得糙但正确的那条。

原因: LLM 的绝对分数没有校准基准,它不知道 0.7 和 0.8 的客观差别在哪;而流畅度是训练目标里的强信号,可行性不是。

正确做法: 优先级从高到低:

  1. 能确定性校验的部分一律用代码——能跑代码就跑代码,能算就算,能查 schema 就查。
  2. 用分类而非打分——原论文在 24 点上就是让模型把状态归成 sure / likely / impossible 三档,比连续分数稳定得多。
  3. 用两两比较而非绝对分——「A 和 B 哪个更有希望」的准确率显著高于给 A 打分。原论文在创意写作这类没有客观标准的任务上用的就是投票式比较。

⚠️ 以为 24 点的评估器只是「查算式合不合法」 错误操作: 认为 24 点是可判定问题,所以评估器写成一个校验函数:算式合法就留、不合法就剪。

实际结果: 几乎剪不掉任何东西。因为 Generator 生成的候选基本都是合法算式——4+9=134×9=369-4=5 全都合法。合法性筛完,该展开的分支一个没少,指数爆炸原封不动,ToT 退化成穷举。

原因: 混淆了两个不同的判断。「这一步合不合法」是语法问题,确实可判定且廉价,但没有区分度;ToT 真正需要的是「从这个局面出发还够不够得着 24」——这是前瞻性判断,才是剪枝的依据。原论文的 value prompt 做的正是后者:把剩余数字喂给模型,让它判断能否达到 24,输出 sure / likely / impossible

正确做法: 两层叠加——先用代码做合法性和终止判定(算错了、用错数字、已经等于 24),用模型或启发式做「还有没有希望」的前瞻评估。只做第一层等于没有评估器;只做第二层则会让明显算错的分支活下来。

顺带一提:24 点确实可以纯暴力枚举求解,根本不需要 LLM。它在论文里的角色是基准任务,用来量化 ToT 相对 CoT 的提升,不是说这类问题该用 ToT 解。

⚠️ 成本失控 错误操作: 分支数 k=5,深度 d=4,不设任何预算上限。

实际结果: 不剪枝时,第 4 层的叶子就有 5⁴ = 625 个,整棵树的节点总数是 1 + 5 + 25 + 125 + 625 = 781。每个节点至少一次生成 + 一次评估,单次问答上千次模型调用,延迟以分钟计。

原因: 每层节点数是 kᵈ,总数是等比数列求和 (k^(d+1) − 1) / (k − 1),量级由最后一层主导,所以仍然是指数增长。

注意别把 kᵈ 和总节点数搞混——kᵈ 只是第 d 层的宽度。分支数大时两者差距不大(781 vs 625),但 k=2 这种小分支下差一倍(d=4 时叶子 16、总数 31),估成本时按总数算。

正确做法: 三道闸门一起上:

  • Beam Search 固定每层只保留 b 个节点(把指数压成线性 b × k × d);
  • 设总节点数硬上限,超了就返回当前最优;
  • 深度上限 + 早停(一旦某分支达到可接受解就停)。

💡 先问一句:这题真的需要 ToT 吗 ToT 的收益来自「走错了能退回来」。如果任务本身很少走错,或者错了也能靠 Reflexion 事后修,那 CoT + Reflexion 的组合通常比 ToT 便宜一个数量级。ToT 适合那种错了就没法修、必须当场换路的问题。

六、什么时候用

用:

  • 数学题、逻辑题、Puzzle(24 点、数独、填字)
  • 需要探索多种方案再选优的规划问题
  • 有廉价、可靠的中间校验手段的任务(这是关键前提)

不用:

  • 单跳事实问答 → 直接答
  • 缺信息而非缺思路 → Self-Ask
  • 对延迟和成本敏感的线上场景 → ToT 通常跑不起

七、复习重点

复习重点

  1. 定义:把 CoT 的线性链扩展成可分叉、可评估、可剪枝的树,再用经典搜索算法遍历。
  2. 节点是 state 不是 thoughts = [x, z₁…zᵢ],即「原问题 + 走过的全部 thought」这个部分解;thought 是。评估器评的是局面,不是最后那句话。
  3. 一轮四步:生成候选 → 评估 → 剪枝 → 继续展开。
  4. 四个必备组件:Thought 粒度定义、Generator、Evaluator、搜索策略。
  5. 和 Self-Consistency 的关键差别:ToT 每步都评估;Self-Consistency 只在末尾投票,走错了也得走完。回溯是 DFS 变体才有的,不是 ToT 的定义。
  6. 命门:Evaluator,而且要评「还有没有希望」而不是「这步合不合法」——24 点的 value prompt 判的是剩余数字能否达到 24(sure / likely / impossible)。别用未校准的 LLM 绝对打分。
  7. 成本:第 d 层宽度是 kᵈ,总节点数(k^(d+1)−1)/(k−1)(k=5、d=4 时是 781,不是 625)。必须用 Beam 宽度 + 节点上限 + 早停三道闸门。
  8. 它管哪一层:候选搜索。缺思路才用它;缺信息用 Self-Ask,缺步骤用 Plan-and-Execute

相关笔记:Agent 推理范式总览Plan-and-Execute 先规划再执行Reflexion 反思式自我纠错Self-Ask 自问自答多跳推理