任务拆解错了怎么救:Agent 动态重规划(Replanning)工程策略
Agent 真正的可靠性,不是“一次规划就做对”,而是“做错了还能自救”。本文用工程视角拆解重规划:如何检测计划失效、如何最小代价修补、如何避免重试风暴与重复执行,并给出可落地的事件日志、状态机与回滚/补偿设计。

📷 Photo by RDNE Stock project via Pexels
先说结论:能上线的 Agent 必须“允许自己犯错”
很多团队把 Agent 的失败当成“模型不够聪明”。但在真实系统里,更常见的失败原因是:
- 计划依赖了不存在的前提(用户权限、数据字段、工具可用性)
- 执行中出现了新信息(工具返回与预期不同、数据被并发修改)
- 副作用不可逆(邮件已发、工单已创建、库存已扣)
所以“动态重规划”不是可选项,而是可靠性的核心。
如果你还没读过 Agent 的最小工程基线,建议先看:
一、先把概念工程化:重规划的输入不是 Prompt,而是“事实”
在工程语境里,重规划至少要拿到这三类输入:
- 已发生的事实(Facts)
- 已执行的动作(tool call)及其回执
- 产生的外部实体(邮件 id、工单 id、文件 url)
- 资源状态(余额、配额、锁)
- 约束(Constraints)
- 不可逆操作的禁止重复
- 合规/权限边界(scope)
- 成本/时延预算(token、工具调用次数、端到端 p95)
- 目标(Goal)
- 用户目标(可能被澄清/变更)
- 验收条件(输出合同/格式约束)
这意味着:你做 replanning 的核心数据结构不是一段对话,而是一个可追溯执行记录。
二、失败检测:什么时候判定“计划坏了”?
不要把“工具报错”才当失败。更可靠的做法是把失败分成 4 类触发器(Trigger),每类都有可观测信号。
1)工具失败(Tool Failure)
典型信号:
- 超时、429、5xx
- 返回空/字段缺失
- 业务拒绝(权限不足、配额不足)
处理原则:
- 可恢复错误(超时/429):有限重试 + 退避 + 预算
- 不可恢复错误(权限/配额):立即停止,转为追问/提示升级权限
2)不变量被打破(Invariant Violation)
例子:你要求“创建工单后必须拿到 ticketId”,但工具返回没有。
这类失败不能盲重试,必须:
- 记录“违反了哪个不变量”
- 进入修补分支(补字段、换工具、变更流程)
3)进度停滞(No Progress / Stuck)
最隐蔽,也最常见:Agent 不断解释、不断尝试,但系统状态没有变化。
可操作判定:
- 连续 N 次动作没有新增事实(facts)
- 端到端耗时超过阶段预算(例如规划 5s、执行 60s)
4)结果校验失败(Output Contract Failed)
你应该把输出校验当作“执行的一部分”:
- JSON schema 校验
- 必填字段校验
- 枚举值/范围校验
- 关键事实引用校验(例如必须引用工具回执里的金额/日期)
校验失败后再 replanning,质量会稳定很多。
三、重规划策略谱系:从“局部修补”到“全量重算”
重规划不是只有一种做法。建议按代价从低到高分 4 档,优先走低代价。
1)局部修补(Local Repair):只修坏掉的一步
适用:
- 某一步参数错、字段缺失
- 工具小概率失败
做法:
- 保留既有计划与已完成步骤
- 仅替换失败节点(比如换一个工具、补一个参数)
关键:必须能定位“失败节点”。所以你需要把计划结构化(例如步骤列表/DAG)。
2)回退到检查点(Checkpoint Rollback):从最近可确认状态继续
适用:
- 中间步骤产生了不确定状态
- 并发导致状态被修改
做法:
- 定义可持久化检查点:完成到哪一步、产物是什么
- 从检查点重新执行后续步骤(注意幂等与补偿)
3)替代路径(Plan B / Fallback):换流程而非换参数
适用:
- 工具不可用或不稳定
- 数据源缺失
例子:
- CRM 查不到 → 改为让用户上传 CSV
- 邮件接口超时 → 改为生成草稿给用户确认
4)全量重算(Full Replan):重新生成一份新计划
适用:
- 目标变化
- 上下文/事实变化太大,局部修补会越来越脏
注意:全量重算不是“忘掉过去”。它必须把“已发生事实”作为硬约束输入,否则会重复执行写操作。
四、一个可落地的 Replanning 循环(含状态机 + 事件日志)
建议把 Agent 执行抽象成一个“可重入”的循环:
- 生成/更新计划(plan)
- 执行一步(act)
- 写入事件(event)
- 校验与判定(verify + decide)
- 需要时重规划(replan)
1)最小状态机
PLANNING:生成计划RUNNING:执行计划步骤WAITING_INPUT:向用户追问WAITING_TOOL:等待异步工具REPLANNING:基于事实修补计划DONE/FAILED
关键不是状态名称,而是:状态必须持久化,否则断线/重启就无法安全重入。
2)事件日志的最小结构
建议每条事件都能回答“发生了什么”以及“为何发生”。例如:
{
"taskId": "t_123",
"planVersion": 3,
"stepId": "send_email",
"eventType": "TOOL_CALL",
"tool": "gmail.send",
"idempotencyKey": "t_123:send_email:v3",
"inputHash": "...",
"startedAt": "...",
"durationMs": 842,
"result": { "success": false, "error": { "type": "429" } },
"decision": { "next": "RETRY", "backoffMs": 2000 }
}
有了它,你才能做到:
- 复盘失败原因分布
- 控制重试预算
- 防止重复执行
3)幂等与补偿:重规划“敢做”的前提
把动作分两类:
- 读操作:可重复(但要限流/缓存)
- 写操作:必须幂等,且尽量提供补偿
原则:如果某个写操作既不可幂等、也不可补偿,那它就不该自动执行,而应该走审批(HITL)。
五、重规划的质量控制:别让 Agent 越修越乱
1)把“修补范围”写进策略
常见灾难:每次失败都在原计划上打补丁,最后变成无法理解的“意大利面计划”。
建议设置阈值:
maxRepairCountPerTask(例如 3 次)maxPlanVersion(例如 5 版)- 超过阈值则:转为全量重算或人工介入
2)重规划也要评测
不要只评测“最终答案好不好”。建议增加:
- 自救成功率:触发 replanning 后最终完成率
- 重复执行率:同一幂等键触发次数
- 重试风暴指标:单任务工具调用次数分布(p95/p99)
- 修补类型分布:参数修补/回退/换路径/追问
指标可观测,迭代就有方向。
六、可直接复用的 Checklist
- 失败检测:工具失败/不变量/停滞/校验失败四类触发器
- 状态机:状态可持久化,可重入执行
- 事件日志:每步 tool call 有输入摘要、耗时、回执、决策
- 幂等:所有写操作有
idempotencyKey,冲突可观测 - 检查点:定义可复用产物与回退点
- 重试预算:按阶段/按工具设置次数与时间上限
- 退出策略:超过修补阈值转全量重算或人工/追问
常见问题
“重规划”会不会让模型更容易幻觉?
如果你把 replanning 做成“对话补丁”,确实会更乱。正确做法是:以事实(tool receipts)为约束输入,所有关键输出都要引用或可追溯到回执,然后再做局部修补。
我没有工作流引擎,也能做 replanning 吗?
能。你不需要一开始就上 DAG 引擎。最小可行是:结构化步骤列表 + 事件日志 + 幂等键 + 输出校验。很多团队缺的不是引擎,而是“可追溯执行记录”。
重规划是不是一定要让 Agent 自己决定?
不一定。高风险场景更适合“策略驱动”:系统根据错误类型与风险等级决定是否重试/降级/追问,而不是把所有选择权交给模型。