经典 ReAct 的阿喀琉斯之踵
经典 ReAct 范式通过交替执行 Thought(思考)、Action(动作)和 Observation(观察)让模型逐步推导。
然而在复杂工程中,纯 ReAct 极易产生:
- 短视贪心(Greedy Bias):走一步看一步,缺乏长期全局规划,在死胡同里不断浪费 Token;
- 错误放大(Error Cascade):前序工具调用的轻微误差会污染后续所有推理步骤。
规划与求解分离架构 (Plan-and-Solve)
现代工业级 Agent 普遍引入两阶段机制:
- Planner 阶段:模型首先不调用任何执行工具,专注于将复杂目标分解为有依赖关系的子任务图(DAG);
- Executor 阶段:由更轻量的执行器依次针对子任务调用对应工具;
- Critic / Reflector 阶段:当执行器遇到异常时,触发独立的反思机制,评估当前偏离度并重写未完成的计划。
落地示例:把三阶段写进调度器
规划阶段最关键的约束是"禁用工具"。给 Planner 的提示里只允许输出结构化步骤列表,并显式声明当前无工具可调用,否则它会一边列计划一边开始执行,阶段隔离立刻失效。
计划建议采用统一的中间结构:每个子任务带标识、目标描述、前置依赖、完成判据四项。完成判据尤其重要,它是 Critic 判断"这步到底做没做成"的唯一依据,缺失时反思阶段只能靠猜测。
执行阶段则用更小的模型,因为它面对的已经是边界清晰的单步任务。Critic 不共享执行器的对话历史,只读计划与产出,避免被同一个错误说服。
三种范式的适用对比
| 维度 | 纯 ReAct | Plan-and-Solve | 加 Reflector |
|---|---|---|---|
| 任务时长 | 短,几步内 | 中长,可预先分解 | 长且结果需验收 |
| Token 成本 | 低但易失控 | 前置一次性开销 | 明显更高 |
| 错误恢复 | 依赖局部观察 | 重排未执行步骤 | 显式回滚与重写 |
| 可观测性 | 日志线性可读 | 树状便于定位 | 需记录反思链路 |
| 典型场景 | 查询类工具链 | 多文件改造 | 交付型自动化 |
经验上,子任务数量在两步以内时引入 Planner 反而增加延迟与漂移,此时纯 ReAct 更稳;步骤多、依赖关系复杂时才值得付出规划成本。
验证方法
用同一批任务做 A/B:一组纯 ReAct,一组规划分离,比较平均轮次、Token 消耗与完成率三项即可,不必追求复杂指标。更实用的是故障注入:人为让第 2 个子任务返回错误结果,观察系统是否只重跑受影响分支,还是把整个计划推翻重来;后者说明反思阶段缺少偏离度阈值。
常见故障速查
| 现象 | 原因 | 处理 |
|---|---|---|
| 计划列完就结束没执行 | 执行器未从计划读取待办 | 强制由调度器驱动下一步 |
| 反思后反复重写同一计划 | 缺少重规划次数上限 | 设最大重规划次数后转人工 |
| 子任务无限膨胀 | Planner 粒度过细 | 约束计划条目数并合并同类步骤 |
| 长任务中途遗忘目标 | 计划未随上下文注入 | 每轮把未完成计划回灌 |
| 规划阶段就开始调用工具 | 未禁用工具列表 | 该阶段传入空工具集 |
小结
选择范式只看一件事:任务能否在开始前被清晰分解。能分解就上 Plan-and-Solve,并在 Critic 里设置偏离度阈值与重规划上限;不能分解的探索型任务保留 ReAct,但必须配轮次与预算硬限制。判据落在数据上:同一批任务的完成率与 Token 成本同步改善,才算这次演进有效。