第 15 章 · Chain-of-Thought

一笔算错的到岸成本

还是那个卖家。他让 Agent 帮忙估一批货的到岸成本:采购价每件 12 美元,进 800 件,海运费 1900 美元,关税按货值的 6.5% 收,另外还有 3% 的支付手续费。他想知道单件到岸成本是多少,好定零售价。

Agent 张口就来:“大约每件 16.8 美元。”他将信将疑,自己拿计算器一按——不对。追问之下,Agent 才承认:它把关税算在了“采购价 + 运费”的合计上,可关税其实只按货值(采购价部分)收;手续费也漏算了一项。它不是不会算,而是想一步到位,中间几步在脑子里囫囵过了,就错在那几步

后来他换了个说法:“别急着给结果,一步一步把账列出来。”Agent 于是老老实实地算:货值 = 12 × 800 = 9600,关税 = 9600 × 6.5% = 624,运费 1900,小计 = 12124,手续费 = 12124 × 3% ≈ 364,总成本 ≈ 12488,单件 ≈ 15.6 美元。这回对了。

同一个模型、同一道题,区别只在于有没有把推理过程摊开来算。这个“摊开来”的技巧,就是 Chain-of-Thought(思维链,CoT)

CoT 是什么:先展开推理,再给答案

CoT 的核心就一句话:让模型在给出最终答案之前,先把中间推理步骤一步步生成出来。

为什么摊开来就更准?关键在于大模型是逐 token 生成的——它写下的每一个 token,都以前面已经生成的内容为依据。如果它先把“货值 9600、关税 624、运费 1900……”这些中间结果写出来,这些数字就成了后续 token 实实在在的“依据”,相当于给自己搭了一层层脚手架,最后那个总数是踩着脚手架得出来的。反过来,如果它直接跳到“每件 16.8 美元”,等于抽掉了全部脚手架,凭一次性的直觉硬报数字——复杂题目自然容易崩。

所以 CoT 提升的不是模型的“智力”,而是它的“工作方式”:把一次性的猜,变成一步步的推。

CoT 的几种形态

同样是让模型展开推理,触发方式有好几种,术语值得记清楚:

  • Zero-shot CoT(零样本思维链):不给任何示例,只在提示里加一句引导语——最经典的就是“让我们一步步思考(let's think step by step)”,模型就会自动展开推理。成本几乎为零,是最常用的一招。
  • Few-shot CoT(少样本思维链):在提示里给几个“带完整推理过程”的例题,模型会模仿这种解题格式,把自己的推理也照着展开。适合有固定解题套路的任务(比如到岸成本、税费这类计算,给一个算好的范例,后面就照葫芦画瓢)。
  • 内化推理 / 推理模型(reasoning model):现代的一类模型把 CoT “内化”了——你不用提示它,它在输出答案前会自动进行大量内部推理。这部分推理体现为 reasoning token(推理 token):它们真实产生、真实计费,但通常不直接展示给用户,只把结论呈现出来。

CoT 与 ReAct 是什么关系

学到这里你可能会觉得眼熟——第 3 章 ReAct 里的 Thought(推理),不就是 CoT 吗?

它俩确实是近亲,但有一条清晰的分界:

  • CoT 是纯推理的展开,全程在“脑子里”进行,不接触外部世界。它适合那些靠想就能想明白的问题——数学计算、逻辑推导、把复杂需求拆解清楚。到岸成本那道题,模型不需要查任何东西,把账列清楚就能算对,这是 CoT 的主场。
  • ReAct 是“推理 + 行动”交错:想一步、去查一步、看到真实结果再想下一步。它适合那些光想不够、必须够到外部数据的问题——查实时价格、读日志、调接口。

一句话:CoT 是 ReAct 里那个 Thought 的独立强化版。ReAct 用推理来决定“下一步做什么行动”,CoT 用推理直接把答案推导出来。很多复杂 Agent 任务里,两者是叠加的——每一次 Action 之前的 Thought,本身就可以是一小段 CoT。

用 pi 实现:提示引导 vs 推理模型

在 pi 里,CoT 体现在两个层面,正好对应“让普通模型显式思考”和“让推理模型内部思考”两条路。

1. 提示层面——通过系统提示引导模型分步推理。pi 的 system prompt 本身就鼓励模型先规划、再分步执行(第 13 章提过),这就是 CoT 在提示层的应用。你也可以在具体任务里加一句“先把计算步骤列出来,再给结论”,强制它展开。

2. 模型层面——pi 的 pi-ai 包统一了多个 provider,其中不少支持推理模型。这类模型的推理是内建的,还能调节强度:

// 概念示意:选用支持推理的模型,推理由模型内部完成
const response = await ai.complete({
  model: "provider/reasoning-model",
  messages: session.messages,
  // 部分 provider 可配置推理强度:越高,模型内部想得越多、reasoning token 越多、也越贵
  reasoningEffort: "high",
});
// response 里有最终答案,可能还附带一段推理摘要

对使用者来说,这就成了一个明确的取舍:是用提示让便宜的普通模型“显式思考”,还是直接花钱用推理模型让它“内部思考”。前者透明、可控、便宜,推理过程你看得见也改得动;后者省心、通常更强,但 reasoning token 要真金白银地花。到岸成本那种题,普通模型加一句“一步步列账”就够了;真正烧脑的多步推理,才值得上推理模型。第 34 章会讲如何按任务分层选模。

动手看看

拿到岸成本那道题(或任何一道多步计算题),在 pi 里做个对照实验:第一次直接问结果,第二次在问题后面加一句“请先逐步列出计算过程,再给最终答案”。对比两次的正确率和输出长度,你会直观感受到脚手架的作用。

再试第三种:换一个支持 reasoningEffort 的推理模型,不加任何引导语直接问。观察它的答案质量,顺便留意一下这次调用的 token 消耗——那些看不见的 reasoning token,是要计费的。

一个实践提醒:CoT 不是万能药

坑一:简单问题硬上 CoT,纯浪费。

  • 现象:一句话就能答的问题,也让它长篇大论地“一步步思考”。
  • 原因:无差别地给所有任务套 CoT 模板。
  • 对策:只对多步、易错的任务开 CoT;简单问答直接答。

坑二:推理看着漂亮,结论照样错。

  • 现象:模型写出一段逻辑通顺的推理,最后的答案却是错的。
  • 原因:CoT 提升准确率,但推理 ≠ 正确——它可能一本正经地推出错误结论。
  • 对策:该验证还得验证(第 14 章的反思),别因为“它讲得头头是道”就信。

坑三:把冗长推理直接甩给用户。

  • 现象:用户只想要个数字,却收到大段推理过程。
  • 原因:没区分“给模型搭脚手架”和“给用户看结论”。
  • 对策:推理过程通常折叠或隐藏,只把结论呈现给用户;推理模型的 reasoning token 更是默认不展示。

坑四:以为开了推理模型就不用管提示。

  • 现象:换了推理模型,效果没预期好还更贵。
  • 原因:任务本身简单,推理模型的内部推理是浪费;或提示本身没说清楚要什么。
  • 对策:先把任务和提示写清楚,再决定要不要上推理模型;简单任务用普通模型 + 提示引导更划算。

对比:其他框架

CoT 是模型层面的通用技巧,与框架基本无关——任何框架都能靠提示触发,或直接选用推理模型。差异只在“开启/配置推理有多顺手”:

框架CoT / 推理怎么用特点
LangGraph自身不管推理,靠底层 LangChain 配置 reasoning;也可显式建“先推理再答”的节点能把 CoT 变成图上一步
CrewAI给 Agent 配 reasoning 选项,让它执行前先想一轮;backstory 里也可引导分步角色层面开启推理
PydanticAI可透传各 provider 推理设置;强项是推理随意展开、结论必须落到 schema结构化约束结论
Agno把“推理”做成显式能力,支持推理模型,提供 reasoning 开关/工具应用层一键开启
pipi-ai 把各 provider 推理能力(含 reasoningEffort)统一在一个接口下切模型不改业务代码

说到底,各家给的都是同一件事的两条路——提示引导普通模型显式思考 vs 直接用推理模型内部思考,区别只在封装是否顺手。

小结

  1. CoT = 让模型先展开推理、再给答案,逐 token 的特性让中间步骤成为后续生成的“脚手架”,显著提升复杂任务准确率。
  2. 三种形态:zero-shot CoT(加一句“一步步思考”)、few-shot CoT(给带推理的示例)、reasoning model(推理内化为 reasoning token)。
  3. CoT 是 ReAct 里 Thought 的独立强化版:CoT 靠想就能出答案,ReAct 靠想来决定行动——复杂任务里两者叠加。
  4. 两条落地路径:提示引导普通模型显式思考(透明、可控、便宜)vs 直接用推理模型内部思考(省心、更强、reasoning token 要花钱)。
  5. CoT 提升准确率但不保证正确,简单任务别硬上,推理过程通常对用户折叠。

Part 4 到此结束:规划给方向、反思纠错、思维链把单步变多步——都是让单个 Agent 尽可能聪明的功夫。可有些问题,单个 Agent 再聪明也扛不动,得靠多个 Agent 协作。这正是 Part 5 的主题。