第 20 章 · Tree-of-Thoughts

一次定价方案的纠结

那个跨境卖家又碰到难题了。他要给一款新上架的户外水壶定价,问 Agent:“帮我想个既能抢占市场、又不至于亏本的定价策略。”

这个任务没有唯一答案。可以走“低价冲销量、靠复购回本”,也可以走“中高价树品牌、配赠品提转化”,还可以走“阶梯价——首周促销、之后回调”。哪条路更好,得把几条路都摊开算一遍才知道:低价路要算清广告成本会不会吃掉利润,品牌路要判断这个类目消费者认不认溢价……

如果让 Agent 顺着第一直觉一条道走到黑——比如它张口就说“定 19.9 美元冲量”——那你拿到的只是“一个还凑合的答案”,而不是“比较过几种后选出的最好答案”。第 15 章的思维链(Chain-of-Thought,CoT)能让它把这一条路想清楚,却没法让它同时权衡好几条路、走不通再换。这正是本章 Tree-of-Thoughts(思维树,ToT) 要解决的问题。

CoT 是一条链,ToT 是一棵树

先把两者的关系说透,这是本章最该记牢的一点。

Chain-of-Thought(CoT) 让模型“一步接一步地想”,推理过程是一条直线:想法 1 → 想法 2 → 想法 3 → 结论。它的好处是清晰、省钱;它的软肋也正在这条直线上——一旦某一步想歪了,后面全跟着错,而且没法回头。就像顺着一条路走进死胡同,却没有退路。

有些问题偏偏就像走迷宫:需要“试一条路,走不通就退回来换一条”。解一道逻辑谜题、规划一个多步骤方案、给一款新品定价——第一直觉往往不是最优的,得探索多个可能、比较之后再选

Tree-of-Thoughts(ToT) 就是把推理从“一条链”升级成“一棵树”:

  • 在每个决策点,不是只想一个下一步,而是生成多个候选(多个分支)。
  • 对每个候选评估(evaluate):这条路有希望吗?
  • 选择有希望的分支继续深入,放弃没希望的。
  • 走进死胡同就回溯(backtrack),退回上一个岔口换一条分支重来。

一句话:CoT 是“想一条路”,ToT 是“探索一片可能性,再选最好的”

本质:把搜索算法跑在“想法”上

ToT 听着新,内核却是计算机科学里最老实的东西——搜索(search)

把每个“想法”当成搜索树的一个节点(node),ToT 做的就是经典的树搜索:

  • 广度优先(BFS):每一层把所有候选都铺开,横向比较。适合分支不多、要全面比对的场景(比如就三种定价策略,全摊开算)。
  • 深度优先(DFS):顺着一条最有希望的分支一路钻到底,走不通再回溯。适合分支很多、想尽快找到一个可行解。
  • 剪枝(pruning):评估分低的分支直接砍掉、不再扩展——这是控制成本的命门。

和传统搜索唯一的区别是:节点不是预先定义好的,而是用模型现场生成;节点的好坏,也用模型来打分。所以 ToT 可以概括成一句:用 LLM 既当“扩展节点的生成器”,又当“评估节点的启发函数”,把搜索算法跑在想法上。

三个动作:生成—评估—选择—回溯

ToT 的骨架是一个循环,每一轮做四个动作:

1. 生成(Generate):从当前节点,生成 N 个候选下一步(分支)
2. 评估(Evaluate):给每个候选打一个"前景分"
3. 选择(Select):保留最有希望的 K 个,扩展它们(剪掉其余)
4. 回溯(Backtrack):到达目标 → 返回;走进死路 → 退回岔口换分支

你会发现,“生成候选”和“评估候选”天然适合用多个 Agent 并行做(回顾 Part 5)——一批 Agent 负责生成不同思路,另一批负责打分。这就是为什么 ToT 归在“高级推理”部分:它不是单个 Agent 的独角戏,常常需要多 Agent 协作来支撑那棵树的展开。

把定价这个任务套进来:第一层生成“低价冲量/中高价树品牌/阶梯价”三个分支,评估 Agent 分别给它们算利润模型打分,选出得分最高的两条继续往下展开“具体定多少、配什么赠品”,走到某个分支发现“广告成本会吃光利润”就剪掉、回溯换另一条——最后返回的,是比较过的最优路径,而不是拍脑袋的第一直觉。

用 pi 实现

pi 没有内建的 ToT 原语——它是一种你在 harness(运行时骨架)之上构建的模式。有了前面章节的积木(工具、循环、多 Agent),实现思路很清晰:

// 概念示意:用 Agent 生成候选、评估、选择,构成一棵思维树
async function treeOfThoughts(problem, { breadth = 3, depth = 3 }) {
  let frontier = [{ path: [], state: problem }]; // 当前这一层待扩展的节点
  for (let d = 0; d < depth; d++) {
    const candidates = [];
    for (const node of frontier) {
      // 生成(Generate):一个节点分出多个候选下一步,可并行
      const steps = await generateSteps(node.state, breadth);
      for (const step of steps) {
        const score = await evaluate(step); // 评估(Evaluate):用模型给前景打分
        candidates.push({ path: [...node.path, step], state: step, score });
      }
    }
    // 选择 + 剪枝(Select/Prune):只保留最有希望的分支
    frontier = candidates.sort((a, b) => b.score - a.score).slice(0, breadth);
    if (frontier[0].state.isSolved) return frontier[0].path; // 到达目标,返回
  }
  return frontier[0].path; // 深度用尽,返回目前最优路径
}

generateStepsevaluate 各自就是一次 Agent 调用——前者是“扩展节点”,后者是“启发式打分”。整个 ToT,就是“用循环 + 多 Agent,把搜索算法跑在想法上”。这里用的是最朴素的逐层广度剪枝(beam search,束搜索);想做深度优先或更花哨的回溯,改的只是遍历 frontier 的顺序,骨架不变。

动手看看

先别急着写整棵树,做个最小实验:给模型一个开放问题(比如“给这款水壶想三种定价策略”),让它一次只生成候选、不下结论,看它能不能给出真正不同的三条路(而不是换了措辞的同一条)——这一步的多样性,直接决定后面搜索有没有意义。

再单独写一个“评估提示”:把三个候选喂进去,要求模型只输出打分和一句理由。对照它的排序和你自己的判断——如果模型的评估不靠谱,整棵树就是在错误的启发函数下瞎搜。ToT 能不能用,八成取决于评估这一环准不准

实战中的几个坑

坑一:ToT 很贵,拿去做简单题。

  • 现象:一个本来 CoT 一步就答对的问题,用 ToT 跑了几十次调用、账单暴涨。
  • 原因:广度 3、深度 3 就是最多 27 条路径、几十次 LLM 调用,成本是 CoT 的一个数量级以上。
  • 对策:只对真正需要探索的难题用 ToT;简单题用 CoT 就够。用便宜模型做“生成候选”,贵模型做“关键评估”(分层,第 34 章)。

坑二:候选之间大同小异,等于没分叉。

  • 现象:生成的 N 个分支措辞不同、实质一样,搜索白搭。
  • 原因:生成提示没强调“要真正不同的思路”,或温度(temperature)太低。
  • 对策:在提示里明确要求“给出角度迥异的候选”,适当提高采样温度,必要时给每个分支预设不同视角。

坑三:评估函数不靠谱,越搜越偏。

  • 现象:模型把差分支打了高分,好分支被剪掉,最后返回一个烂答案。
  • 原因:评估提示太笼统,模型没有明确的打分标准。
  • 对策:给评估一套清晰的评分维度(如定价题就是“利润率/竞争力/可执行性”),让它按维度打分并给理由,别只要一个数字。

坑四:不设上限,搜索停不下来。

  • 现象:树越展开越大,迟迟不收敛,token 和时间双双失控。
  • 原因:没设 breadth / depth 上限,或没有“够好就停”的判据。
  • 对策:显式设定广度、深度上限;设一个“满意阈值”,第一个分支达标就返回,别追求穷尽最优。

对比:其他框架

ToT 是学术界提出的推理范式,本身不绑定任何框架——它是模式层面的技巧,四家框架都能实现,差别只在编排“搜索/回溯”这套控制流的便利性。

框架Tree-of-Thoughts 怎么做特点
LangGraph状态图天然表达“生成—评估—选择—回溯”:节点是生成/评估步骤,条件边处理“死路回退”,循环处理逐层展开要显式画出搜索树,它最顺手,代价是图定义啰嗦
CrewAI把“生成候选”“评估候选”拆成不同角色的 Task 让 Crew 协作偏“角色分工完成任务”,对树搜索、回溯无一等抽象,要自己绕
PydanticAI无内建搜索/树结构,但可让评估节点返回强类型的打分对象(分数+理由)把“评估”做得可靠,搜索循环仍要自己用普通 Python 写
Agno用 Workflow 编排多步、用 Team 组织“生成者/评估者”组件齐全上手快,但无专门 ToT 原语,展开与剪枝要自己搭
pi用工具、循环、多 Agent 这些积木自行组合成树harness 给“能力”、模式由你拼装,控制粒度细但不替你画树

一句话点破:没有哪家框架内建 ToT 原语——它是通用推理模式,各家的差别只在“编排搜索便不便利”,本质都是“用 LLM 生成+评估节点,跑一遍树搜索”。

小结

  1. ToT(Tree-of-Thoughts,思维树)把推理从“一条链”升级成“一棵树”:生成多个候选 → 评估 → 选最优 → 死路回溯,比 CoT 多了“分叉、比较、回退”的能力。
  2. 它的本质是把搜索算法跑在想法上——用 LLM 既当生成节点的扩展器、又当评估节点的启发函数,可选广度优先 / 深度优先 / 剪枝等策略。
  3. 与 CoT 的区别在“单线 vs 多路”:CoT 想一条路、想歪了回不来;ToT 探索一片可能、可回溯换路,代价是贵一个数量级
  4. pi 没有内建 ToT,它是在 harness 之上构建的模式,generateStepsevaluate 各是一次 Agent 调用,常需多 Agent 支撑。
  5. 成败在评估:评估函数不准,整棵树就在错误的启发下瞎搜;同时务必设好 breadth/depth 上限、配合分层模型控制成本。

ToT 是“一个思路探索多条路”,靠的是想得更全。下一章看另一种高级推理——让多个 Agent 互相辩论来逼近正确答案,靠的是视角更多。