知识与集成

企业级 AI Agent“计划与执行”(Plan-and-Execute)架构实战:破解长程任务拓扑解耦、动态重规划(Re-planning)与断点容错

针对企业在跨系统复杂长程业务中 ReAct 架构易陷入局部死循环与上下文遗忘难题,深度解构 DAG 任务拓扑生成、执行器(Executor)多任务并行调度、动态增量重规划(Re-planning)触发机制与状态机断点容错引擎,并给出生产级 TypeScript 架构实现方案。

百信 AI Agent发布于 约 9 分钟
企业级 AI Agent 计划与执行架构拓扑与动态重规划控制中心工作台示意图
企业级 AI Agent 计划与执行架构拓扑与动态重规划控制中心工作台示意图

在企业级智能体落地过程中,当业务需求从单轮检索或单步工具调用升级到跨 ERP/MES 供应链排产调整、企业财务年度账目核验、数据中心批量离线巡检等长程任务(Long-horizon Tasks)时,传统的单步循环思考(ReAct / Reflexion)模式暴露出显著瓶颈:由于每一步决策都高度依赖完整对话历史,随着执行步数增加,上下文急剧膨胀,不仅导致推理成本呈二次方激增,更极易引发“长视野迷失(Horizon Loss)”、工具调用陷入死循环以及无法并发执行互不依赖的子步骤。为了攻克长程复杂业务编排难题,“计划与执行”(Plan-and-Execute)架构成为了现代企业级智能体系统的核心范式。本文结合百信企业智能体平台的私有化生产实践,深度拆解由 Planner 进行任务拓扑解耦与 DAG 有向无环图生成、由执行器(Executor)进行上下文隔离与高并发调度、通过增量动态重规划(Re-planning)应对真实系统环境变化,以及结合 Checkpointer 机制实现秒级断点恢复与幂等容错的完整架构。

企业长程复杂任务痛点:ReAct 架构局限与 Plan-and-Execute 范式演进

在大模型驱动的智能体系统演进中,经典的 ReAct(Reasoning + Acting)架构通过“思考-行动-观察(Thought-Action-Observation)”的紧密交替循环,在解决 3~5 步内的短链任务中表现卓越。然而,一旦面对跨系统、多前置条件、耗时数十分钟甚至需要人工审批的长程企业任务,其底层机理便暴露出三大深层次困境:

1. 单步贪婪试错的“视野狭隘”与死循环陷阱(Horizon Loss & Tool Oscillation)

ReAct 的核心假设是“每一步行动都基于前一步的即时反馈进行贪婪推断”。这种缺乏全局蓝图的局部试错机制,在复杂业务中极易导致:

  • 局部最优陷阱:智能体在处理供应链突发缺料预警时,为了满足局部某个紧急订单,直接调用采购接口下单,却忽略了后续步骤中由于仓储库容不足、关税申报排期冲突带来的全局系统性瘫痪;
  • 工具调用震荡与死锁:当查询接口返回“参数不完整”或“权限受限”时,ReAct 容易在相邻两个接口之间反复切换重试,直到耗尽最大轮次或预算熔断,无法从更高维度意识到需要重新规划执行路径。

2. 线性上下文滚雪球与注意力稀释(Context Dilution)

在 ReAct 循环中,每次观察到的外部接口返回数据(如一段数百行的 JSON 结构体)都会不加筛选地追加到总 Prompt 中:

  • 注意力分散与指令漂移:当执行到第 10 步时,上下文已累积数万 Token,底层模型对最初系统设定的核心业务规则(如“严禁在未确认预算前生成订单”)的遵从率显著下滑;
  • 无法并行(Sequential Bottleneck):即使任务中包含 4 个彼此毫无依赖关系的子系统数据拉取任务(例如同时拉取 ERP 财务凭证、CRM 客户评级、WMS 库位状态和税务发票池),ReAct 也只能按序串行执行,导致端到端耗时被无限拉长。
编排架构范式规划与执行关系长视野控制与并发能力异常自愈与动态适应性适用业务场景边界
单步交替式 (ReAct)单步紧密耦合,思考与行动交替执行无全局视图,纯串行,超过 5 步易发生上下文漂移仅能局部贪婪调整,容易陷入工具调用死循环简单信息查询、单系统 3 步内操作
一次性求解 (Plan-and-Solve)前置生成全量静态步骤,随后机械按序执行具备全局视野,但执行过程中完全脱节真实环境极差:任何单步报错都会直接导致整个任务链崩溃确定性离线计算、封闭数学推理
分层主管 (Hierarchical Supervisor)树状分工,由中心主管逐级下发子任务支持复杂多团队协作,但主管节点存在路由单点瓶颈由各 Worker 或 Supervisor 独立处理,缺乏全局 DAG 优化跨部门大团队多智能体协同
计划与动态重规划 (Plan-and-Execute)全局 Planner 解耦 + DAG 拓扑执行 + 增量闭环 Replanner具备全局前瞻性,严格隔离局部上下文,原生支持并发 Fan-out极优:环境变化时仅增量修正未执行子图,已完成节点幂等保留跨系统长程业务流、复杂报表批处理、企业级运维自动化

核心架构解构:Planner 拓扑解耦、DAG 有向无环图与 Executor 分布式执行

在 Plan-and-Execute 架构中,系统将“思考要做什么(宏观规划)”与“具体怎么做(微观执行)”进行物理级解耦,构建了由规划器(Planner)、任务拓扑(DAG Graph)和执行器池(Executor Engine)组成的三层系统结构:

1. 规划阶段(Planning Phase):全局意图向有向无环图(DAG)映射

Planner 通常由高推理能力的基座大模型(如通过系统提示词专门强化的任务分解器)承担。它并不直接调用业务系统接口,而是专注将用户的非结构化宏观目标,分解为一组具有严格依赖关系的结构化子任务节点:

  • 显式依赖声明(Explicit Dependency Declaration):每个任务节点明确声明前置依赖项(如 dependencies: ["task_fetch_erp", "task_verify_wms"]),形成合法的 DAG 拓扑,杜绝隐式时序假设;
  • 局部上下文最小化(Context Minimization):Planner 为每个任务节点生成高度自包含的执行目标与参数期望,Executor 在执行具体节点时无需加载其他无关分支的细节日志。

2. 结构化任务节点规范(Task Node Schema)

在企业级私有化引擎中,任务节点必须遵循强类型的 JSON Schema 契约:

// 生产级任务节点数据结构定义
export interface PlanTaskNode {
  id: string;                         // 任务唯一标识,如 task_01_query_erp
  title: string;                      // 任务人类可读名称
  description: string;                // 执行指令描述,用于引导 Worker 专注于目标
  assignedWorker: string;             // 指定执行该任务的专业 Worker 或工具集
  dependencies: string[];             // 前置任务 ID 列表,全量完成方可激活本节点
  status: 'pending' | 'ready' | 'running' | 'completed' | 'failed' | 'skipped';
  inputSchema?: Record<string, any>;  // 输入参数映射(支持引用前置节点输出变量)
  outputResult?: any;                 // 节点真实执行输出,作为后续节点的上下文输入
  retryCount: number;                 // 当前重试次数
  maxRetries: number;                 // 最大允许局部重试次数
}

3. 执行阶段(Execution Phase):拓扑排序与高并发并发派发(Fan-out / Fan-in)

执行引擎维护一个动态任务队列,通过对 DAG 持续进行拓扑排序(Topological Sort)推进流程:

  • 就绪检测与并行扇出(Fan-out):当检测到多个节点的 dependencies 均已进入 completed 状态,调度器将这些节点同时分发给独立的 Executor Worker 进行高并发处理,大幅缩减总链路耗时;
  • 状态汇总与屏障同步(Fan-in Barrier):对于汇聚节点(如“根据 ERP 采购单与 MES 质检结果综合生成入库单”),执行引擎设置屏障等待,直到所有上游依赖节点全部写入中间结果黑板,才激活下游节点。

动态增量重规划(Re-planning):执行反馈闭环、拓扑变更条件与幻觉防御

传统的静态工作流一旦遭遇外部接口返回非预期数据(如 ERP 提示“物料已被占用”或“价格超过审批红线”)就会立即报错退出。Plan-and-Execute 架构的核心威力在于其具备**运行时的闭环动态重规划(Re-planning)**能力:

1. 动态重规划触发守卫条件(Re-planning Guardrails)

重规划是一个消耗模型推理算力的高开销操作,不能无节制触发。百信平台设计了三道严格的触发守卫(Guard Conditions):

  • 重大环境事实分歧(Environmental Divergence):当执行节点返回的外部业务事实与 Planner 最初的前置假设冲突(例如原本规划调用 A 供应商采购,接口返回其停产整改),局部重试无法修复时触发;
  • 前置节点执行彻底失败(Terminal Step Failure):某任务在达到 maxRetries 后依然失败,且该任务被下游多个核心任务强依赖,无法通过简单降级忽略时触发;
  • 新增动态前置条件发现(Dynamic Pre-condition Discovered):在执行某查询步骤后,返回结果指明需要先通过一道全新的法务审批流程,原 DAG 拓扑缺失该关键节点。

2. 增量拓扑重写算法(Incremental Re-planning Algorithm)

在触发重规划时,Replanner 绝不是推倒重来,而是实施**局部增量手术**:

  1. 冻结已完成节点(Freeze Completed Nodes):已执行成功节点(状态为 completed)及其产生的业务副作用(如已生成的采购预占单)被完全锁定为不可变上下文(Immutable Context),严禁被重新规划,防止重复写入系统;
  2. 裁剪失效未执行子图(Prune Orphan Branches):移除受阻断节点影响且已无意义的后续 pending 节点;
  3. 增量注入补救节点(Inject Remedial Sub-graph):Replanner 根据当前最新黑板上下文,为剩余未满足的目标生成新的替代路径(如由“调用主供应商”切换为“拆解为两家备选供应商采购并补发比价审批”),拼接到现有 DAG 中继续推进。

3. 重规划次数防雪崩熔断与防死锁(Budget & Loop Prevention)

为了防止大模型在复杂边界条件下陷入“规划-失败-重规划-再次失败”的无限震荡死循环:

  • 设置重规划预算上限(Max Re-planning Budget):全链路硬性限制重规划次数(通常建议设为 3 次)。一旦达到上限,直接将上下文与当前 DAG 状态打包,升级为人工审批或安全优雅降级;
  • 相似计划检测与语义去重(Semantic Plan Deduplication):通过计算新规划子图与历史已失败子图的编辑距离或语义相似度,若检测到 Replanner 试图复用已证明失败的执行策略,强行中断并提示模型更换求解逻辑。

状态治理与断点容错:中间变量持久化、Checkpointer 机制与幂等回退

在企业生产环境中,一个长程规划任务可能持续数小时(例如涉及跨部门审批与批量报表合成),中间难免遭遇网络波动、服务重启或异步等待。因此,状态治理与容错恢复机制是决定架构能否商用的分水岭:

1. 全局状态机与中间变量黑板(State Machine & Blackboard)

系统维护一个结构化的全局状态黑板,所有节点必须且只能通过黑板进行数据交互:

  • 变量引用契约(Variable Scoping & Referencing):下游任务可以通过统一语法(如 {{task_query_stock.output.available_qty}})引用上游产物,调度器在派发任务前自动完成参数插值与合法性校验;
  • 敏感信息掩码(Data Masking):对于涉及客户隐私或财务敏感字段,黑板支持字段级脱敏隔离,避免无关任务节点的 Worker 接收到超权限数据。

2. 检查点机制(Checkpointer)与秒级断点续跑

系统在每一个任务节点状态流转(如 running -> completed)或重规划完成的瞬间,触发 Checkpointer 执行不可变快照持久化:

{
  "checkpointId": "chk_20261105_04_008",
  "planId": "plan_erp_inventory_reconcile",
  "version": 4,
  "timestamp": "2026-11-05T09:35:12.000Z",
  "dagNodes": [
    { "id": "t1", "status": "completed", "output": { "discrepancyCount": 12 } },
    { "id": "t2", "status": "completed", "output": { "approvalStatus": "APPROVED" } },
    { "id": "t3", "status": "running", "retryCount": 1 }
  ],
  "blackboardState": { "auditId": "AUD-99812", "operator": "auto_agent_worker" }
}

当宿主进程崩溃或因维护重启后,系统能够根据 checkpointId 从外部数据库(如 PostgreSQL / Redis)直接恢复 DAG 内存状态,跳过所有已完成节点,实现真正无缝的断点续跑。

3. 分布式补偿与 Saga 幂等回退(Saga Compensation & Idempotency)

在涉及银行扣款、ERP 记账、工单关闭等具备真实副作用的外部系统调用时:

  • 节点绑定反向补偿逻辑(Compensation Actions):在声明写操作任务时,必须同时登记其反向回滚接口(如 execute: "createPurchaseOrder" 对应 compensate: "cancelPurchaseOrder");
  • 全局中止时的有序逆序回滚:当整条长程任务因不可抗力彻底失败且需退出时,系统沿着已完成的写操作节点路径进行逆序(Reverse-order)补偿调用,确保外部异构系统的数据强一致性。

生产级 TypeScript 引擎实战:DAG 调度器、动态重规划器与容错执行流

以下为百信在生产环境中运行的核心 Plan-and-Execute 调度引擎精简实现,完整展示了 DAG 拓扑解析、并行分发、反馈检测与增量重规划逻辑:

/**
 * 企业级 Plan-and-Execute 核心调度引擎
 * 职责:实现 DAG 拓扑排序、多 Worker 并行派发、环境变化感知与动态重规划闭环
 * 遵循严格生产规范与全中文注释说明
 */

// 任务节点定义接口
export interface PlanTask {
  id: string;                         // 任务全局唯一标识
  title: string;                      // 任务中文名称
  description: string;                // 执行指令细则
  dependencies: string[];             // 前置依赖任务 ID 数组
  status: 'pending' | 'ready' | 'running' | 'completed' | 'failed';
  result?: any;                       // 真实业务执行结果
  retryCount: number;                 // 重试计数
}

// 执行上下文与黑板共享状态
export interface ExecutionContext {
  planId: string;                     // 规划流程唯一 ID
  globalGoal: string;                 // 用户原始宏观业务目标
  tasks: Map<string, PlanTask>;       // 动态 DAG 任务哈希表
  blackboard: Record<string, any>;    // 共享上下文变量池
  replanningCount: number;            // 当前已触发的重规划次数
  maxReplanningBudget: number;        // 最大允许重规划次数
}

export class PlanAndExecuteEngine {
  private ctx: ExecutionContext;

  constructor(planId: string, globalGoal: string, initialTasks: PlanTask[]) {
    this.ctx = {
      planId,
      globalGoal,
      tasks: new Map(initialTasks.map(t => [t.id, { ...t }])),
      blackboard: {},
      replanningCount: 0,
      maxReplanningBudget: 3,
    };
  }

  /**
   * 核心主执行循环
   * 采用事件与拓扑驱动,持续派发无前置依赖的就绪任务,检测异常并触发重规划
   */
  public async executePipeline(): Promise<{ success: boolean; data: any }> {
    console.log(`[Plan-and-Execute] 启动流程: ${this.ctx.planId}, 目标: ${this.ctx.globalGoal}`);

    while (true) {
      // 1. 检查全量任务是否已全部顺利完成
      const allTasks = Array.from(this.ctx.tasks.values());
      const allCompleted = allTasks.every(t => t.status === 'completed');
      if (allCompleted) {
        console.log(`[Plan-and-Execute] 全流程执行完毕,已达成业务目标。`);
        return { success: true, data: this.ctx.blackboard };
      }

      // 2. 筛选当前满足依赖条件的“就绪”任务(Fan-out 并发源)
      const readyTasks = allTasks.filter(t => {
        if (t.status !== 'pending') return false;
        // 检查所有前置依赖项是否均已完成
        return t.dependencies.every(depId => {
          const depTask = this.ctx.tasks.get(depId);
          return depTask && depTask.status === 'completed';
        });
      });

      // 若没有就绪任务但整体未完成,检测是否存在失败节点
      if (readyTasks.length === 0) {
        const failedTask = allTasks.find(t => t.status === 'failed');
        if (failedTask) {
          console.warn(`[Plan-and-Execute] 捕获任务执行受阻节点: ${failedTask.title} (${failedTask.id})`);

          // 尝试触发增量动态重规划
          const replanned = await this.triggerReplanning(failedTask);
          if (!replanned) {
            // 重规划预算耗尽或无法生成替代路径,安全熔断
            return { success: false, data: { error: 'REPLANNING_EXHAUSTED', failedTask } };
          }
          // 重规划成功,重新进入主循环
          continue;
        }

        // 若无就绪任务且无失败任务(可能存在循环依赖死锁)
        const runningTasks = allTasks.filter(t => t.status === 'running');
        if (runningTasks.length === 0) {
          throw new Error('检测到 DAG 拓扑死锁或无法解析的前置依赖!');
        }
      }

      // 3. 并发派发所有就绪任务(Fan-out 并行执行)
      console.log(`[Plan-and-Execute] 本轮激活 ${readyTasks.length} 个并发就绪任务节点`);
      await Promise.all(readyTasks.map(task => this.runSingleTask(task)));

      // 4. 持久化检查点(Checkpointer Snapshot)
      this.saveCheckpoint();
    }
  }

  /**
   * 单任务节点沙箱化执行
   */
  private async runSingleTask(task: PlanTask): Promise<void> {
    task.status = 'running';
    console.log(`-> 正在执行子任务: [${task.id}] ${task.title}`);

    try {
      // 模拟调用底层真实工具/业务系统接口
      // 实际生产中此处派发给对应的 Tool / Worker Agent
      const mockResult = await this.mockExternalSystemCall(task);

      // 记录产出并更新黑板变量
      task.result = mockResult;
      task.status = 'completed';
      this.ctx.blackboard[task.id] = mockResult;
      console.log(`✓ 子任务顺利完成: [${task.id}]`);
    } catch (err: any) {
      task.retryCount++;
      console.error(`✗ 子任务异常: [${task.id}] 错误信息: ${err.message}`);

      // 简单的局部重试控制(最多重试 1 次,超出后标记为 failed 交给 Replanner)
      if (task.retryCount <= 1) {
        console.log(`[局部重试] 任务 ${task.id} 即将执行第 ${task.retryCount} 次重试...`);
        task.status = 'pending';
      } else {
        task.status = 'failed';
      }
    }
  }

  /**
   * 闭环动态增量重规划逻辑(Replanner)
   */
  private async triggerReplanning(failedTask: PlanTask): Promise<boolean> {
    this.ctx.replanningCount++;
    console.log(`[Replanner] 正在触发第 ${this.ctx.replanningCount} / ${this.ctx.maxReplanningBudget} 次动态重规划...`);

    if (this.ctx.replanningCount > this.ctx.maxReplanningBudget) {
      console.error(`[Replanner 熔断] 已达到重规划预算上限,终止自动重规划。`);
      return false;
    }

    // 1. 冻结不可变的 completed 任务,收集当前有效上下文
    const completedTasks = Array.from(this.ctx.tasks.values()).filter(t => t.status === 'completed');
    console.log(`[Replanner] 冻结 ${completedTasks.length} 个已完成历史节点,保证外部系统幂等。`);

    // 2. 模拟 LLM 动态评估:根据受阻原因,生成针对性的替代子路径
    // 假设失败原因是某个供应商缺货,动态重规划为拆单采购并补充审批
    console.log(`[Replanner] 正在重写依赖于 ${failedTask.id} 的后续子图...`);

    // 移除原失败节点及受阻的旧待定节点
    this.ctx.tasks.delete(failedTask.id);

    // 增量注入替代任务节点
    const altTask1: PlanTask = {
      id: `${failedTask.id}_alt_fallback_query`,
      title: '调用备选物料库并进行库存再分配',
      description: '主路径受阻,转向备选合格供应商物料目录进行可用性复核',
      dependencies: completedTasks.map(t => t.id).slice(-1), // 依赖最近一个完成项
      status: 'pending',
      retryCount: 0,
    };

    const altTask2: PlanTask = {
      id: `${failedTask.id}_alt_human_confirm`,
      title: '生成变动审计差异单并提交审批',
      description: '对价格与交期差异进行合规留痕',
      dependencies: [altTask1.id],
      status: 'pending',
      retryCount: 0,
    };

    // 将新节点注入 DAG
    this.ctx.tasks.set(altTask1.id, altTask1);
    this.ctx.tasks.set(altTask2.id, altTask2);

    console.log(`[Replanner] 增量注入 2 个补救节点成功,DAG 拓扑已重构。`);
    return true;
  }

  /**
   * 模拟外部业务系统调用
   */
  private async mockExternalSystemCall(task: PlanTask): Promise<any> {
    // 模拟微小网络时延
    await new Promise(r => setTimeout(r, 100));

    // 演示特定任务抛出受阻异常以展示重规划机制
    if (task.id === 'task_verify_primary_supplier' && task.retryCount === 0) {
      throw new Error('主供货商核心物料库存不足(系统返回 STOCK_EXHAUSTED)');
    }

    return { code: 200, message: '执行成功', timestamp: Date.now() };
  }

  /**
   * 检查点持久化保存(模拟存储到分布式存储)
   */
  private saveCheckpoint(): void {
    // 实际生产中将 this.ctx 序列化存储至 Redis / PostgreSQL
    // console.log(`[Checkpointer] 快照已持久化。当前任务数: ${this.ctx.tasks.size}`);
  }
}

落地工程边界与选型决策:ReAct、Plan-and-Execute 与分层 Supervisor 的适用场景对比

在企业级私有化 AI 平台落地中,并不存在适用于所有场景的“万能架构”。架构师必须根据任务的复杂度、耗时跨度、容错要求以及算力消耗进行科学选型:

1. 三大编排范式的工程选型决策树

  • 选用 ReAct 的场景:
    • 步骤少于 5 步,逻辑高度线性,且每一步必须紧跟最新外部反馈才能判断下一步;
    • 典型场景:简单客服问答中的知识库检索扩展、单接口参数自纠错、日常简单文档润色。
  • 选用 Plan-and-Execute 的场景:
    • 任务具备明确的全局最终交付目标,中间步骤多达 8~30 步,存在大量互不依赖可并发的子环节;
    • 执行耗时较长,对网络波动具备容忍度,强依赖断点续跑与不可变中间结果审计;
    • 典型场景:跨 ERP/MES 生产调度复核、多数据源财务并表稽核、自动化代码库安全大范围巡检。
  • 选用分层主管(Hierarchical Supervisor)的场景:
    • 任务需要高度垂直的专业领域知识,且不同角色具有截然不同的权限级别与工具集隔离需求;
    • 典型场景:大型企业多部门联合应急处置(法务、财务、研发与运维智能体跨部门联合攻关)。

2. 私有化部署下的 Token 吞吐与显存优化权衡

在企业私有云算力受限(如仅配备 2~4 张本地算力卡)的环境中,Plan-and-Execute 展现出压倒性的工程经济性:

  • 总 Token 消耗降低 40%~60%:相比 ReAct 将全量历史反复喂给大模型,Plan-and-Execute 的 Executor 仅接收当前节点的专用微观提示词,极大缩短了单次 Prompt 长度,避开了注意力机制的二次方显存爆炸;
  • 首字延迟与吞吐优化:Planner 生成全量骨架后,通过异步并发派发,使得算力卡的批处理(Batching)利用率提升至 85% 以上,大幅改善了企业级并发响应能力。

通过构建**全局 DAG 拓扑解耦、增量闭环动态重规划与 Checkpointer 状态持久化**的完整体系,企业智能体平台得以跨越玩具级 Demo 的死循环与上下文脆弱性泥潭,真正为工业级复杂长程业务提供稳健、确定且高可用的生产力支撑。