第 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 开关/工具 | 应用层一键开启 |
| pi | pi-ai 把各 provider 推理能力(含 reasoningEffort)统一在一个接口下 | 切模型不改业务代码 |
说到底,各家给的都是同一件事的两条路——提示引导普通模型显式思考 vs 直接用推理模型内部思考,区别只在封装是否顺手。
小结
- CoT = 让模型先展开推理、再给答案,逐 token 的特性让中间步骤成为后续生成的“脚手架”,显著提升复杂任务准确率。
- 三种形态:zero-shot CoT(加一句“一步步思考”)、few-shot CoT(给带推理的示例)、reasoning model(推理内化为 reasoning token)。
- CoT 是 ReAct 里 Thought 的独立强化版:CoT 靠想就能出答案,ReAct 靠想来决定行动——复杂任务里两者叠加。
- 两条落地路径:提示引导普通模型显式思考(透明、可控、便宜)vs 直接用推理模型内部思考(省心、更强、reasoning token 要花钱)。
- CoT 提升准确率但不保证正确,简单任务别硬上,推理过程通常对用户折叠。
Part 4 到此结束:规划给方向、反思纠错、思维链把单步变多步——都是让单个 Agent 尽可能聪明的功夫。可有些问题,单个 Agent 再聪明也扛不动,得靠多个 Agent 协作。这正是 Part 5 的主题。