如果你最近翻过任何一个Agent开发教程,大概率会反复撞见一个词:思维链。不少人一听“思维链”,以为是什么高深算法,实际上把它拆开来看,就一句话:让模型把推理过程一步步写出来。这个“把过程写出来”的动作,正是当下几款主流大模型在做多步推理时共同依赖的底层思路。无论你是用哪家厂商的接口做开发,无论你是走提示词调优还是搭Agent框架,思维链(Chain-of-Thought,简称CoT)都是绕不开的关键词。
我今天想聊的,不是再抄一遍提示词模板,而是站在程序员的视角,把思维链是什么、为什么有效、怎么封装进Agent流程、以及我在实际项目中踩过的坑一次讲透。文章末尾还附了几个可以直接拿去改的骨架,希望能帮你少走弯路。
这个技巧适合谁?准备用大模型接口做Agent、做自动化分析、做代码辅助的同学;被“模型答非所问”折磨到怀疑人生的提示词工程师;以及所有想搞明白“多步推理到底是怎么一回事”的开发者。下面的内容不需要你有数学基础,只需要你写过几行代码。
1. 从一个反直觉的现象说起:让模型“多说话”,准确率反而猛涨
1.1 模型不是“思考”,而是在“续写”
很多开发者的痛点是:问大模型一道简单的应用题,它给你一本正经地胡说八道。比如“有三种颜色的球,红的数量是蓝的两倍,蓝比绿多3个,绿有5个,红几个?”模型直接回答“10个”,过程理直气壮,结果大错。
要理解为什么会这样,先得接受一个底层事实:大模型本质上是一个“续写器”。它每一步都在根据前面的文字预测下一个最可能出现的字——就像输入法里的联想。没有中间过程约束时,模型答这种题,依靠的并不是“算数能力”,而是从训练数据里找相似模式和最顺嘴的下文。问题稍加变化,它就开始编。
这个现象和键盘输入法的联想很像:输入“今天天气_”,它大概率接“真好”,但如果你让它做一道两步计算题,它没有草稿纸,就只能靠语气和句式把答案“猜”出来。
1.2 思维链的定义:把“草稿纸”交还给模型
思维链的做法简单到令人怀疑:不要直接要求模型给答案,而是要求它“先写推理过程,再给结论”。这条提示词可能长这样:
问题:红球是蓝球的2倍,蓝球比绿球多3个,绿球有5个,请问红球有几个? 请一步一步地思考,最后以“最终答案:”结尾。模型就会输出类似“绿球=5,蓝球=5+3=8,红球=8×2=16,最终答案:16”。准确率一下就上去了。
这个术语背后有更系统的表达:CoT将复杂问题拆分成多个中间子步骤,每一步的结论作为下一步的输入,形成一个可见的推理链。它分成两种常见形态:零样本CoT(Zero-shot CoT,即在提示词里直接要求模型逐层推理)和少样本CoT(Few-shot CoT,即在提示词中放一两个示例,让模型模仿示例的过程再做题)。标题里说的“多步推理黑科技”,其实就是这个。没有魔法,就是草稿纸。
1.3 为什么“外部草稿纸”能带来质变
你可能想问:让模型多写几个字,为什么准确率变化这么大?
我给一个工程上的直觉解释:模型的隐状态本身是有限带宽的。它内部一次前向计算能容纳的信息量,远小于我们以为的那么多。当模型试图在内部“心算”一个多步问题,较早的中间结果很容易被后续的信息冲掉——可以说它的工作记忆太短了。
而思维链把中间步骤写入生成的token里,等于把中间结果保存到一个外部可读取的“草稿纸”上。每一步都再读一遍之前写下的内容,再把新结果追加进去。这和人类做题需要草稿纸的理由几乎一模一样:外部存储减轻了工作记忆负担。
所以你看,CoT本质上不是魔法,而是给模型扩了一条外部记忆通道。这也是为什么它和多步推理、Agent两个词总被放在一起:因为Agent面对的真实任务,往往需要多轮计算、查询、对比,比一道应用题复杂得多。思维链是让这种复杂流程“化整为零”的基础结构。
2. 从一句提示词到Agent循环:思维链如何变成真正的“多步推理系统”
2.1 基础CoT提示词的正确封装方式
一段正经的CoT提示词,不只是加一句“请逐步思考”。更稳定的写法是给模型一个明确的结构约束。我平时在项目里用的初始模板大概是这样的:
你是问题求解器。请按以下步骤处理用户的问题: 1. 列出问题中的已知条件。 2. 判断需要用到的公式或策略。 3. 代入数据并逐步计算。 4. 检查结果是否符合常识。 5. 最后输出“最终答案:”。 请把你的每一步推理过程写出来。 问题:___为什么不直接写“请仔细思考”?因为实测下来,这种模糊指令容易让模型输出一大段正确但无用的废话。只有“列出已知条件、判断策略、代入计算、检查、给出结论”这种具体的动作序列,才能迫使模型每一步都落在可验证的信息上。你可以把这段模板理解成给模型定义的一个“小流程”:先收集条件,再锁定公式,逐步执行,最后复核。
2.2 从“一次性生成”到“多轮循环”:ReAct 模式
实际项目中,大部分问题光靠一个大模型自说自话解决不了。比如你让Agent查某商品的历史价格再给出未来走势预测,模型必须先去数据库检索,拿到数据后计算,再形成结论。这时候“生成一段推理”做一次就远远不够了。
业界通常把思维链再往前推一步,变成一种交替结构:Reason(思考)和 Act(行动)循环。每一步先思考当前状态,然后决定采取什么动作(比如调用一次搜索、查询一个数据库、执行一段代码),看到动作的返回结果后,继续思考下一步。
这个模式从逻辑上看,就是把思维链从“纯文本推理”变成了“决策-执行-观察-再决策”。CoT是它的推理内核,工具调用是它的行动外壳。这个循环结构,才是标题里提到的Agent多步推理的真正含义。
2.3 一个可以直接参考的Agent循环骨架
下面给出我早期项目的Python骨架,代码故意写得很直白,方便看清楚“思考-行动-观察”三个环节怎么串起来:
import json def run_agent(task, max_rounds=5): messages = [{"role": "system", "content": "你是一个任务助手。每次回复必须输出JSON,包含thought/action/action_input/answer字段。若任务已完成,直接输出answer。"}] history = [] rounds = 0 while rounds < max_rounds: rounds += 1 resp = llm_complete(messages + [{"role": "user", "content": task + "\n历史:" + json.dumps(history)}]) parsed = json.loads(resp) if parsed.get("answer"): return parsed["answer"] if parsed["action"] == "query_tool": observation = query_tool(parsed["action_input"]) elif parsed["action"] == "calc": observation = str(eval(parsed["action_input"])) # 仅做演示,生产环境务必用安全沙箱 else: observation = "不支持的动作,请改用其他方式" history.append({"thought": parsed["thought"], "action": parsed["action"], "observation": observation}) return "达到最大轮次,任务未完成"你不用照抄,关键点是:模型每次输出的thought就是思维链的一句中间推理,action是下一步的意向,action_input是工具入参,observation是工具返回结果——下一个循环再把这些历史信息一起喂回去。
这里有个细节值得注意:为什么要求模型输出JSON而不是纯文本?因为程序要解析动作和入参。纯文本虽然人看着舒服,但程序鲁棒性很差,一旦模型多写一句“下面开始执行”,提取动作就会崩。JSON格式的多步推理,是工程上更稳妥的契约。
3. 实测对比:有思维链和没有思维链,差别到底有多大
3.1 同一个逻辑题,三种提示方式的对比
为了把“差别大”这个结论落到数据上,我在一个内部模拟项目X里做过一个小实验。题目就是我前面说的红蓝绿球问题,分别用三种提示方式询问。
| 提示方式 | 模型输出特征 | 结果 |
|---|---|---|
| 直接提问 | 语气肯定,直接给出答案 | 错误(答案记为10) |
| 加“请逐步思考” | 输出一步接一步的推理,偶尔逻辑跳跃 | 正确 |
| 加结构化流程模板 | 每一步按模板展开,结论稳定 | 正确,且复现率高 |
三次实验里,第二个和第三个方案都答对了。区别在于第二种方式如果换个提问角度(比如加很多干扰信息),容易在中间步骤跳步;第三种方式把过程拆得细,抗干扰更强。
我真正想强调的是:在很多中等难度的推理任务上,无CoT和有CoT的差距,可能不是5个点,而是30到50个点。尤其当问题包含多个条件、需要代入计算时,直接给答案的失败率会迅速上升。如果你觉得“加个思考过程没什么用”,多半是任务本身太简单了——对简单任务确实提升有限。
3.2 不同模型的CoT敏感度差异
需要提醒的是,不同厂商的大模型对CoT提示词的敏感度不一样。我在项目里测过几款主流模型:有的模型只需要一句“请一步步思考”就能稳定触发多步推理;有的模型即使给了详细模板,也可能输出格式跑偏,需要补上少样本示例才能稳定。
这意味着什么?你千万不要假设“同一个CoT模板在所有模型上效果一致”。团队做技术选型时,应该把“CoT稳定性”当成一个评估维度:连续跑若干个需要多步推理的测试集,看模型是不是总能在指定格式内输出,会不会中途自说自话。我见过不少项目,因为换了一个模型,原来辛苦调好的思维链提示词直接失效,这类坑越早发现越省事。
3.3 关键参数调优:temperature 与 max_tokens
CoT的效果高度依赖两个参数。
第一是temperature。做多步推理时,我通常把temperature调到0到0.3之间。逻辑推理任务要求确定性,temperature太高,模型每一步都更“放飞”,中间步骤容易变异想天开。但也不要无脑设成0,某些场景下过低的temperature会让模型倾向于安全回复,反而跳过推理过程,直接给出一个看似合理的答案。
第二是max_tokens。CoT会显著增加输出长度,如果max_tokens开太小,推理写到一半就被截断,模型可能给出半成品甚至错误结论。我的经验是:普通问答给256到512个token,涉及CoT的复杂任务至少给1024个token以上。如果你发现模型总是“戛然而止”,先检查是不是max_tokens不够,而不是怀疑提示词。
4. 思维链在实际项目里的落地形态:三个可以直接抄走的场景
4.1 代码缺陷排查:让模型先定位再解释
很多团队把大模型接进代码审查流程,最典型的问题是:模型报了一大段错误,但没定位到关键行。我在某内部项目里试过,给提示词加一个CoT强制结构,把“检查代码语义-列出可疑点-定位根因-给出修复建议”四步拆开,效果明显好于直接问“这段代码有什么问题”。
示例提示词:
请对以下代码执行缺陷分析。 分析步骤: 1. 阅读函数逻辑,列出它实际做的每一件事。 2. 对比输入输出特征,列出不符合预期的地方。 3. 对每个可疑点,解释它为什么可能导致问题。 4. 定位你认为最可能的一个根因,并给出修复建议。 代码开始: ...你会发现模型输出的内容更长,但信息密度高很多。它不会只丢给你一句“可能有空指针”,而是把调用链、变量可能的取值、触发条件连起来讲,这对开发者快速判断“是否误报”非常关键。
4.2 数据计算与统计:先列公式再代入
另一个高价值场景是数值计算。直接问“上月销售额比上上月增长了多少”,模型很容易在百分比上翻车。用CoT提示词,要求它“先明确原始数据-列出计算公式-代入数据-计算结果”,准确率会大幅提高。
我在一个数据看板项目里封装了这类提示词:模型遇到所有数值问题,都先输出公式再计算。这样即使最终结果算错,人也能从中间过程里看出是哪一步的数据取错了,方便人工修正,而不是拿到一个彻底无法解释的随机数。
4.3 Agent工具调用的结构化输出:JSON形态的思维链
Agent场景里,思维链不应该只存在于给人看的文本中,更应该以结构化形式让程序能消费。我早先项目里使用的格式是:
{ "thought": "当前需要先获取用户最近的订单列表", "action": "query_orders", "action_input": {"user_id": "u_123", "limit": 5} }action表示工具名称,action_input表示工具入参,thought对应模型此刻的推理判断。整个多轮循环中,每一轮都会产生一条这样的JSON记录。把这些记录串起来,就是完整的“思维链”,而且程序可以直接读取、展示、回放,做故障定位的时候尤其方便。
实现时有一个细节:要在System提示词里把“能用的工具列表和入参格式”写清楚,让模型每次只选择一个能匹配工具的动作。否则模型会自己发明不存在的工具名,或者入参格式不符合预期,循环直接卡死。
5. 思维链的坑,我替你踩过了
5.1 推理链太长,模型反而“绕晕”
CoT不是越长越好。我遇到过不少情况:问题本身三步能算完,模型却输出二十步“分析”,中间开始自我纠结,最后推导出一个错误答案。这和人一样,草稿纸写太乱,反而容易出错。
应对办法有两个。一是给提示词里加一个“保持简洁”约束,比如“请用不超过5个步骤完成推理”;二是在Agent循环里设置最大轮次,超过就直接终止并返回当前结果,避免模型在错误路径上越走越远。
5.2 中间步骤可能是“幻觉推理链”
这是最需要警惕的一点:模型输出的推理过程,并不保证和结果因果一致。它完全可能先猜到正确答案,然后反过来编造一套看起来合理的中间步骤;也可能中间步骤每一步都合理,最后结论却错得离谱。换句话说,思维链的正确性不等于推理链的事实性。
注意:如果任务对可解释性要求很高,比如医疗、金融报告场景,建议增加一道验证环节。拿到最终答案后,用一个独立校验提示词让模型重新检查中间步骤和结论的一致性,或者接入规则校验工具,比如计算结果用计算器校验一遍。把“模型说的过程”当成辅助信号,而不是事实依据。
5.3 Token成本翻倍:不是所有请求都该启用CoT
CoT意味着每次请求会多消耗几百甚至上千token,在高频接口下成本上涨很明显。我的做法是做一个简单的分流策略:简单任务直接回答,不启用CoT;只有判断任务需要多步推理时才走CoT链路。
判断可以很粗糙:先看用户输入里是否包含多个条件、是否涉及计算或查询动作,也可以用一个小模型做一次分类。这个混合策略我实测过,能在保持准确率的同时,把平均成本压回接近原来的水平。
5.4 Agent循环里的死循环
多轮CoT最典型的工程故障是死循环:模型反复执行同一个工具,每次观察结果都一样,但它就是不肯停下来。原因可能是提示词里的终止条件写得太模糊,也可能是工具返回的信息没有变化,模型以为需要再来一次。
解决方案很直白:设置最大迭代次数(我一般设5到8次);对所有工具调用做去重,如果某工具在相同入参下被调用了两次,在历史里强制提示“该动作已执行过且结果未变化,请更换策略”;规定模型如果连续三次输出相同thought,就必须结束任务。把这些规则写进System提示词后,死循环概率骤降。
5.5 不同模型的“内隐思维链”差异
还有一类坑藏在接口层。一些大模型可能在内部已经内置了类似CoT的推理机制,或者提供了开关类的参数。你在一个模型上不写CoT提示词,它也能做多步推理;换到另一个模型上不写就完全不行。反过来,某个模型如果已经开启内置思考,你又在外层套CoT提示词,输出可能会变得冗长啰嗦。
所以每接一个新模型,必须做一次基线测试:同一批任务,分别在“无CoT提示词”“加CoT提示词”“开启内置思考参数”三种配置下跑一遍,记录准确率、延迟和成本,再决定线上用什么组合。别偷懒,这一步能省掉后面排查故障的大量时间。
6. 我选场景的标准与成本预算参考
6.1 值得启用CoT的任务特征
不是所有任务都要用思维链。我的筛选标准是三条:
- 任务有多个推理步骤,环环相扣;
- 步骤之间存在依赖关系,前一步的输出会作为后一步的输入;
- 用户需要“结果”之外的解释,或者系统需要记录决策过程。
符合这三条的任务,比如数学计算、代码定位、数据分析、多工具Agent,优先启用CoT。不符合的任务,比如纯情感分类、简单意图识别、直接查询知识库返回结果的场景,用CoT只会平白增加延迟和成本,收益很小。
6.2 成本预算参考
假设你使用的是一个中端定价的大模型接口,单次普通问答消耗约300 token,加入CoT后可能到800到1500 token。以下是我在模拟项目X里统计的粗略参考值:
| 任务类型 | 是否CoT | 平均输出token | 相对耗时 | 建议 |
|---|---|---|---|---|
| 情感分类 | 否 | 50 | 低 | 不开CoT |
| 简单问答 | 否 | 150 | 低 | 不开CoT |
| 数学/逻辑题 | 是 | 700 | 中 | 开CoT |
| 代码缺陷定位 | 是 | 1200 | 中高 | 开CoT |
| 多工具Agent任务 | 是 | 2500+ | 高 | 开CoT,但设轮次上限 |
具体价格会随模型不同而浮动,但比例关系大致如此。做容量预估时,可以按“CoT请求占全部请求的比例”来测算,比如全部请求的20%走了CoT,你的token消耗大约要乘以1.5到2倍。
6.3 最后说一点体会
思维链这个技术,名字听起来唬人,实际上就是一套“把推理显式化”的办法。它在工程上的价值,远远不止提高一道数学题的准确率,更关键的是它让Agent的每一步决策都变得可见、可解析、可干预。你可以在它的任意一环插入工具调用,可以在出问题时回放整个推理路径,也可以限制它的轮次防止跑飞。这种可观测性,才是它被这么多Agent框架选为底层结构的原因。
我个人的经验是:上手不需要什么顿悟,随便找一个你觉得模型答得不够好的小任务,加一句“请逐步推理”,把中间过程打出来看一遍,再根据失败模式逐步修正。这才是这道“黑科技”最朴素也最快的入门方式。项目里真正需要打磨的,其实不是你懂不懂CoT,而是你愿不愿意把它当成一份需要反复调试的工程流程来对待。对我来说,把每个失败的中间步骤当成线索去修,比掌握再多的提示词模板都管用。