【Agent】 别再让你的 Agent 靠直觉写代码了:四种 Planning 架构的工程选型与落地陷阱
别再让你的 Agent 靠直觉写代码了:四种 Planning 架构的工程选型与落地陷阱
声明:本文中提到的「CloudMart」为虚构电商教学系统,仅用于串联知识点。
目录
- 一、戳破 ReAct 的完美幻觉:你造的究竟是 Agent,还是 Token 永动机?
- 二、思考范式的演进:从「即兴表演」到「运筹帷幄」
- 三、规划架构落地:Planner 与 Executor 的「军政分离」
- 四、防线与红线:如何避免你的 Planner 跑飞?
- 五、总结
一、戳破 ReAct 的完美幻觉:你造的究竟是 Agent,还是 Token 永动机?
这几天我翻了挺多 AI Agent 相关的教程。开源框架的上手文档看了,各路博主的技术拆解也看了一圈——然后发现一个很有意思的现象:大家像商量好了一样,都在讲同一个万能公式。Agent = LLM + Prompt(ReAct)+ Tools。
按照这个叙事,Agent 应该是这样的:遇到问题就自动推理(Reasoning),发现缺数据就自己去调工具(Acting),一个完美的 ReAct 闭环跑起来,行云流水。
但这里有一个残酷的事实:一旦你离开「天气查询」和「算术口算」这种玩具 Demo,让 Agent 去处理哪怕只是稍微复杂一点的工程任务——它大概率会翻车,而且翻得很彻底。
来看 CloudMart 这个场景。
你给 Agent 下了一个任务:「去 CloudMart 后端仓库里,把order_service.py里那段十几层 if-else 的订单状态机逻辑重构掉,然后跑通单元测试。」
满载 ReAct 框架的 Agent 跑起来往往是下面这副名场面:
[Thought]: 我需要查看 order_service.py 的结构和报错信息。 [Action]: read_file("order_service.py") [Observation]: (返回了 500 行代码,混杂着复杂的依赖引用和类型注解) [Thought]: 看来核心问题是 line 42 到 line 187 的状态机需要拆分。我用 replace 替换它。 [Action]: replace_code("order_service.py", line=42, text="...(新代码)...") [Observation]: (报错:SyntaxError: invalid syntax,还引用了未导入的模块) [Thought]: 坏了,我漏掉了依赖注入。让我重新读一下文件。 [Action]: read_file("order_service.py") ... (以上过程重复 15 次,直到触发 context window 上限或 API 限流)这就是无数开发者午夜梦回时的噩梦:Agent 陷入了死循环。
走一步看一步的 ReAct,本质上是在用高昂的 Token 成本来掩盖架构上全局规划能力的缺失。大模型在单步推理时,就像一个手里只有手电筒的盲人——只能看清眼前这一个工具的输入与输出。当工具返回了一个符合预期的结果时,它表现得像个天才;可一旦工具返回了 unexpected 的底层报错,LLM 就会瞬间被眼前的局部错误带偏,顺着错误的逻辑一路狂奔,在两三个工具之间反复横跳,直到把你的 Token 烧光。
复杂的工程任务,需要的是导演,而不是只会即兴表演的戏子。
ReAct 这种把「规划」和「执行」高度绑定在每一个 Step 里的做法,最大的问题就在于它太缺乏大局观了。因为大模型在吞下前一步工具返回的巨量 Observation(往往是冗余的 JSON 或堆栈日志)后,它的注意力已经被严重污染。在下一轮 Thought 中,它几乎丧失了对最初目标的掌控力。
核心洞察:ReAct 的每一步推理都在被上一步的工具返回「重新塑造」。工具返回越嘈杂,Agent 偏离原始目标越远。这不是推理能力的问题——这是架构层面的信息污染。
要解决这个问题,我们就必须把 Agent 的「大脑」解耦,为它注入真正的「思考骨架」——也就是从 ReAct 走向更高级的 Planning 架构。
二、思考范式的演进:从「即兴表演」到「运筹帷幄」
为了打破 ReAct 的局部最优解陷阱,业界在工程实践中演进出了另外三种主流的规划架构。它们的核心逻辑、优缺点以及适用场景,我用一张表来对比:
| 规划模式 | 核心逻辑 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| ReAct | 想一步,做一步 | 极度灵活,能应对高度动态的环境 | Token 消耗极大,极易迷路和死循环 | 简单的探索性任务、短平快的工具调用 |
| ReWOO | 预先规划工具流水线,斩断中间观察 | 零等待,省 Token,执行效率极高 | 无法处理工具之间的条件分支(If-Else) | 工具依赖明确、需要并行处理的批处理场景 |
| Plan-and-Execute | 先画全局地图再出发,途中动态重规划 | 兼顾大局观与灵活性,抗挫折能力强 | 架构复杂,重规划时对大模型要求高 | 复杂的长文本处理、多步骤软件自动化 |
| Self-Discover | 让 LLM 先从原子模块池里自选推理结构 | 逻辑极其严密,深度定制思考路径 | 首字延迟(TTFT)高,不适合简单任务 | 复杂的数学证明、代码重构、科学推演 |
下面逐一拆解每种架构的核心机制。
2.1 效率至上主义:ReWOO 架构
如果一个任务需要调用 5 次 API,传统的 ReAct 需要等 LLM 思考 5 次、吐 5 次 Token,大把的时间全死在了网络 IO 和首字延迟上。
ReWOO(Reasoning Without Observation)提出了一个极其优雅的解法:斩断中间观察。
它让大模型在出发前,直接交出一份完整的「工具流水线依赖表」。回到 CloudMart 的场景,Planner 会一次性输出:
计划: Step 1: 调用 read_file("order_service.py"),获取完整代码 Step 2: 将 Step 1 的输出传给 analyze_code(),识别需重构的状态机段落 Step 3: 将 Step 2 的分析结果传给 run_tests("tests/order/"),获取当前测试覆盖率 Step 4: 基于 Step 1-3 的全部结果,生成重构方案然后 Worker 节点批量并行执行这些工具调用——Step 1 到 Step 3 如果彼此不依赖外部结果,可以同时发射。等全部工具返回后,Solver 一次性汇总所有结果,输出最终的解决方案。
把思考和执行解耦,最好的规划不是在终点前不断修正,而是在出发前就把所有的炮火编排好批量发射。ReWOO 的核心魅力,在于它用一轮推理,换取了工业级的零等待执行效率。
但 ReWOO 有它的硬伤:它假设工具之间的依赖关系是静态的、可预知的。如果 Step 2 的结果告诉你「这个文件根本不存在,你应该去读order_service_v2.py」,ReWOO 没有办法在流水线中途拐弯——它的工具依赖表在出发前就锁死了。
2.2 稳健派:Plan-and-Execute
当面对极度复杂的任务时,我们需要的是 Plan-and-Execute——先规划,再执行。
它拥有一个独立的 Planner,先将大目标拆解为 Plan A(包含 Step 1, 2, 3…)。Executor 独立去跑这些步骤。关键的是第三步:如果中途 Step 2 报错了,信息会回传给 Planner 触发Replan(重规划),重新修正后面的路线。
回到 CloudMart:Planner 先规划「读取代码 → 分析状态机 → 重构 → 运行测试 → 验证覆盖率」。Executor 跑到第三步时发现重构引入了循环依赖。这个信息回传给 Planner,Planner 重规划:先拆解循环依赖,再继续重构。
Plan-and-Execute 相比 ReWOO 多了一个「重规划」环节,这带来了极强的容错能力,但也引入了新的风险——如果 Planner 反复在同一节点失败,它可能陷入和 ReAct 一样的问题:只不过这次烧的不是单步 Token,而是一整轮规划 + 执行的 Token。
2.3 深度推理派:Self-Discover
Self-Discover 走的是另一条路。它不让开发者预设推理结构,而是让 LLM自己从原子模块池里挑选最适合当前任务的思维框架。
原子模块池里放的是一些通用的推理模式,比如:
- 批判性思维:这个假设站得住脚吗?有没有反例?
- 首要原则拆解:这个问题的最底层约束是什么?
- 逆向推导:从期望的最终状态反推需要的前置条件
- 类比推理:这个问题和哪个已知问题结构相似?
面对 CloudMart 的订单状态机重构任务,Self-Discover 可能自己选出一套组合:「首要原则拆解 → 批判性思维 → 逐步细化」——先用首要原则搞清楚状态机的核心约束(订单状态流转的不可逆规则),再用批判性思维检查现有实现是否违反了这些约束,最后逐步细化出重构方案。
Self-Discover 的优势在于它不假设任何通用的推理结构适用于所有任务——它让 Agent 自己诊断问题的类型,然后为自己量身定做一条推理路径。代价是首字延迟(TTFT)更高,因为 LLM 需要先「思考如何思考」,再开始真正的推理。
2.4 四种架构的决策指南
这么多架构,实际工程中怎么选?我用一个 2×2 矩阵来帮你快速定位:
- 任务简单 + 工具依赖明确:直接 ReWOO,别浪费 Token 在即兴表演上
- 任务简单 + 工具依赖不明确:ReAct 够用,探索成本可控
- 任务复杂 + 工具依赖明确:Plan-and-Execute,先画地图再出发
- 任务复杂 + 工具依赖不明确:Self-Discover,让 Agent 自己选择合适的推理路径
三、规划架构落地:Planner 与 Executor 的「军政分离」
在将这些 Planning 架构落地到代码层面时,大部分开发者会犯同一个错误:用同一个大模型上下文(Context Window)既当大脑又当四肢。
当你把规划逻辑、工具描述、工具返回的几百行原始 JSON 混在同一个聊天历史里时,大模型很快就会不堪重负。
不要让干脏活的工具返回值,污染了将军的战略沙盘。
在工程实现上,优秀的 Planning 架构必须做到「军政分离」:
这套架构的核心要义只有一句话:Planner 永远只能看到被清洗过的、高度抽象的状态摘要,而不是原始的报错日志。
回到 CloudMart 的场景,当 Executor 执行run_tests("tests/order/")后发现 12 个测试挂了 11 个,它不会把 500 行 pytest 堆栈直接甩回给 Planner。它会先做摘要:
[Executor → Planner 摘要] 任务:运行 tests/order/ 单元测试 结果:12 个测试,1 通过,11 失败 关键失败集群: - test_state_transition (3个):状态机循环依赖导致 ImportError - test_payment_integration (5个):Mock 对象接口不匹配 - test_edge_cases (3个):边界值处理逻辑缺失 建议:优先修复状态机循环依赖(阻塞后续所有测试),再处理 Mock 接口Planner 拿到这份摘要后,清楚地知道「先修循环依赖,再修 Mock」,而不是在 500 行堆栈里迷失方向。
四、防线与红线:如何避免你的 Planner 跑飞?
无论你选择了哪种规划架构,只要引入了动态重规划机制,你就必须在代码层面上建立硬性的安全边界。
永远不要相信 Agent 能自己停下来。一个没有硬编码max_replan_steps的 Agent,不是人工智能,而是一个随时准备刷爆你信用卡的 Token 永动机。
以下三条红线,每一条都来自真实的工程血泪教训:
4.1 强行硬编码截断
在你的控制循环里,必须写死截断逻辑。不要指望在 Prompt 里写「如果你找不到答案就请停止」能百分之百生效——LLM 在陷入局部循环时,这个提示词大概率会被它自己忽略。
classPlanningAgent:MAX_STEPS=12# 硬上限:全局总步数MAX_REPLAN_ROUNDS=3# 硬上限:同一节点的重规划次数defrun(self,goal):step_count=0replan_count=0whilestep_count<self.MAX_STEPS:ifreplan_count>=self.MAX_REPLAN_ROUNDS:returnself.escalate_to_human(goal)# ... 正常执行逻辑 ...step_count+=1returnself.timeout_handler(goal)MAX_STEPS和MAX_REPLAN_ROUNDS必须是硬编码的常量,不能从配置文件动态读取,更不能让 LLM 自己决定何时停止。这不是不信任模型——这是防御性工程的基本素养。
4.2 状态隔离与回滚
当 Planner 连续 3 次 Replan 都指向同一个失败节点时,必须触发早停机制,或者引入人工介入。
defreplan(self,failure_node):self.failure_count[failure_node]+=1ifself.failure_count[failure_node]>=3:# 早停:这个节点在现有能力下无法解决returnHumanInterventionRequest(node=failure_node,attempts=self.failure_count[failure_node],suggestion="建议人工介入或重新定义目标")# 正常重规划:绕开失败节点returnself.generate_alternative_plan(exclude=[failure_node])这条红线的底层逻辑是:如果一个节点连续 3 次失败,问题大概率不在执行层面,而在规划层面——要么目标本身在当前工具集下达不到,要么缺少关键信息。
4.3 剪枝与摘要
前面讲「军政分离」时已经提到了信息清洗的重要性。这里补充一个具体的工程建议:
Executor 执行完工具后,使用一个极其轻量、便宜的模型(截至 2026 年 6 月,如 GPT-4o-mini 或 Claude 3.5 Haiku)对结果进行缩减摘要,只把关键结论喂回给 Planner。
原始工具返回(500 行堆栈日志) │ ▼ [轻量摘要模型] │ ▼ 结构化的 3 行摘要: - 成功/失败状态 - 关键数据(数字、路径、错误类型) - 对下一步的建议这样做有两个好处:一是保护核心模型(截至 2026 年 6 月,如 GPT-4o / Claude Opus)的注意力不被垃圾信息污染,二是大幅降低 Token 成本——500 行堆栈日志压缩成 3 行摘要,单轮消耗从几千 Token 降到几十 Token。
五、总结
从 ReAct 的「即兴表演」走向 Planning 的「运筹帷幄」,是 Agent 从玩具走向工业级应用的必经之路。
在设计你下一款 Agent 时,不妨先慢下来,问自己三个问题:我的任务真的需要它每一步都即兴发挥吗?工具之间的依赖关系是静态可预知的,还是动态变化的?我有没有在代码里为它写好硬性的安全红线?
规划架构的选择没有银弹,但有清晰的决策逻辑。关键是:别让你的 Agent 在黑暗中摸索——给它一张地图,一盏灯,和一条随时可以踩刹车的红线。
感谢看到这里,评论+关注比点赞更有价值。
