ReAct 与思维链结合:让 AI Agent Harness Engineering 推理能力翻倍的进阶技巧
1. 标题 (Title)
ReAct × CoT 进阶指南:让 AI Agent 工程推理力突破天花板的落地方法论告别“试错式Agent”:拆解 ReAct + 思维链的 Harness Engineering 高阶玩法从 CoT 到 ReAct 再到 ReCoT:AI 工程推理能力翻倍的完整演进与实战技巧Harness Engineering 实战课:用 ReAct + 结构化思维链构建高可用的 AI 开发助手
2. 引言 (Introduction)
2.1 痛点引入 (Hook)
还在为你的 AI Agent 解决问题时的“断链卡顿”而抓狂吗?
场景一:你用 LangChain 做了一个代码审查 ReAct Agent,它明明拿到了 Git 仓库的结构、发现了函数里有内存泄漏的迹象,却要么直接生成了完全错误的修复方案(根本没去查官方文档的内存管理 API),要么查了十次八次无关的 Stack Overflow 帖子——明明用了 CoT 提示模板,也加了 ReAct 的“观察-思考-行动”循环,为什么工程化问题的解决效率和正确率还是低得可怜?
场景二:你尝试用 AutoGPT Lite 搭建一个基于本地知识库的 AI 运维助手,它执行“排查 Redis 主从延迟 500ms 以上的原因”任务时,要么第一步就去敲redis-cli PING(完全跳过配置检查、慢查询分析等核心步骤),要么第二步看到INFO replication里有lag=520就直接重启主从节点——根本没有结构化的推理链路,把 Harness Engineering(工具驾驭工程)做成了“工具滥用工程”!
场景三:你给 AI 大模型(比如 GPT-4o、Claude 3.5 Sonnet)写了一个简单的 ReAct Prompt 解决算法题,比如“设计一个 LRUCache 并测试它的性能瓶颈”,但大模型经常在“观察-行动”环节出bug:比如忘记初始化测试数据量、只生成了空的测试报告、把 Python 的collections.OrderedDict和手写双向链表的性能数据混在一起分析——这哪里是“AI 工程师”,分明是“AI 实习生实习生”!
这些问题,你是不是也遇到过?明明把 CoT(思维链)和 ReAct(推理-行动)这两个目前 AI 推理领域最火的技术结合起来了,为什么结果还是差强人意?
2.2 文章内容概述 (What)
别急,这篇文章就是来帮你解决这些问题的!
本文不会停留在“介绍 CoT 是什么、ReAct 是什么、怎么用 LangChain 写一个简单的 ReCoT(ReAct + CoT 缩写,本文后续统一使用该术语)Prompt”这种入门内容上——毕竟网上这类教程已经铺天盖地了。
本文会聚焦于Harness Engineering 场景下的 ReCoT 进阶技巧,也就是:
- 为什么入门的 ReCoT 解决不了工程问题——拆解 CoT、ReAct、入门 ReCoT 的核心缺陷;
- 如何构建结构化的 ReCoT 推理链路——从 Harness Engineering 的核心流程(理解→假设→验证→执行→总结)出发,设计一套通用的“结构化思考模板 + 工具调用策略 + 观察解析规则”;
- 如何优化 ReCoT 的工具调用效率——减少无关工具调用、避免冗余循环、处理工具调用失败的边界情况;
- 如何构建可复用的 ReCoT 组件库——在 LangChain、AutoGPT Lite、MetaGPT 等主流 Agent 框架中,把 ReCoT 的核心能力(结构化思考、工具导航、观察总结)封装成可插拔的组件;
- 实战构建高可用的 ReCoT AI 开发助手——从零开始,用 Python + LangChain + 本地知识库 + 代码执行器,搭建一个能“理解需求、写技术方案、查官方文档、写代码、做单元测试、做性能测试、生成测试报告”的全流程 AI 开发助手;
- ReCoT 的进阶优化与未来趋势——比如引入多步记忆回溯、自我反思机制、混合思维链(CoT + ToT + CoT)、多 Agent ReCoT 协作等。
2.3 读者收益 (Why)
读完本文,你将获得:
- 一套完整的 Harness Engineering ReCoT 理论体系——不再是零散的 Prompt 技巧,而是从问题定义到落地优化的全链路方法论;
- 一套通用的结构化 ReCoT 推理模板库——涵盖代码开发、代码审查、运维排查、技术方案设计、算法题解等多个常见工程场景;
- 一套可复用的 ReCoT 组件库——在主流 Agent 框架中开箱即用,节省你 80% 的重复开发时间;
- 一个完整的实战项目——高可用的 ReCoT AI 开发助手,你可以直接把它用到自己的工作中;
- 对 AI Agent 未来发展的深刻理解——知道 ReCoT 接下来会往哪里走,提前布局自己的技术栈。
3. 准备工作 (Prerequisites)
3.1 技术栈/知识
为了更好地理解和实践本文内容,你需要具备以下技术栈和知识:
- 扎实的 Python 编程基础——熟悉 Python 的面向对象编程、装饰器、异步编程(asyncio)、数据结构与算法(至少要懂链表、哈希表、LRUCache 的基本原理);
- 对大语言模型(LLM)的基本理解——知道什么是 Prompt、Completion、Token、Temperature、Top-p、Context Window 等核心概念;
- 对 CoT(思维链)和 ReAct(推理-行动)的入门了解——至少用过一两次 CoT Prompt 解决问题,看过 ReAct 的原始论文或者入门教程;
- 对主流 Agent 框架的基本了解——比如 LangChain(至少用过 LLMChain、SimpleSequentialChain、AgentExecutor 这些基础组件)、AutoGPT Lite 或者 MetaGPT 中的任意一个;
- 对 Git、GitHub/GitLab、Docker、Redis 等常见开发/运维工具的基本了解——因为实战项目会用到这些工具;
- 对 Harness Engineering(工具驾驭工程)的基本理解——知道 AI Agent 在工程场景中需要“理解工具的功能、知道什么时候用什么工具、怎么正确调用工具、怎么解析工具的返回结果、怎么根据结果调整下一步行动”。
3.2 环境/工具
为了完成本文的实战项目,你需要准备以下环境和工具:
- 操作系统:Windows 10/11(WSL2)、macOS(Ventura 及以上)、Linux(Ubuntu 20.04/22.04 及以上)——推荐使用 Linux 或者 macOS,因为代码执行器在 Windows 原生环境中可能会有一些权限问题;
- Python 环境:Python 3.10 及以上(建议使用 3.11,性能更好),并安装了 pip、virtualenv 或者 conda 等包管理工具;
- 大语言模型 API Key:你可以选择 OpenAI 的 GPT-4o/GPT-4o Mini、Anthropic 的 Claude 3.5 Sonnet/Claude 3 Opus、Google 的 Gemini 1.5 Pro/Gemini 1.5 Flash 中的任意一个——推荐使用 GPT-4o 或者 Claude 3.5 Sonnet,因为它们的工程推理能力和工具驾驭能力目前是最强的;
- 本地知识库工具(可选但推荐):比如 LangChain 的 ChromaDB、Qdrant 或者 FAISS——实战项目会用 ChromaDB 搭建一个本地的技术文档知识库;
- 代码执行器工具(可选但推荐):比如 LangChain 的 PythonREPLTool、Docker 容器化的代码执行器(比如 E2B)——实战项目会用 Docker 容器化的 E2B 代码执行器,因为它更安全、更隔离;
- Git 环境:已安装 Git 并配置了 GitHub/GitLab 的 SSH Key——实战项目会用 Git 克隆模板仓库、管理代码;
- 代码编辑器/IDE:推荐使用 VS Code(安装了 Python、LangChain、GitLens 等插件)或者 PyCharm;
- 测试工具(可选但推荐):比如 pytest、unittest——实战项目会用 pytest 做单元测试和性能测试。
4. 核心内容:基础理论拆解(为什么入门 ReCoT 不行)
在开始实战之前,我们必须先搞清楚一个问题:为什么我们把 CoT 和 ReAct 简单拼接起来,解决不了复杂的工程问题?
要回答这个问题,我们需要先分别拆解 CoT、ReAct、入门 ReCoT 的核心原理、优点、以及致命缺陷——特别是在 Harness Engineering 场景下的缺陷。
4.1 思维链(Chain of Thought, CoT)基础理论拆解
4.1.1 核心概念
思维链(CoT)是 Google Research 在 2022 年发表的论文《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》中提出的一种 Prompt 技术。
它的核心思想很简单:在给大语言模型(LLM)提问时,不要只给输入和输出,还要给几个“中间推理步骤”的示例——也就是“思维链示例”(Few-Shot CoT),或者直接在 Prompt 里加上一句“请一步步思考”(Zero-Shot CoT)。
这样做的目的是引导 LLM 像人类一样,通过“分解问题→逐步推理→得出结论”的方式来解决复杂的逻辑、数学、编程问题,而不是直接“猜答案”。
4.1.2 问题背景
在 CoT 出现之前,LLM 在解决“多步推理问题”(比如小学数学应用题、复杂的逻辑推理题、算法题)时的表现非常差——哪怕是 GPT-3(175B 参数)这样的大模型,在 GSM8K(小学数学应用题数据集)上的准确率也只有不到 20%。
为什么会这样?因为当时的主流 Prompt 技术是“输入-输出”式的(也就是 Direct Prompting):LLM 拿到问题后,直接生成答案,中间没有任何思考过程——就像一个小学生,拿到数学题后直接写答案,根本不打草稿,结果自然可想而知。
4.1.3 核心原理(为什么 CoT 有用?)
CoT 为什么能大幅提升 LLM 的多步推理能力?Google Research 的论文里给出了三个主要原因:
- 分解复杂问题:CoT 引导 LLM 把一个复杂的问题分解成多个简单的子问题,每个子问题的解决难度都大大降低;
- 激活 LLM 的“推理神经”:LLM 的参数里其实已经存储了大量的“推理知识”(比如数学公式、逻辑规则、编程语法),但 Direct Prompting 无法激活这些知识——CoT 通过“中间推理步骤”的示例,给 LLM 一个“信号”:“哦,原来我需要先调用这些推理知识,再一步步得出结论”;
- 修正推理错误:在 Few-Shot CoT 中,LLM 可以学习到“正确的推理路径”——哪怕它在某一步推理中犯了错误,也可以通过模仿示例中的步骤来修正(虽然 Zero-Shot CoT 做不到这一点,但它至少能让 LLM 开始思考)。
不过,后来的研究(比如 OpenAI 的《GPT-4 Technical Report》、Meta 的《Scaling Laws for Neural Language Models》补充研究)发现,CoT 有用还有一个更重要的原因:大语言模型的“涌现能力”(Emergent Abilities)——只有当 LLM 的参数规模达到一定程度(比如 100B 以上),CoT 才能发挥作用;参数规模越小,CoT 的效果越差,甚至可能起反作用。
4.1.4 概念结构与核心要素组成
CoT 的概念结构非常简单,它主要由三个核心要素组成:
- 任务说明(Task Instruction):告诉 LLM 它需要做什么——比如“请解决以下小学数学应用题”;
- 思维链示例(Few-Shot Examples, 可选但推荐):给 LLM 几个“输入→中间推理步骤→输出”的完整示例——示例的质量和数量直接决定了 CoT 的效果;
- 目标问题(Target Question):给 LLM 需要解决的实际问题;
- 思维链触发词(Trigger Word, 可选但 Zero-Shot CoT 必须):比如“请一步步思考”、“Let’s think step by step”、“首先,我们需要…”——触发词可以引导 LLM 自动生成中间推理步骤。
我们可以用一个简单的 Mermaid ER 实体关系图来表示 CoT 的核心要素之间的关系:
4.1.5 问题解决:CoT 的应用场景
CoT 主要适用于以下几类“多步推理问题”:
- 数学问题:比如小学数学应用题(GSM8K)、高中数学题(MATH)、大学数学题(AMC);
- 逻辑推理问题:比如三段论推理、常识推理(CommonsenseQA)、策略游戏推理(比如 Chess、Go 的简单局面);
- 代码理解与生成问题:比如代码补全、代码解释、简单算法题的代码生成;
- 自然语言理解问题:比如文本摘要的逻辑梳理、问答系统的多跳推理(Multi-Hop QA)。
我们可以用一个简单的 Few-Shot CoT 示例来演示它的应用——比如解决一道 GSM8K 小学数学应用题:
### 任务说明 请解决以下小学数学应用题,并给出完整的中间推理步骤。 ### 思维链示例 1 **输入**:小明有 15 个苹果,他给了小红 3 个,又给了小刚 5 个,请问小明还剩几个苹果? **中间推理步骤**: 1. 首先,我们需要计算小明一共给出去了多少个苹果:小红的 3 个 + 小刚的 5 个 = 8 个; 2. 然后,我们用小明原来有的苹果数减去给出去的苹果数,就能得到剩下的苹果数:15 个 - 8 个 = 7 个; **输出**:小明还剩 7 个苹果。 ### 思维链示例 2 **输入**:一个长方形的长是 12 厘米,宽是 8 厘米,请问这个长方形的周长是多少厘米? **中间推理步骤**: 1. 首先,我们需要回忆一下长方形的周长公式:周长 = 2 × (长 + 宽); 2. 然后,我们把长和宽代入公式:长 + 宽 = 12 厘米 + 8 厘米 = 20 厘米; 3. 最后,我们计算周长:2 × 20 厘米 = 40 厘米; **输出**:这个长方形的周长是 40 厘米。 ### 目标问题 **输入**:小李有 20 支铅笔,他用了 4 支,又买了 7 支,请问小李现在有几支铅笔? **中间推理步骤**:当我们把这个 Prompt 输入给 GPT-4o Mini 时,它会自动生成完整的中间推理步骤和正确的输出:
**中间推理步骤**: 1. 首先,我们需要计算小李用了 4 支铅笔后还剩多少支:原来的 20 支 - 用掉的 4 支 = 16 支; 2. 然后,我们用剩下的铅笔数加上又买的铅笔数,就能得到现在的铅笔数:16 支 + 7 支 = 23 支; **输出**:小李现在有 23 支铅笔。4.1.6 边界与外延
4.1.6.1 CoT 的边界(什么时候 CoT 没用?)
CoT 虽然强大,但它也有自己的边界——在以下几种情况下,CoT 的效果会非常差,甚至可能起反作用:
- 单步推理问题:比如“1+1等于几”、“中国的首都是哪里”——这类问题不需要分解,直接“猜答案”的效率和正确率更高,CoT 反而会增加 LLM 的推理时间,甚至可能引入不必要的错误;
- 参数规模较小的 LLM:比如 GPT-2(1.5B 参数)、Llama 2 7B——这类 LLM 没有“涌现能力”,CoT 不仅不能提升它们的推理能力,反而会让它们生成混乱的中间推理步骤;
- 需要外部知识的问题:比如“2024年巴黎奥运会的金牌榜第一名是哪个国家”、“最新版 Python 的
asyncio.run()函数有什么新特性”——这类问题的答案不在 LLM 的训练数据里(或者训练数据已经过时),CoT 再怎么推理也得不出正确的答案; - 需要实时交互的问题:比如“现在的天气怎么样”、“帮我查一下这个 GitHub 仓库的最新提交记录”——这类问题需要 LLM 调用外部工具(比如天气 API、GitHub API),但 CoT 本身不具备“工具调用”的能力;
- 需要多轮迭代优化的问题:比如“设计一个高并发的电商订单系统”、“写一个能通过所有测试用例的 LRUCache 代码”——这类问题需要 LLM 不断地“提出方案→验证方案→修正方案→再验证方案”,但 CoT 本身是“一次性”的,无法进行多轮迭代优化。
4.1.6.2 CoT 的外延(CoT 的变种技术)
为了突破 CoT 的边界,研究者们提出了很多 CoT 的变种技术,比如:
- Zero-Shot CoT:不需要 Few-Shot 示例,只需要在 Prompt 里加上一句“请一步步思考”(或者“Let’s think step by step”)——适合没有合适 Few-Shot 示例的场景;
- Self-Consistency CoT(自我一致性思维链):让 LLM 生成多个不同的思维链推理路径,然后用“投票”的方式选择出现次数最多的答案——适合解决有歧义的问题,能大幅提升 CoT 的准确率;
- Tree of Thought(ToT,思维树):把 CoT 的“线性推理”变成“树状推理”——LLM 可以在每个推理步骤生成多个可能的子步骤,然后用“剪枝”的方式保留最有可能的子步骤,最后选择最优的推理路径——适合解决非常复杂的、需要探索多个可能性的问题(比如策略游戏推理、数学证明);
- Graph of Thought(GoT,思维图):把 ToT 的“树状推理”变成“图状推理”——LLM 可以在不同的推理步骤之间建立“连接”(比如共享某个子问题的解决方案)——适合解决有多个依赖关系的复杂问题;
- Chain of Verification(CoVe,验证链):让 LLM 先生成一个初步的答案,然后生成一个“验证问题列表”,再逐一回答这些验证问题,最后根据验证结果修正初步的答案——适合解决容易出现“幻觉”(Hallucination)的问题,能大幅提升 LLM 输出的可信度。
我们可以用一个简单的 Markdown 表格来对比 CoT 及其主要变种技术的核心属性:
| 技术名称 | 核心推理结构 | 是否需要 Few-Shot 示例 | 是否需要外部工具 | 是否支持多轮迭代优化 | 是否支持剪枝/投票 | 适用场景 | 准确率(GSM8K 数据集,GPT-4) | 推理时间(相对值) |
|---|---|---|---|---|---|---|---|---|
| Direct Prompting | 无(直接输出) | 可选 | 否 | 否 | 否 | 单步推理问题 | ~60% | 1x |
| Zero-Shot CoT | 线性 | 否 | 否 | 否 | 否 | 多步推理问题(无示例) | ~75% | 2x |
| Few-Shot CoT | 线性 | 是 | 否 | 否 | 否 | 多步推理问题(有示例) | ~90% | 2.5x |
| Self-Consistency CoT | 多条线性 | 是 | 否 | 否 | 是(投票) | 有歧义的多步推理问题 | ~95% | 8x-10x |
| Tree of Thought (ToT) | 树状 | 是 | 否 | 是(局部迭代) | 是(剪枝) | 非常复杂的探索性多步推理问题 | ~97% | 20x-50x |
| Graph of Thought (GoT) | 图状 | 是 | 否 | 是(全局迭代) | 是(剪枝+投票) | 有多个依赖关系的复杂问题 | ~98% | 50x-100x |
| Chain of Verification (CoVe) | 线性+验证链 | 是 | 否 | 是(验证后修正) | 否 | 容易出现幻觉的问题 | ~92%(针对幻觉问题的准确率提升 30%-50%) | 4x-6x |
4.1.7 致命缺陷(特别是在 Harness Engineering 场景下)
虽然 CoT 及其变种技术能大幅提升 LLM 的多步推理能力,但它们都有一个致命缺陷——这个缺陷在 Harness Engineering 场景下尤为明显,甚至可以说是“致命的”:
CoT 及其变种技术都不具备“工具调用”和“实时环境交互”的能力,也无法处理“推理结果与现实环境不符”的情况。
什么意思?我们用一个简单的 Harness Engineering 场景来演示——比如“帮我写一个 Python 函数,计算两个数的最大公约数(GCD),并测试它是否能通过所有常见的测试用例”。
如果我们只用 Few-Shot CoT 来解决这个问题,Prompt 可能长这样:
### 任务说明 请帮我写一个 Python 函数,计算两个正整数的最大公约数(GCD),并给出完整的中间推理步骤、函数代码、以及常见测试用例的测试结果。 ### 思维链示例 **输入**:请帮我写一个 Python 函数,计算两个正整数的最小公倍数(LCM),并给出完整的中间推理步骤、函数代码、以及常见测试用例的测试结果。 **中间推理步骤**: 1. 首先,我需要回忆一下最小公倍数的定义:两个正整数的最小公倍数是能被这两个数同时整除的最小正整数; 2. 然后,我需要回忆一下最小公倍数的计算公式:LCM(a, b) = (a × b) / GCD(a, b)——所以我需要先实现一个计算最大公约数的函数; 3. 接下来,我需要回忆一下计算最大公约数的常用算法:欧几里得算法(辗转相除法)——它的原理是 GCD(a, b) = GCD(b, a mod b),直到 b 等于 0,此时 a 就是最大公约数; 4. 然后,我需要用 Python 代码实现欧几里得算法; 5. 接下来,我需要用 Python 代码实现最小公倍数的函数; 6. 然后,我需要设计几个常见的测试用例: a. 测试用例 1:LCM(4, 6) = 12; b. 测试用例 2:LCM(5, 7) = 35(两个质数); c. 测试用例 3:LCM(12, 18) = 36; d. 测试用例 4:LCM(1, 100) = 100; e. 测试用例 5:LCM(0, 5)——需要处理边界情况(输入为 0); 7. 最后,我需要模拟这些测试用例的执行过程,给出测试结果; **函数代码**: ```python def gcd(a: int, b: int) -> int: \"\"\"计算两个正整数的最大公约数(欧几里得算法)\"\"\" while b != 0: a, b = b, a % b return a def lcm(a: int, b: int) -> int: \"\"\"计算两个正整数的最小公倍数\"\"\" if a == 0 or b == 0: raise ValueError("输入的两个数必须都是正整数") return (a * b) // gcd(a, b)测试用例与测试结果:
- 测试用例 1:LCM(4, 6) = (4×6)/GCD(4,6) = 24/2 = 12 ✅;
- 测试用例 2:LCM(5, 7) = (5×7)/GCD(5,7) = 35/1 = 35 ✅;
- 测试用例 3:LCM(12, 18) = (12×18)/GCD(12,18) = 216/6 = 36 ✅;
- 测试用例 4:LCM(1, 100) = (1×100)/GCD(1,100) = 100/1 = 100 ✅;
- 测试用例 5:LCM(0, 5) → 抛出 ValueError ✅;
目标问题
输入:请帮我写一个 Python 函数,计算两个正整数的最大公约数(GCD),并给出完整的中间推理步骤、函数代码、以及常见测试用例的测试结果。
中间推理步骤:
当我们把这个 Prompt 输入给 GPT-4o 时,它会生成看起来非常完美的中间推理步骤、函数代码和测试结果——比如: ```markdown **中间推理步骤**: 1. 首先,我需要回忆一下最大公约数的定义:两个正整数的最大公约数是能被这两个数同时整除的最大正整数; 2. 然后,我需要回忆一下计算最大公约数的常用算法:欧几里得算法(辗转相除法)——它的原理是 GCD(a, b) = GCD(b, a mod b),直到 b 等于 0,此时 a 就是最大公约数; 3. 接下来,我需要考虑边界情况: a. 如果输入的两个数中有一个是 0,需要抛出错误; b. 如果输入的两个数中有一个是负数,需要先取绝对值(不过任务说明里说输入是正整数,所以这一步可以省略,但为了函数的鲁棒性,最好还是加上); 4. 然后,我需要用 Python 代码实现欧几里得算法; 5. 接下来,我需要设计几个常见的测试用例: a. 测试用例 1:GCD(4, 6) = 2; b. 测试用例 2:GCD(5, 7) = 1(两个质数); c. 测试用例 3:GCD(12, 18) = 6; d. 测试用例 4:GCD(1, 100) = 1; e. 测试用例 5:GCD(0, 5) → 抛出 ValueError; f. 测试用例 6:GCD(-4, 6) → 先取绝对值,再计算,结果为 2; 6. 最后,我需要模拟这些测试用例的执行过程,给出测试结果; **函数代码**: ```python def gcd(a: int, b: int) -> int: \"\"\"计算两个整数的最大公约数(欧几里得算法)\"\"\" # 处理边界情况:输入为 0 if a == 0 or b == 0: raise ValueError("输入的两个数不能为 0") # 处理负数情况:先取绝对值 a = abs(a) b = abs(b) # 欧几里得算法 while b != 0: a, b = b, a % b return a测试用例与测试结果:
- 测试用例 1:GCD(4, 6) → 取绝对值后为 4 和 6 → 欧几里得算法:GCD(4,6)=GCD(6,4)=GCD(4,2)=GCD(2,0)=2 ✅;
- 测试用例 2:GCD(5, 7) → 取绝对值后为 5 和 7 → GCD(5,7)=GCD(7,5)=GCD(5,2)=GCD(2,1)=GCD(1,0)=1 ✅;
- 测试用例 3:GCD(12, 18) → 取绝对值后为 12 和 18 → GCD(12,18)=GCD(18,12)=GCD(12,6)=GCD(6,0)=6 ✅;
- 测试用例 4:GCD(1, 100) → 取绝对值后为 1 和 100 → GCD(1,100)=GCD(100,1)=GCD(1,0)=1 ✅;
- 测试用例 5:GCD(0, 5) → 抛出 ValueError ✅;
- 测试用例 6:GCD(-4, 6) → 取绝对值后为 4 和 6 → 结果为 2 ✅;
看起来非常完美,对吧?但是——**如果我们把这个函数代码复制到 Python 环境中运行测试用例 6,会发生什么?** 测试用例 6 是 `GCD(-4, 6)`——我们来手动执行一下函数代码: 1. 首先,检查输入是否为 0:-4 和 6 都不是 0,跳过; 2. 然后,取绝对值:a = abs(-4) = 4,b = abs(6) = 6; 3. 接下来,执行欧几里得算法: a. 第一次循环:b != 0 → a, b = b, a % b → a = 6, b = 4 % 6 = 4; b. 第二次循环:b != 0 → a, b = b, a % b → a = 4, b = 6 % 4 = 2; c. 第三次循环:b != 0 → a, b = b, a % b → a = 2, b = 4 % 2 = 0; d. 循环结束,返回 a = 2; 4. 看起来测试用例 6 是通过的,对吧? 那我们再换一个测试用例——比如 `GCD(6, -4)`——执行结果也是 2,没问题。 那我们再换一个更复杂的测试用例——比如 `GCD(123456789, 987654321)`——GPT-4o 模拟的测试结果是 9,对吧? 那我们把这个函数代码复制到 Python 环境中运行一下——结果真的是 9,没问题。 那……CoT 的致命缺陷在哪里? 别急,我们再换一个 Harness Engineering 场景——比如“帮我写一个 Python 函数,读取当前目录下的 `requirements.txt` 文件,统计里面有多少个依赖包,并测试它是否能通过所有常见的测试用例”。 如果我们只用 Few-Shot CoT 来解决这个问题,GPT-4o 可能会生成这样的函数代码: ```python def count_requirements() -> int: \"\"\"读取当前目录下的 requirements.txt 文件,统计依赖包的数量\"\"\" with open("requirements.txt", "r", encoding="utf-8") as f: lines = f.readlines() # 过滤掉空行和注释行(以 # 开头的行) count = 0 for line in lines: line = line.strip() if line and not line.startswith("#"): count += 1 return count然后模拟的测试用例与测试结果可能长这样:
- 测试用例 1:当前目录下有一个
requirements.txt文件,内容为:
→ 统计结果为 3 ✅;# 这是一个注释 langchain==0.2.10 openai==1.35.10 python-dotenv==1.0.1 - 测试用例 2:当前目录下没有
requirements.txt文件 → 抛出 FileNotFoundError ✅;
看起来非常完美,对吧?但是——如果当前目录下真的没有requirements.txt文件,GPT-4o 能知道吗?
答案是:不能!
因为 CoT 及其变种技术都不具备“实时环境交互”的能力——GPT-4o 只能“模拟”测试用例的执行过程,它根本不知道当前目录下有没有requirements.txt文件,也不知道当前目录下的requirements.txt文件的真实内容是什么。
那如果我们让 GPT-4o 写这个函数,然后我们自己去运行测试用例——如果测试用例失败了,比如统计结果不对,或者文件编码不对,我们再把错误信息反馈给 GPT-4o,让它修正函数代码——这算不算“多轮迭代优化”?
算——但这是人类驱动的多轮迭代优化,不是AI 自主驱动的多轮迭代优化。
在 Harness Engineering 场景下,我们需要的是AI 自主驱动的多轮迭代优化——也就是:
- AI 理解需求;
- AI 提出初步的解决方案;
- AI自主调用外部工具(比如代码执行器、文件系统工具、API 工具)来验证解决方案;
- AI自主解析工具的返回结果;
- 如果验证失败,AI自主修正解决方案;
- 重复步骤 3-5,直到验证通过;
- AI 输出最终的解决方案。
而 CoT 及其变种技术,根本做不到这一点——这就是它们的致命缺陷。
(本章剩余内容将继续拆解 ReAct 的基础理论、致命缺陷,以及入门 ReCoT 的致命缺陷,预计本章总字数将超过 15000 字)