Agent 的规划与执行范式:Plan-Execute-Replan 与 ReAct

Agent 的规划与执行范式:Plan-Execute-Replan 与 ReAct

一.什么是 Agent

在大模型应用中,Agent 通常指一个系统。它围绕目标,能够选择行动、调用工具,并根据环境反馈继续工作。它常用于需要多个步骤才能完成的任务,例如客服查询、资料调研,也包括故障排查。

大模型可以解释"订单通常为什么延迟发货"。但要回答"我的这笔订单能不能在周五前收到",就需要查询具体订单、库存和配送信息,再根据查到的结果作出判断。

这个过程中,模型负责理解目标和选择行动,工具负责查询或操作外部系统,运行程序负责执行调用、保存结果和控制流程。

这里有一个容易混淆的地方:模型提出工具调用,运行程序实际执行调用。 工具返回的结果进入上下文后,模型才有条件据此决定下一步。

有了这些能力,还需要解决任务怎样组织的问题:先做什么,后做什么?原来的安排走不通时,接下来怎样调整?

下面按照 Plan-Execute → 暴露局限 → 引入 Replan → ReAct → 对比 → 协作 的顺序,逐步看清这些问题。

二.先规划,再执行:Plan-Execute

1.Plan 和 Execute 分别做什么

Plan-Execute 将任务处理分成两个逻辑阶段。

Plan,也就是规划。 根据用户目标和约束,形成一组步骤,明确先后顺序和依赖关系。这部分职责通常称为 Planner。

Execute,也就是执行。 选取计划中的步骤,调用工具或其他处理逻辑,得到对应结果。这部分职责通常称为 Executor。

例如,Planner 安排"核对原仓的预计到货时间",Executor 再决定需要查询哪些信息。

一个计划步骤不一定对应一次工具调用。 核对到货时间,可能需要先查订单,再查备货时间,最后查询配送时效。

2.先采用一个简化版本

为了看清后面的演变过程,我们先约定:

Planner 只生成一次总体计划。执行器可以根据反馈完成当前步骤,但系统暂时不修改总体计划。

这里限制的是总体计划的修订。执行器仍然可以补查信息、记录失败,或者调整当前步骤里的工具调用方式。

这是本文的教学简化。LangChain 官方的 Plan-and-Execute 介绍本身就包含执行后的重规划,因此不能把"计划始终不变"当成所有 Plan-Execute 实现的共同定义。

3.用订单到货查询串起整个流程

**案例说明:**下文的订单、仓库、费用、工具名称与返回结果均为教学模拟。工具调用使用示意写法,不对应某个平台的实际 API;到货时间表示当前信息下的预计结果。

假设现在是周二上午,用户提出下面的需求,时间统一使用北京时间:

帮我看看订单 O1001 能不能在本周五 18:00 前收到。如果原来的安排赶不上,查一下其他办法。商品、数量和收货地址保持不变,可以考虑其他仓库或配送方式,额外总费用不能超过 20 元。本次只查询并给建议。

订单购买了 1 件 SKU-01 商品,目前安排由 A 仓发货。库存和配送情况还需要进一步查询。

先从原仓路线开始,给出一份尚未展开替代方案的初始计划。下面观察执行反馈如何暴露计划中的缺项,再通过重规划补齐剩余工作。

步骤 工作内容 预期产物
P1 确认订单、商品、数量、收货地址和原发货仓 订单基础信息
P2 核对 A 仓供货情况和预计到货时间 原仓路线的时效判断及依据
P3 在原仓路线能满足期限的前提下,整理到货安排 原仓方案
P4 汇总到货判断、处理建议及相关条件 给用户的查询结果

注意,P3 依赖"原仓路线能够按时到货"这个待验证前提。用户允许评估其他仓库,并没有要求必须沿用 A 仓。

如果 P2 确认原仓能够按时送达,后面就可以直接整理安排和建议。接下来我们会看到,这个前提也可能被查询结果推翻。

4.再看控制流程

现在有了具体任务,再看流程图就容易对应了:Planner 生成 P1~P4,执行器依次处理步骤,每次结果都会被保存,但图中没有返回 Planner 修改计划的路径。
#mermaid-svg-FEjdeiQILmSTPk3D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FEjdeiQILmSTPk3D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FEjdeiQILmSTPk3D .error-icon{fill:#552222;}#mermaid-svg-FEjdeiQILmSTPk3D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FEjdeiQILmSTPk3D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FEjdeiQILmSTPk3D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FEjdeiQILmSTPk3D .marker.cross{stroke:#333333;}#mermaid-svg-FEjdeiQILmSTPk3D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FEjdeiQILmSTPk3D p{margin:0;}#mermaid-svg-FEjdeiQILmSTPk3D .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FEjdeiQILmSTPk3D .cluster-label text{fill:#333;}#mermaid-svg-FEjdeiQILmSTPk3D .cluster-label span{color:#333;}#mermaid-svg-FEjdeiQILmSTPk3D .cluster-label span p{background-color:transparent;}#mermaid-svg-FEjdeiQILmSTPk3D .label text,#mermaid-svg-FEjdeiQILmSTPk3D span{fill:#333;color:#333;}#mermaid-svg-FEjdeiQILmSTPk3D .node rect,#mermaid-svg-FEjdeiQILmSTPk3D .node circle,#mermaid-svg-FEjdeiQILmSTPk3D .node ellipse,#mermaid-svg-FEjdeiQILmSTPk3D .node polygon,#mermaid-svg-FEjdeiQILmSTPk3D .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FEjdeiQILmSTPk3D .rough-node .label text,#mermaid-svg-FEjdeiQILmSTPk3D .node .label text,#mermaid-svg-FEjdeiQILmSTPk3D .image-shape .label,#mermaid-svg-FEjdeiQILmSTPk3D .icon-shape .label{text-anchor:middle;}#mermaid-svg-FEjdeiQILmSTPk3D .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FEjdeiQILmSTPk3D .rough-node .label,#mermaid-svg-FEjdeiQILmSTPk3D .node .label,#mermaid-svg-FEjdeiQILmSTPk3D .image-shape .label,#mermaid-svg-FEjdeiQILmSTPk3D .icon-shape .label{text-align:center;}#mermaid-svg-FEjdeiQILmSTPk3D .node.clickable{cursor:pointer;}#mermaid-svg-FEjdeiQILmSTPk3D .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FEjdeiQILmSTPk3D .arrowheadPath{fill:#333333;}#mermaid-svg-FEjdeiQILmSTPk3D .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FEjdeiQILmSTPk3D .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FEjdeiQILmSTPk3D .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FEjdeiQILmSTPk3D .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FEjdeiQILmSTPk3D .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FEjdeiQILmSTPk3D .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FEjdeiQILmSTPk3D .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FEjdeiQILmSTPk3D .cluster text{fill:#333;}#mermaid-svg-FEjdeiQILmSTPk3D .cluster span{color:#333;}#mermaid-svg-FEjdeiQILmSTPk3D div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FEjdeiQILmSTPk3D .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FEjdeiQILmSTPk3D rect.text{fill:none;stroke-width:0;}#mermaid-svg-FEjdeiQILmSTPk3D .icon-shape,#mermaid-svg-FEjdeiQILmSTPk3D .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FEjdeiQILmSTPk3D .icon-shape p,#mermaid-svg-FEjdeiQILmSTPk3D .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FEjdeiQILmSTPk3D .icon-shape .label rect,#mermaid-svg-FEjdeiQILmSTPk3D .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FEjdeiQILmSTPk3D .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FEjdeiQILmSTPk3D .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FEjdeiQILmSTPk3D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 继续执行
无剩余步骤
前提失效
用户目标与约束
生成初始计划
选取当前步骤
执行步骤
保存结果
后续安排
检查并汇总
返回阶段结果

下面用语言无关的伪代码表示,重点看计划怎样被使用:

text 复制代码
计划 ← Planner(目标, 约束)
历史 ← 空记录

按依赖顺序处理计划中的步骤:
    结果 ← Executor(当前步骤, 约束, 历史)
    保存步骤状态、结果和依据

    如果后续步骤的关键前提不成立:
        返回阶段结果、未完成项和原因

核对目标与交付内容,返回汇总结果

这里的历史需要由程序保存,再提供给后续步骤。新的模型调用不会自动知道之前查到了什么。

三.当新信息推翻了原来的假设

1.工具成功返回,原仓路线却赶不上了

执行到 P2 时,查询得到以下信息:

text 复制代码
【教学模拟:E1,原仓供货与配送信息】

订单:O1001,尚未出库
原发货仓:A
当前可用库存:0
预计补货时间:本周六 10:00
按该备货时间估算的到货时间:下周一 18:00

库存与配送工具正常返回了信息,但这些信息说明:按照当前供货安排,A 仓路线无法满足本周五 18:00 前到货的要求。

再看原来的 P3:

在原仓路线能满足期限的前提下,整理到货安排。

它的执行前提已经不成立了。接下来要调查的内容变成了:其他仓库有没有同款现货?能否送到原地址?到货时间和额外费用是否符合要求?

这些工作还没有包含在原计划中。

2.原计划还能交付什么

基础版本可以停止这条路线,并告诉用户:原仓缺货,按现有安排预计下周一到货,赶不上要求的时间。

这个回答有依据,但只完成了需求的一部分。用户还要求了解其他办法,而我们尚未调查其他发货方案。

初始计划建立在不完整的信息上,执行过程中得到的新信息,可能改变剩余工作本身。

如果初始计划已经安排了其他仓库评估,这里可以按条件继续执行。固定工作流可以覆盖预先设计的分支,Replan 则允许系统根据新结果补充或调整安排。

四.通过 Replan 更新剩余计划

Replan,也就是重规划,负责结合执行结果检查:目标是否已经满足,剩余计划是否仍然合适,需要继续、修改,还是结束。

加入这项职责后,就形成了 Plan → Execute → 检查结果 → Replan 的循环。本文将其称为 Plan-Execute-Replan。

Planner、Executor 和 Replanner 是逻辑职责,可以使用同一个模型配合不同输入和程序控制完成,不必对应三个独立 Agent。

1.重规划需要哪些信息

如果只把"A 仓没货"交给 Replanner,它还不知道用户是否着急、能否接受加价,也不知道哪些事情已经查过。

在当前案例中,它需要一起看到这些信息。

  • **原始目标:**判断能否按时到货,并给出处理建议。
  • **用户约束:**本周五 18:00 前收到,商品、数量和地址不变,额外总费用不超过 20 元。
  • **已完成工作:**P1 已确认订单信息,P2 已完成原仓供货与时效核查。
  • **新观察及依据:**E1 表明原仓预计周六补货,按当前安排预计下周一到货。
  • **剩余计划:**P3 原本准备整理原仓方案,P4 再汇总建议。

这些信息放在一起,才能判断哪些步骤需要保留,哪些步骤需要调整。原仓赶不上,并不意味着可以自行放宽用户的到货期限或费用上限。

2.计划究竟改了什么

前面准备沿用原仓,现在查询结果已经否定了这个前提。原来的 P3 需要调整,先把其他方案的调查补上:

原计划 更新后的安排 修改原因
P1:确认订单基础信息 保留完成状态和查询结果 商品、数量和地址仍然是后续查询的依据
P2:核对原仓供货与时效 保留完成状态和 E1 已经查明原仓路线赶不上期限
P3:整理原仓方案 P3:评估其他仓库的配送方案,寻找满足到货期限和费用上限的候选 原仓赶不上,需要评估其他仓库的现货和配送方案
P4:汇总建议 汇总候选方案的费用、预计到货时间及办理条件 最终建议要建立在新调查上

这里将不同配送方式放在同一个计划步骤中评估,具体查询顺序由执行器根据反馈决定;实际工具如果能一次返回完整报价,也可以直接比较。

这次调整保留了已经完成的调查,只修改受影响的剩余工作。它也没有提前断言"其他仓库一定有合适方案",P3 还是待验证的任务。

3.什么时候需要检查计划

本例由一条成功取得的新信息触发重规划,过程中并没有必须发生的工具报错。

其他需要检查的情况还包括:取得的报价违反费用约束,且当前步骤内没有可继续评估的方案;必要接口持续不可用;多次查询没有带来进展;已有结果已经足够回答用户,可以取消多余步骤。

实现时,可以每完成一个步骤就检查,也可以在关键发现出现时提前交接。

检查计划,不等于每次都必须改写计划。 如果新的情况已经被剩余步骤覆盖,继续执行就可以了。

4.怎样判断可以结束

完成判断要对照用户需求:原仓能否按时到货、有哪些符合约束的候选方案,以及办理时需要满足哪些条件,这些问题是否已经回答清楚。

计划列表为空,只表示没有剩余条目,还需要检查有没有遗漏工作。

如果查过的方案都不满足要求,可以给出"本次已核查的方案均不符合约束"的结论。如果只是关键资料没有查到,则应说明"目前还不能判断"。两种结果的依据不同。

调用次数、运行时间和无进展限制也会影响何时停止,后面结合双层循环的伪代码一起说明。

五.让推理与行动交替进行:ReAct

1.ReAct 的核心思想

ReAct 来自 Reasoning 与 Acting,核心是让推理与行动交替进行:根据目标和已有观察决定下一步,通过行动获得新信息,再让新信息影响后续决策。

ReAct 原论文中常见的表示是:

text 复制代码
Thought:决定下一步
    ↓
Action:执行行动
    ↓
Observation:获得观察
    ↓
结合目标与新观察,继续决定下一步

这是一种组织决策与行动的方式,不要求实现必须公开模型的内部思考。下文使用人为编写的简短决策摘要来解释过程。

2.用三个连续阶段看清执行过程

先让 ReAct 直接负责完整的订单查询目标,看看下一次行动怎样受到上一条结果的影响。到第七章,再把它放进具体的计划步骤中。

2.1确认订单,发现原仓赶不上

先确认订单对应的商品和仓库,再核对当前到货安排。查询发现订单还没有明确的预计到货日期,就继续补查供货信息。

text 复制代码
【教学模拟:原仓查询过程】

查询订单("O1001")
→ 1 件 SKU-01,原仓 A,尚未出库,取得原收货地址。

查询原订单预计到货("O1001")
→ 等待补货,预计到货日期暂缺。

查询补货("A", "SKU-01")
→ 当前可用库存为 0,预计本周六 10:00 补货。

估算配送("A", 原收货地址, "本周六 10:00 备货", "普通")
→ 预计下周一 18:00 到货。

这里在"到货日期暂缺"后继续查询,根据缺货信息补查备货时间,再取得配送估算,形成前面的 E1。

原仓路线赶不上期限,下一步就需要调查其他仓库。

2.2找到加急方案,发现费用超出约束

接下来查询同一商品的其他发货方案,先核对加急配送是否可行。

text 复制代码
【教学模拟:E2,其他仓库与加急报价】

查询其他仓库方案("O1001")
→ B 仓同一 SKU 可用库存为 4 件。
→ 该订单支持申请改由 B 仓发货,原地址可配送。
→ 可查询加急和普通两种配送报价。

查询配送报价("O1001", "B", "加急")
→ 预计本周四 18:00 到货。
→ 额外总费用:35 元。
→ 报价要求:本周二 16:00 前确认改仓与配送安排。

这个方案的预计到货时间符合要求,但额外费用是 35 元,超过用户给出的 20 元上限。加急方案因此不能作为符合本次要求的建议。

工具已经返回 B 仓还支持普通配送,接下来就可以继续查它的时效和费用。

2.3核对普通配送,形成候选建议

我们已经取得 B 仓库存和该订单的改仓条件,可以沿用这些信息,继续核对普通配送报价。

text 复制代码
【教学模拟:E3,B 仓普通配送报价】

查询配送报价("O1001", "B", "普通")
→ 预计本周五 16:00 到货。
→ 额外总费用:10 元。
→ 报价要求:本周二 16:00 前确认改仓与配送安排。

按当前报价,普通配送的预计时间早于周五 18:00,额外费用也没有超过 20 元,因此可以作为候选方案。

回头看这三个阶段:没有明确到货日期,就补查供货;原仓赶不上,就查其他仓库;加急超预算,就继续核对普通配送。后一个动作都有前一个观察作为依据。

3.ReAct 能不能规划

ReAct 也能拆解目标、形成计划,还能跟踪进展,并根据反馈调整安排。原论文就将这些列为推理的用途。

它与显式 Plan-Execute-Replan 的主要区别在于:是否把总体计划及其修订设置为独立的控制层。 典型 ReAct 循环可以直接围绕目标选择行动,不要求先创建一份单独维护的完整计划对象。

在较长任务中,如果状态管理不足,ReAct 可能重复查询已经查过的仓库,或者忽略先前的费用限制。这时就需要加强结果记录、阶段目标和进展检查。

六.Plan-Execute-Replan 与 ReAct 怎样比较

下面比较两种典型组织方式。它们的能力范围存在重叠,也可以组合使用。

比较维度 Plan-Execute-Replan ReAct
主要关注 显式管理总体步骤、依赖和剩余工作 根据目标与观察选择下一步行动
怎样使用反馈 更新步骤记录,检查目标与剩余计划 直接影响接下来的行动选择
调整时机 步骤完成、关键发现或异常等检查点 获得新观察后即可调整下一步
长任务中的特点 便于检查进度、遗漏和路线变化 需要注意历史管理、重复行动和目标偏离
成本与延迟 增加规划和重规划调用,也可能减少无效探索 多轮决策会产生开销,短任务也可能很快结束
常见适用情况 多阶段、有依赖、需要持续检查进度的任务 需要根据工具结果不断决定下一步的任务

成本需要结合具体分工判断。如果几次查询就能完成任务,再加入规划和重规划可能增加等待;如果任务包含多个相互依赖的调查阶段,显式计划则有助于管理剩余工作。

还有一种组织方式:保留总体计划,在执行某个步骤时使用 ReAct。下面重点看它们怎样配合。

七.Plan-Execute-Replan 与 ReAct 如何协作

1.先看两层怎样连接

一种常见的组合是:外层通过 Plan-Execute-Replan 管理总体任务,内层 ReAct Executor 完成当前步骤。

LangGraph 的官方归档教程展示了这种结构:用 ReAct 执行器处理计划中的当前步骤,再将结果交给重规划逻辑。这里参考其架构,归档代码不作为当前 API 的使用指南。

看图时关注两个循环,以及内层向外层交接的位置:
#mermaid-svg-lpIEP1QrSeeLElvm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lpIEP1QrSeeLElvm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lpIEP1QrSeeLElvm .error-icon{fill:#552222;}#mermaid-svg-lpIEP1QrSeeLElvm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lpIEP1QrSeeLElvm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lpIEP1QrSeeLElvm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lpIEP1QrSeeLElvm .marker.cross{stroke:#333333;}#mermaid-svg-lpIEP1QrSeeLElvm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lpIEP1QrSeeLElvm p{margin:0;}#mermaid-svg-lpIEP1QrSeeLElvm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lpIEP1QrSeeLElvm .cluster-label text{fill:#333;}#mermaid-svg-lpIEP1QrSeeLElvm .cluster-label span{color:#333;}#mermaid-svg-lpIEP1QrSeeLElvm .cluster-label span p{background-color:transparent;}#mermaid-svg-lpIEP1QrSeeLElvm .label text,#mermaid-svg-lpIEP1QrSeeLElvm span{fill:#333;color:#333;}#mermaid-svg-lpIEP1QrSeeLElvm .node rect,#mermaid-svg-lpIEP1QrSeeLElvm .node circle,#mermaid-svg-lpIEP1QrSeeLElvm .node ellipse,#mermaid-svg-lpIEP1QrSeeLElvm .node polygon,#mermaid-svg-lpIEP1QrSeeLElvm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lpIEP1QrSeeLElvm .rough-node .label text,#mermaid-svg-lpIEP1QrSeeLElvm .node .label text,#mermaid-svg-lpIEP1QrSeeLElvm .image-shape .label,#mermaid-svg-lpIEP1QrSeeLElvm .icon-shape .label{text-anchor:middle;}#mermaid-svg-lpIEP1QrSeeLElvm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lpIEP1QrSeeLElvm .rough-node .label,#mermaid-svg-lpIEP1QrSeeLElvm .node .label,#mermaid-svg-lpIEP1QrSeeLElvm .image-shape .label,#mermaid-svg-lpIEP1QrSeeLElvm .icon-shape .label{text-align:center;}#mermaid-svg-lpIEP1QrSeeLElvm .node.clickable{cursor:pointer;}#mermaid-svg-lpIEP1QrSeeLElvm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lpIEP1QrSeeLElvm .arrowheadPath{fill:#333333;}#mermaid-svg-lpIEP1QrSeeLElvm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lpIEP1QrSeeLElvm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lpIEP1QrSeeLElvm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lpIEP1QrSeeLElvm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lpIEP1QrSeeLElvm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lpIEP1QrSeeLElvm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lpIEP1QrSeeLElvm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lpIEP1QrSeeLElvm .cluster text{fill:#333;}#mermaid-svg-lpIEP1QrSeeLElvm .cluster span{color:#333;}#mermaid-svg-lpIEP1QrSeeLElvm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lpIEP1QrSeeLElvm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lpIEP1QrSeeLElvm rect.text{fill:none;stroke-width:0;}#mermaid-svg-lpIEP1QrSeeLElvm .icon-shape,#mermaid-svg-lpIEP1QrSeeLElvm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lpIEP1QrSeeLElvm .icon-shape p,#mermaid-svg-lpIEP1QrSeeLElvm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lpIEP1QrSeeLElvm .icon-shape .label rect,#mermaid-svg-lpIEP1QrSeeLElvm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lpIEP1QrSeeLElvm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lpIEP1QrSeeLElvm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lpIEP1QrSeeLElvm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外层:Plan-Execute-Replan
内层:ReAct Executor
下发步骤输入
否
是
继续
调整
验收通过
阻塞或停止
用户目标与约束
生成初始计划
选择步骤
决定下一步
需要交接?
调用工具
记录观察
返回步骤结果
更新执行历史
检查目标与计划
修改剩余计划
交付最终结果
交付阶段结果

"需要交接"包括步骤完成、发现影响总体安排的问题、无法继续调查,或局部预算到限。内层可以调用多次工具,再向外层返回一次结果。

全局预算由运行程序统一检查,可以在任一调用前触发停止;图中只保留主要交接路径,具体控制放在后面的伪代码中。

2.把订单案例连续执行一遍

2.1外层选择 P2,并下发步骤输入

P1 已经完成,外层选择 P2。此时发送给执行器的内容可以是:

text 复制代码
【教学模拟:P2 的步骤输入】

步骤目标:核对 A 仓供货与配送安排,判断原路线是否符合到货期限。

已有上下文:
订单 O1001,1 件 SKU-01,原发货仓为 A,原收货地址已取得。

用户约束:
本周五 18:00 前收到;商品、数量和地址不变;
额外总费用不超过 20 元;本次只查询并给建议。

局部完成条件:
取得原仓供货与预计到货依据,给出明确判断。
关键资料缺失时,返回尚未完成及缺失原因。

工作范围:
本步骤核查原仓,替代路线交给外层安排。

这里的完成条件是"查明原路线是否符合期限"。得出"不符合"的结论,也因此可以完成这个调查步骤。

2.2内层补查信息,并返回结果包

执行器先查询原订单预计到货时间,发现日期暂缺,于是补查备货情况,再估算配送时效:

text 复制代码
【教学模拟:P2 内部的行动与观察】

查询原订单预计到货 → 等待补货,暂缺到货日期
查询 A 仓补货安排 → 预计本周六 10:00 补货
根据备货时间估算配送 → 预计下周一 18:00 到货

这个过程中,执行器调整了调查路径,但始终围绕 P2 的目标工作。取得 E1 后,它向外层返回:

text 复制代码
【教学模拟:P2 的返回结果】

步骤状态:已完成
结论:按当前供货与时效信息,原仓路线不能满足到货期限。

依据:
E1,A 仓补货查询与配送估算。
预计本周六 10:00 补货,按该备货时间预计下周一 18:00 到货。

对剩余计划的影响:
P3 所依赖的"原仓能够按时到货"前提不成立。

还缺少的工作:
其他仓库及配送方式的调查。

实际系统还应保留查询时间、关键参数和来源,便于复核库存、报价等会变化的信息。

注意,此时这三个状态同时存在。

  • **工具调用成功:**取得了供货和配送信息。
  • **当前步骤完成:**已经回答原仓能否满足期限。
  • **原路线受阻:**沿用原仓无法满足本次要求,需要评估其他办法。

如果只返回一个"失败",外层就难以分清是接口没有查通,还是已经查明路线不合适。前一种情况可能需要补查,后一种情况需要调整剩余工作。

2.3Replanner 调整剩余计划

Replanner 结合目标和约束,参考 E1 与当前计划,保留 P1、P2 的完成记录,将原来的 P3 替换为第四章中的候选方案调查:

text 复制代码
【教学模拟:更新后的剩余计划】

P3:评估其他仓库的配送方案,寻找满足到货期限和费用上限的候选。
P4:汇总候选方案、费用、预计到货时间及办理条件。

这里增加了原计划没有覆盖的工作,原始到货期限和费用限制继续生效。

2.4ReAct 执行新步骤,外层继续检查

外层下发新的 P3。ReAct Executor 查询其他仓库和加急报价,取得 E2:B 仓有同款现货,但加急需要额外支付 35 元,超出上限。

评估还没有结束。执行器根据 20 元的费用上限排除加急方案,继续核对普通配送,这些行动都在 P3 内部完成。

查询得到 E3:预计周五 16:00 到货,额外费用 10 元,报价要求周二 16:00 前确认安排。执行器将普通配送作为候选,连同 E2、E3 的依据一起返回外层。

Replanner 检查候选与剩余计划,确认可以继续执行 P4,整理给用户的建议。这一次需要检查,但没有必要再生成一份全新计划。

2.5完成整体交付检查

P4 可以形成下面这样的结果:

text 复制代码
【教学模拟:最终建议】

原仓安排:
A 仓预计本周六补货,按当前安排预计下周一到货,赶不上要求。
依据:E1。

加急方案:
B 仓加急预计周四到货,但额外总费用为 35 元,超过费用上限。
依据:E2。

候选建议:
申请改由 B 仓使用普通配送,商品、数量和地址不变。
按当前报价,预计周五 16:00 到货,额外总费用为 10 元。
依据:E2 中的改仓条件,以及 E3 的普通配送报价。

办理条件:
需在本周二 16:00 前确认改仓和配送安排,办理时复核库存与报价。
到货时间为预计值。

当前进度:
已形成查询建议,尚未修改订单或锁定库存。

外层检查的重点是:原仓判断有没有依据,候选方案是否符合商品、地址、时间和费用要求,办理条件与不确定性有没有交代清楚。

这些内容齐全,才满足本次"查询并给建议"的目标。仅有 P4 的"已完成"标记还不够。

3.局部调整与总体重规划的边界

刚才的过程可以这样区分。

  • 到货日期暂缺,转而查询补货时间:仍在回答 P2 的问题,由内层 ReAct 继续调查。
  • 查明原仓赶不上,新增其他仓库与配送方式的评估:改变了剩余工作,由外层 Replanner 调整。
  • 加急超预算,继续核对普通配送:仍在完成 P3 的候选评估,由内层 ReAct 处理。

这个边界取决于当前步骤被赋予的目标和范围。本例把配送方案评估放在同一个 P3 中,因此加急与普通配送的切换都由内层处理。

第五章的 ReAct 直接负责完整查询目标,可以自行推进整条调查;本章将它放入明确的计划步骤,交接范围就随之收窄。

4.用伪代码看两层怎样衔接

先看内层。与第二章相比,这里把 Executor 展开成一个循环,能够继续调查,也能够向外层交接:

text 复制代码
过程 ReAct执行(步骤, 上下文, 约束, 共享预算):
    局部记录 ← 必要上下文

    循环:
        如果满足局部完成条件:
            返回已完成的结果包

        如果发现需要外层处理的问题:
            返回步骤进展、依据和对总体计划的影响

        如果全局停止条件触发,或局部调查无法继续:
            返回阶段结果、缺失信息和停止原因

        行动 ← 根据步骤目标、约束与局部记录决定下一步
        结果 ← 执行行动并记录结果
        更新局部记录、证据、预算和进展状态

行动可以是工具调用,也可以是整理结论。模型提出结束时,仍要按局部完成条件检查证据是否足够;交接结果还要区分步骤是否完成。

再看外层。结果先进入历史,Replanner 才能据此安排下一步:

text 复制代码
共享预算 ← 初始化一次任务的全局预算
计划 ← Planner(目标, 约束)
历史 ← 空记录

循环:
    如果全局停止条件触发:
        返回阶段成果、未完成项和原因

    步骤 ← 从计划中选取当前可执行步骤

    如果步骤存在:
        结果 ← ReAct执行(步骤, 必要上下文, 约束, 共享预算)
        更新历史中的步骤状态、结果和依据

    如果全局停止条件触发:
        返回阶段成果、未完成项和原因

    决策 ← Replanner(目标, 约束, 计划, 历史)

    如果决策为完成:
        如果整体交付检查通过:
            返回最终结果
        否则:
            将缺项补入剩余计划,继续循环

    如果决策为阻塞:
        返回已有成果和缺失条件

    根据决策保留或更新剩余计划

这些伪代码用于说明控制结构,省略了工具参数校验、异常处理等实现细节。每次实际模型或工具调用前,都需要由运行程序检查预算和超时;达到全局上限时直接走停止出口,不能继续调用 Replanner。

可以为教学实现设置一组限制:单个步骤最多调用工具 6 次,整个任务最多调用工具 20 次、模型 30 次,总耗时不超过 5 分钟。连续两次外层检查都没有新增证据、排除候选或推进步骤时,也停止并报告进展不足。

这些数字只是配置示例。模型调用次数应覆盖 Planner、ReAct 内部决策、Replanner,以及额外的模型检查;进入新步骤时,局部额度可以重新分配,全局预算继续累计。

5.什么时候值得使用这种组合

这种组合适合有多个总体阶段的任务,阶段内部又需要根据反馈继续探索,例如复杂订单异常处理和跨系统故障调查,也包括多来源资料分析。

它也会增加模型调用、状态维护和交接成本。步骤划分过细,外层会频繁介入;步骤过大,外层又难以掌握实际进展。

对于规则固定的订单查询,如果一次接口就能返回完整结果,直接使用业务工作流会更简单。需要持续管理剩余任务,同时又无法预先确定每一次工具行动时,外层规划与内层 ReAct 的分工才更有价值。

相关推荐
在世修行1 小时前
智学文枢:数据备份与恢复
python·数据安全·备份恢复·zipfile
OpsEye1 小时前
模型能力波动怎么办?网关侧做模型质量监控与自动切换
javascript·ai编程
ONEYAC唯样2 小时前
TE:不只看产品,更要看价值:下一代高压连接方案如何选择?
python·django
高洁012 小时前
具身智能感知系统底层原理
人工智能·python·深度学习·机器学习·transformer
const_qiu2 小时前
第四章 05:4.5 Multi-Agent —— 五个专职智能体协作
java·人工智能
我就是不信2 小时前
Java8 lambda 表达式 forEach 如何提前终止?
开发语言·windows·python
A小码哥2 小时前
大模型成本怎么降,5 个动作先做前两个
java·前端·spring
鬼手点金2 小时前
构建有效 Agent 的核心原则
java·人工智能·git·学习·自动化
全栈弄潮儿2 小时前
Python实战第9期:文件操作
后端·python·编程语言