图 1:ToT 的每一步都是「生成候选、打分、沿高分继续」。
先说明属性:这是一篇经典题解析,题目出自本地历史面试资料整理,与任何公司的当前招聘无关。思维链(CoT)大家已经很熟:让模型把中间步骤一步步写出来。思维树(ToT)是在它之上的下一个考点——为什么线性链条不够,以及把推理组织成搜索需要哪几个零件。
先看 CoT 在哪类任务上失灵。
CoT 是一条从左到右的直线:每一步都建立在前一步之上,一旦某个中间步骤走错,后面所有步骤都在错误的地基上继续,模型没有机制回头。对算术应用题这类「顺着推就能到」的任务,这没问题;但遇到需要探索、前瞻和回溯的任务——比如 24 点游戏,四个数字的运算组合是一棵指数增长的树,第一步选错两个数配对就注定无解——线性链条就成了硬伤。2023 年的 ToT 论文给了一组直观的对比:同样解 24 点,GPT-4 用 CoT 提示只解出 4% 的题目,换成 ToT 框架后成功率到了 74%。差距不是来自模型变聪明了,而是来自推理结构变了。
ToT 的四个要素:状态、生成、评估、搜索。
ToT 把任何问题形式化为在一棵树上的搜索,四个要素各司其职。
状态:树的每个节点是一个状态,即输入加上到目前为止的思考序列——一条部分完成的解。思考不是零散 token,而是一段连贯的语言片段,比如 24 点里的一次运算「13 - 9 = 4,剩余 4、4、10」。
生成:给定当前状态,让模型产出 k 个候选的下一步思考。论文给了两种姿势——对思考空间大的任务直接采样 k 个独立候选;对思考空间小的任务用一个提案提示让模型一次性列出多个选项。
评估:让模型自己给每个候选状态打分或投票,判断这条路「离答案更近还是更远」。这是 ToT 最妙的设定:语言模型同时扮演生成器和评估器,不需要额外训练任何打分模型。
搜索:用经典搜索算法把前三者粘起来——BFS 逐层扩展、每层只保留得分最高的若干状态;DFS 沿最有希望的分支深入,碰壁就回溯。算法本身是可插拔的,框架不关心你用哪一种。
用代码把「状态 + 生成 + 搜索」跑一遍。
下面这段代码用 BFS 在 24 点的思维树上搜索(Node.js 22.15.0,node tot24.js):状态是剩余数字集合,生成是取两个数做一次运算,搜索是逐层扩展并剪掉重复状态:
function solve24(nums) {
const key = st => st.map(x => x.v).sort((a, b) => a - b).join(",");
const seen = new Set();
let layer = [nums.map(n => ({ v: n, expr: String(n) }))];
seen.add(key(layer[0]));
while (true) {
const next = [];
for (const st of layer) {
if (st.length === 1 && Math.abs(st[0].v - 24) < 1e-9) return st[0].expr;
for (let i = 0; i < st.length; i++)
for (let j = i + 1; j < st.length; j++) {
const a = st[i], b = st[j];
const rest = st.filter((_, k) => k !== i && k !== j);
const cands = [
{ v: a.v + b.v, expr: `(${a.expr}+${b.expr})` },
{ v: a.v - b.v, expr: `(${a.expr}-${b.expr})` },
{ v: b.v - a.v, expr: `(${b.expr}-${a.expr})` },
{ v: a.v * b.v, expr: `(${a.expr}*${b.expr})` },
];
if (Math.abs(b.v) > 1e-9) cands.push({ v: a.v / b.v, expr: `(${a.expr}/${b.expr})` });
if (Math.abs(a.v) > 1e-9) cands.push({ v: b.v / a.v, expr: `(${b.expr}/${a.expr})` });
for (const c of cands) {
const st2 = [...rest, c], k = key(st2);
if (!seen.has(k)) { seen.add(k); next.push(st2); } // 剪去重复状态
}
}
}
if (!next.length) return null;
layer = next;
}
}
console.log("4 9 10 13 ->", solve24([4, 9, 10, 13]));
console.log("1 2 3 4 ->", solve24([1, 2, 3, 4]));
console.log("1 1 1 1 ->", solve24([1, 1, 1, 1]));
实测输出:
4 9 10 13 -> ((4-10)*(9-13))
1 2 3 4 -> (4*(3+(1+2)))
1 1 1 1 -> null
第一组正是论文例题的输入,搜出的 ((4-10)×(9-13)) = 24 与论文给出的解法等价;无解的输入会在整棵树遍历完后返回 null。这个演示里「评估」退化为「是否到达 24」,真实 ToT 中评估由模型对每个中间状态打分——评估器的质量直接决定剪枝的准头,也就决定了框架的上限。
图 2:四要素循环转动,直到搜到终局。
代价与适用边界要说透。
ToT 不是免费的午餐:每一层生成 k 个候选再逐个评估,模型调用次数相对 CoT 成倍上涨,延迟和成本都跟着涨。所以它只对「值得搜」的任务启用——需要探索多种可能、需要前瞻几步、早期决策影响全局的任务,如 24 点、创意写作、迷你填字这类论文验证过的场景;简单的算术与常识题,CoT 一次顺推就够,上 ToT 纯属浪费。
回到面试现场,建议的答题结构:先讲 CoT 的线性局限(一步错步步错、无法回溯),再给出 ToT 的形式化——状态是部分解,四要素各司其职,最后落到本质:语言模型被同时用作生成器与评估器,经典搜索算法负责把两者组织成可回溯的推理过程,并主动补一句成本权衡。能把「为什么需要树」讲清楚的候选人,通常也真的理解 CoT 为什么会失效。你在实际项目里用过搜索式的推理框架吗?评估器这一环是交给模型还是写了规则?欢迎聊聊。