第 01 章 · CoT 家族
CoT 家族:推理即算力
起点把六种模式钉在两根轴上;这一章从最基础的 CoT 入手,建立横轴的左半边——串行 token 与并行采样,以及纵轴的上半——内部闭环。
读完本章,你的 schema 里会多出这几条
- 把 CoT 看成「给固定深度的模型补串行计算步数」——每个吐出的 token 是一步额外计算,不是装饰文字。
- 分得清 zero-shot CoT(一句"step by step")与 few-shot CoT(示例里写满推理步骤)的成本与触发条件。
- Self-Consistency = 并行采样 N 条链、对最终答案投票——横轴从「串行 token」迈到「并行采样」的第一步。
- 一段 CoT 可能不忠实(faithfulness):写出来的链条不等于模型真实的计算路径,可能是事后编的——这正是纵轴「内部闭环没有真值校验」的病灶,直接引出第 2 章。
起点立了一条贯穿全教程的断言:每一种推理模式都用推理期算力换单次前向传播给不了的可靠性。这句话听上去抽象。本章用 CoT 把它落到实处——CoT 是这条断言最干净的实例,也是后面所有模式的地基。横轴的最左端(串行 token)、纵轴的最上沿(内部闭环、无外部校验)都在这一章成形。
1.1Chain-of-Thought:把 token 流当算力
在 few-shot 示例里写出中间推理步骤,模型解新题时会照着先写步骤再给答案——纯 prompt 技巧,不改模型权重、不改解码方式。
一道两位数乘法、一道多步应用题,直接问 GPT-3 经常错。不是模型「不会」,是它被逼着在一次前向传播里既算完中间过程、又吐出最终答案。一次前向传播的计算深度是固定的(层数固定);步骤一多,固定深度装不下,于是它跳步、拍脑袋。CoT 做的事很朴素:把中间步骤显式写进 token 流,让模型一步一步往外写,用 token 数换计算深度。
底层机制:token 流是「展开的递归」
这里要比官方文档深一层。文档说 CoT「让模型 step by step 地想」——这是结果,不是机制。机制是这样的:
一个固定层数的 Transformer,对单个 token 位置做的运算,计算复杂度类属于很弱的一档——理论上接近 AC⁰(常数深度的布尔电路类),连「可靠地跟踪一个会随步数变化的状态」这种迭代任务都做不稳(Merrill & Sabharwal, 2310.07923)。换句话说,单次前向传播的「想」是有硬上限的,再大的模型也搬不动这堵墙——墙的位置由架构定,不由参数量定。
关键转折在自回归:每吐出一个 CoT token,这个 token 立刻被拼回输入,模型重新跑一次前向传播。于是 token 流不是一句话,而是一条串行计算链——第 T 个 token 的计算,能用上前面 T-1 个 token 写下的所有中间结果。写 T 步 CoT,约等于让模型模拟一个规模为 T 的电路;步数 T 随题目长度多项式增长时,可达到的计算类从 AC⁰ 一路抬到 P(多项式时间可解,Feng et al. 2402.12875)。这是「多写 token 真能提升正确率」唯一站得住的解释:token 是被借来的串行计算步数。
场景走查:一道 GSM8K 式应用题
题目:果园里 3 行树、每行 7 棵;摘走 5 棵后,又补种 12 棵。现在多少棵?
直接答(无 CoT)。模型在一次前向传播里要一口气算完 3×7、再减 5、再加 12,还要把这一连串中间值压进固定深度——很容易吐出一个看着合理的错数,例如脱口而出「30」。没有任何中间值落到 token 上,错在哪无从查。
写出步骤(CoT)。逐句标注每一句对应的「一步串行计算」:
原有:3 行 × 7 棵 = 21 棵 ← 串行步 1:算总数,21 落到 token 上
摘走:21 − 5 = 16 棵 ← 串行步 2:用上一步的 21,减 5
补种:16 + 12 = 28 棵 ← 串行步 3:用上一步的 16,加 12
答案:28 棵 ← 抽取,复用步 3 的结果
每一步都把一个中间值写成 token,下一步的前向传播直接读它,不必在固定深度里重算。三步串行做完,答案稳定为 28。这就是图 1.1 右半边在一道真题上的样子。
实证:涌现,不是「越大越好」那么简单
CoT 原始论文(Wei et al. 2022, 2201.11903)的招牌数字:PaLM 540B 在 GSM8K(小学数学应用题)上,标准 prompt 只有 17.9%,加 8 个带推理步骤的 few-shot 示例后跳到 56.9%,超过了当时「fine-tuned GPT-3 + 训一个验证器」的约 55%。一个 prompt 技巧打平了一整套微调流水线。
CoT 不是对所有模型都有正收益。在约 10B 参数以下的模型上,加 CoT 反而掉分——小模型写出的中间步骤逻辑不通,等于往输入里灌噪声。只有当模型规模够大、单步质量足够高时,「多写一步」才真的多算一步、而不是多错一步。CoT 是一种涌现能力:能力到了门槛才解锁,没到门槛是负担。这条直接反驳「加了 CoT 一定更好」的 2022 式直觉,也为第 4 章「推理模型上手写 CoT 反而掉分」埋了第一根线。
同一个 540B 模型、同一道两位数乘法题,把 CoT 示例里的中间步骤全部删成「答案是 X」(只留输入输出、不留推理过程),正确率会怎样?为什么?
展开
会掉回接近无 CoT 的水平。删掉中间步骤,就是把图 1.1 右半边的串行链砍回左半边那堵固定深度的墙——模型又得在一次前向传播里算完全部中间过程。few-shot 示例之所以有效,关键正是示例里写出来的那几步推理,不是「给了几个例子」这件事本身。这也预告了 §1.4:如果链条的内容无关紧要,那它八成没在真的参与计算。
把 CoT 当作 prompt 技巧的更广写法(few-shot 模板、结构化输出、示例排序),在 prompt-engineering · 思维链 有系统展开;本章只取「token = 串行算力」这一条机制线。
1.2Zero-shot CoT:一句咒语,两次调用
不给任何示例,只在问题后接一句「Let's think step by step」,模型就会自己生成推理步骤——但抽答案要再调一次,实为两阶段、两次 LLM 调用。
few-shot CoT 要为每类任务手写示例——数学题一套、逻辑题一套,又贵又难维护。Kojima et al. 2022(2205.11916)发现:一句固定的「Let's think step by step」就能触发同一条串行展开机制,无需任何示例。零示例,零任务定制。
底层机制:两阶段,不是一次
名字叫 zero-shot,但它在工程上是两次前向调用,常被忽略:
- 推理阶段:prompt = 问题 +「Let's think step by step」,模型生成一整段推理文本(这段就是借来的串行算力)。
- 抽取阶段:把第一阶段的输出再拼上「Therefore, the answer is」喂回去,让模型从自己刚写的推理里抽出最终答案。
为什么要分两次?因为模型自由发挥写完推理后,答案藏在一段自然语言里,格式不定,得再调一次把它「逼」成可解析的形式。代价随之而来:延迟和 token 成本翻倍;抽取阶段本身可能失败(模型推理写对了,最后一步却抽错数)。
招牌数字(text-davinci-002):MultiArith 17.7% → 78.7%,GSM8K 10.4% → 40.7%。一句话量级的改动换来几倍正确率,但要记住这「一句话」背后是两次调用。
把 zero-shot CoT 压成一次调用——直接在 prompt 里写「step by step 地想完后,最后一行只输出数字」——和标准两阶段相比,最可能出什么问题?
展开
省了一次调用、省了成本,但抽取的稳健性下降:模型一边自由展开推理、一边还要约束最后一行的格式,两个目标互相干扰,时常要么推理被格式带跑、要么最后一行没守住约定。两阶段把「自由推理」和「受约束抽取」拆开正是为了避免这种互相打架——这也呼应 §1.4 的发现:约束施加在哪个 token 上,会真切影响推理质量。生产里常用折中:一次调用 + 要求结尾输出 JSON,靠正则兜底解析。
1.3Self-Consistency:横轴迈向并行采样
对同一道题用温度采样跑出 N 条不同的 CoT,只取每条的「最终答案」做多数投票,推理文本本身丢弃——横轴从「串行 token」迈到「并行采样」的第一个点。
单条 CoT 是一条路走到黑:某一步采样偏了,整条链跟着错,且模型对错误答案常常一样自信。Self-Consistency(Wang et al. 2022, 2203.11171)赌的是:通往正确答案的推理路径有很多条、彼此独立,会在最终答案上撞到一起;通往各种错误答案的路径则各错各的、票数分散。采样多条、对终点投票,正确答案因「殊途同归」浮上来。
底层机制:在最终答案上边缘化,而非选最佳链
这是最容易记错的一点:Self-Consistency 不是挑一条「看起来最好的链」,而是把每条链的推理文本扔掉,只保留它得出的最终答案,再对这些答案数票。用概率的话说,它在「最终答案」这个变量上做边缘化——把同一个答案下千差万别的推理路径全加到一起,等价于在问「哪个答案被最多条独立路径支持」。链条只是到达答案的载具,投票投的是终点。
场景走查:续上那道果园题
对果园题(正确答案 28)跑 5 条采样链,正是图 1.2 的内容:3 条算出 28,1 条某步乘错得 30,1 条漏了补种得 16。三种错法没撞到一块儿、各 1 票,正确答案 28 拿 3 票胜出。哪怕单条链只有六成把握,多条独立链一投票,整体准确率被显著抬高。在 PaLM 540B 上,Self-Consistency 把 GSM8K 又往上推了约 +17.9 个百分点(在 CoT 之上叠加)。
成本是 N 倍 token:跑 5 条就是 5 倍推理开销,40 条更夸张。只对可抽取、可投票的答案有效:数学题(一个数)、分类(一个标签)能投票;开放生成(写一段摘要、出一段代码)没有「同一个答案」可数,投不了票。收益递减:多数题在约 5–10 条后曲线就平了,继续加链只烧钱不涨分。这三条共同决定了它在横轴上的定位——比 CoT 贵一档,且适用面更窄。
把 Self-Consistency 直接套到「为这篇文章写一句话标题」这种开放生成任务上——采样 10 条标题,然后呢?会卡在哪?
展开
卡在「无法投票」。10 条标题措辞各不相同,没有两条字面相同的「最终答案」可以数票,多数投票直接失效。开放生成只能换思路:要么定一个评分标准、用模型或规则给 10 条打分选最高(这就滑向第 3 章 ToT 的评估器,而评估器恰恰是真正的难点);要么先把任务转成可投票形式(如先抽取关键信息点、对信息点投票)。Self-Consistency 的适用边界,正卡在「最终答案能不能被离散地数票」这条线上。
1.4Faithfulness:写出来的链,未必是真算的那条
忠实性(faithfulness)指模型写出的 CoT 是否真实反映了它得出答案的计算过程——很多时候不是:链条是事后给已定答案编的理由。
前三节默认「写出来的链 = 模型真在算」。一旦这个默认成立得不牢,CoT 的可信度就出现裂缝:链条看着步步在理,却可能是模型先有了答案、再倒着编出来骗你的。而 CoT 整条循环没有任何外部真值来校验这段推理——这就是纵轴最上沿「内部闭环」的病灶,也是把第 2 章 grounding 逼出来的直接动因。
两个反例:链条看着对,其实是事后合理化
Turpin et al. 2023(2305.04388)——植入偏置。在 few-shot 示例里动手脚:把所有示例的正确答案都摆成选项 (A)。模型接收到这个隐藏规律后,在新题上会默默偏向 (A),并为这个被偏置的答案一本正经地编出 CoT 理由——全程只字不提「我是因为前面答案都在 A 才选 A」这个真实原因。这类偏置使某些任务正确率最多掉 36%,而写出来的链条读起来毫无破绽。链条解释的是一个体面的假理由,真实动因被藏起来了。
Lanham et al. 2023, Anthropic(2307.13702)——干预链条看答案会不会变。做了两类干预:early answering(推理只截断到一半就逼它给答案)和 adding mistakes(往链条里掺进一处错误再让它接着推)。如果链条真在驱动答案,干预后答案应当随之改变。结果分裂成两类任务:在真靠推理的任务(AQuA、LogiQA 这类多步数学/逻辑)上,干预让答案改变 >26%——链条确实在算;而在事后合理化的任务(ARC、OpenBookQA 这类常识问答)上,答案改变 <10%——模型其实已经知道答案,链条只是装点门面。
filler 之争:内容到底重不重要
既然链条有时只是装点,那干脆用无意义符号占位、只保留「多花算力」这件事,行不行?两篇结论相反,但合起来才是完整答案:
- Lanham 2023:把 CoT 整段换成等长的「
...」填充符(只占 token、无内容),收益归零。结论:对真靠推理的任务,关键不只是「多占了 token」,token 里写的内容本身在参与计算。 - Pfau et al. 2024(dot-by-dot):在专门构造的任务上,纯 filler token(一串「.」)确实能让模型解出原本解不了的题——但仅对特定结构有效(如量词嵌套深度低的一类问题),且需要专门训练才能利用上这种「空算力」。
把两者拼起来:filler 能提供的,只是一点点「额外的并行算力槽位」,对绝大多数真正串行的推理远远不够;一旦任务需要把第 2 步的结果喂给第 3 步,token 里写的内容就不可替代。所以面对真串行推理,CoT 的内容是重要的——这反过来印证:当链条内容可以随意替换却不影响答案时(§1.4 开头那种事后合理化),它多半没在真的算。
还有一个反直觉:忠实度逆向 scaling
Lanham 还测到一条「逆向 scaling」:在 8 个任务里的 7 个上,13B 模型比 175B 模型的 CoT 更忠实。直觉会说大模型更靠谱,但更大的模型恰恰更可能「不靠写出来的链就已经知道答案」,于是那段链更像事后补的合理化。这条和 §1.1 的涌现是同一枚硬币的两面:能力随规模上去,但「链条忠实地反映计算」这件事并不跟着一起变好——它是独立的一维,不能拿能力强弱去推断。
结论收束到纵轴:CoT 这一整套——zero-shot、few-shot、Self-Consistency——都是内部闭环,循环里没有任何外部真值能告诉模型「你这步算错了」「你这个事实记错了」。链条不忠实时,它会带着一脸笃定把你引向错处,而你从链面上看不出破绽。要打破闭环,只有一条路:把推理的某些步骤钉在外部可验证的反馈上。那正是第 2 章 grounding 要做的事。
一个客服 agent 用 CoT 回答「我这张订单为什么被取消」,链条写得井井有条、结论笃定。为什么哪怕这段 CoT 读起来完全合理,也不能当成答案可靠的证据?要补上什么才靠得住?
展开
因为 CoT 是内部闭环:那段链可能完全是模型基于先验「编」出的合理化(图 1.3),订单系统里的真实取消原因它根本没看过,却能写出一套自洽叙事——faithfulness 无从保证。要靠得住,必须把推理钉到外部真值上:让 agent 真去查订单系统/退款记录,把查到的字段作为 observation 喂回,推理基于这个 observation 而非凭空想象。这一步「查一下再说」就是 grounding,正是第 2 章 ReAct 的核心。
✓自测 & 挑战
合上前三节,先自己答,再展开对照。第 4 题是设计层。
-
一句话讲清:为什么「在 CoT 里多写几个 token」能提升正确率?不许用「让模型想清楚一点」。
参考答案
一次前向传播的计算深度由层数固定(弱到接近 AC⁰),多步推理装不下。每吐出一个 CoT token 就被拼回输入、触发一次新的前向传播,于是 token 流变成一条串行计算链:第 T 步能复用前 T-1 步写下的中间结果。T 步 CoT ≈ 模拟规模为 T 的电路,多项式步数把可达计算类从 AC⁰ 抬到 P。token 是借来的串行计算步数,不是修辞。
-
Self-Consistency 跑了 5 条链,得到答案 [28, 28, 30, 28, 16]。它输出什么?它是「选了最好的那条链」吗?
参考答案
输出 28(3 票多数)。不是选最佳链——所有推理文本读完即弃,只把每条的最终答案拿来数票,在「最终答案」上做边缘化(同一答案下的不同路径全加到一起)。投的是终点,不是过程。
-
「我读到一段逻辑严密的 CoT,所以模型确实是这样一步步算出答案的。」这句话哪里错?引一个反例。
参考答案
错在把「链条读着对」当成「模型真这样算」的证据——这正是 faithfulness 缺口。Turpin 2023:示例答案全植入为 (A),模型默默选 (A) 却编出一套与真因(位置偏置)无关的体面理由,正确率最多掉 36%,链面无破绽。或 Lanham 2023:常识问答里截断/掺错链条,答案改变 <10%,说明链是事后合理化、没在驱动答案。
-
(设计层)给出一个具体场景:用 CoT 是错的选择,会主动帮倒忙。说清为什么。
参考答案
至少两类。(a) 小模型 + 复杂推理:约 10B 以下模型加 CoT 会掉分——单步质量不够,写出的中间步骤逻辑不通,等于往输入灌噪声(§1.1 涌现)。(b) 答案依赖外部当前事实:如「这张订单为何被取消」「这只股票今天的价」。CoT 是内部闭环、无外部真值校验,会基于先验编出一段笃定却可能与事实不符的链(faithfulness)。这种场景该用 grounding(第 2 章 ReAct)而非更长的 CoT。也可提第 4 章伏笔:在 o1/R1 这类已把 CoT 训进权重的推理模型上,再手写 few-shot CoT 反而掉分。
设计一个实验,判断你手上这段 CoT 到底忠不忠实
给定一个黑盒 LLM 和一类任务,你只能改 prompt、看输出,拿不到内部权重或注意力。设计一套可操作的实验,判断模型在这类任务上写的 CoT 是「真在驱动答案」还是「事后合理化」。要给出至少两种相互独立的探针,并说明各自的「忠实 / 不忠实」判据。
提示(卡住再看)
核心思路:干预链条,看答案变不变——若链条真在算,扰动它应当改变答案。复刻 Lanham 的两把探针:early answering(把 CoT 截断到不同比例就逼答案,画「答案随截断位置的变化曲线」——忠实任务应随截断剧烈改变,不忠实任务很早就锁定);adding mistakes(往链条某步注入一个明确错误再让它续推,看最终答案是否跟着错——跟着错=忠实,照旧=链条没在驱动)。第三把可借 Turpin:植入偏置(如示例答案全设为某一选项),看模型是否默默偏向该选项、且 CoT 是否对此只字不提——若是,则不忠实。要点:把「忠实」操作化成「对链条的扰动能否传导到最终答案」这一可测量的因果判据,而不是靠肉眼读链顺不顺。