返回文章列表
Agent工作流可靠性事务幂等

Agent 回滚与补偿设计:不要“重来一遍”,要能精确修复

Agent 系统最昂贵的失败不是报错,而是“一键重跑”把时间、token 和外部副作用都放大。本文用工程视角讲清楚:为什么 Agent 更需要补偿(compensation)而不是回滚(rollback)、如何设计幂等与可逆操作、如何用事件日志把执行变成可恢复的状态机,并给出一套适用于工具链路与工作流的补偿模式清单。

2026年3月4日
Synthly 团队
预计阅读 17 分钟
Agent 执行的事件日志与补偿链路:从失败点精确修复而非全量重跑

📷 Photo by Vladimir Srajber via Pexels

一、先把概念说清楚:Agent 更像“分布式工作流”,不是单次函数调用

很多团队把 Agent 当作:

  • 输入 → LLM → 输出

但一旦引入工具,你的系统就变成:

  • 规划 → 多次外部调用 → 多次写入 → 合成结果

这时失败的形态不再是“返回 500”,而是:

  • 已经写入了一部分
  • 已经发出了一部分请求
  • 外部世界状态已经变化

所以你需要的是:可恢复执行(resumable execution)


二、为什么“重来一遍”会更糟

重跑的问题主要有三类:

  1. 成本放大:token + 工具费用成倍增长
  2. 副作用重复
  • 重复发送邮件/短信
  • 重复创建工单/日程
  • 重复下单/扣费
  1. 语义不一致
  • 时间变化导致数据不同
  • 外部系统的幂等窗口过期

因此,正确的目标不是“能重跑”,而是:

  • 失败后能继续,或能精确补偿

三、设计核心:事件日志 + 状态机,让执行可恢复

把一次 Agent run 记录为事件流:

  • PlanCreated
  • ToolCallStarted
  • ToolCallSucceeded
  • ToolCallTimedOut
  • SideEffectCommitted
  • CompensationScheduled
  • CompensationSucceeded

这样你就能回答:

  • 做到哪一步了?
  • 哪一步失败了?
  • 是否已经产生副作用?

状态机决定下一步:继续、补偿、降级、或请求用户确认。


四、补偿模式清单:把“撤销”写成策略,而不是临时脚本

1)写入型副作用:必须有幂等键

外部写入建议统一携带:

  • idempotencyKey = runId + stepId + payloadHash

这能保证:

  • 重试不会重复写
  • 补偿不会重复撤销

2)SAGA 思路:每一步都有对应补偿

示例:

  • 创建资源 → 补偿:删除资源
  • 发送通知 → 补偿:发送撤销/更正通知(不能“撤回”就要更正)
  • 扣费 → 补偿:退款

并不是每一步都能完美撤销,所以要分级:

  • 可逆(delete/undo)
  • 可抵消(refund/correct)
  • 不可逆(只能记录并告知用户)

3)补偿触发条件:不是所有错误都补偿

建议区分:

  • 失败发生在“提交前” → 可以直接重试/继续
  • 失败发生在“提交后” → 需要补偿或人工确认

这里的“提交”指副作用落地。


五、与超时治理联动:超时不是终点,是分支

工具超时常见做法是直接抛错,但更好的方式是:

  • 把超时记录为一种结果
  • 根据预算与风险选择:
    • 走 fallback
    • 延迟执行(异步补全)
    • 触发补偿

超时治理的系统化方案见:


六、落地建议:从“可恢复”最小集开始

一周内可做的 MVP:

  • 每个步骤都有 stepId,每次 run 有 runId
  • 事件日志落库(至少 append-only)
  • 外部写入带幂等键
  • 对高风险副作用加入“提交点”(commit point)
  • 为关键步骤定义补偿动作
  • 失败时优先 resume / compensate,而不是 full rerun

当你做到这一层,Agent 才真正具备“生产可用”的韧性。

想看更多工程化文章见 /articles,也可以在 /apps/new 体验 Agent 能力。