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

📷 Photo by Vladimir Srajber via Pexels
一、先把概念说清楚:Agent 更像“分布式工作流”,不是单次函数调用
很多团队把 Agent 当作:
- 输入 → LLM → 输出
但一旦引入工具,你的系统就变成:
- 规划 → 多次外部调用 → 多次写入 → 合成结果
这时失败的形态不再是“返回 500”,而是:
- 已经写入了一部分
- 已经发出了一部分请求
- 外部世界状态已经变化
所以你需要的是:可恢复执行(resumable execution)。
二、为什么“重来一遍”会更糟
重跑的问题主要有三类:
- 成本放大:token + 工具费用成倍增长
- 副作用重复:
- 重复发送邮件/短信
- 重复创建工单/日程
- 重复下单/扣费
- 语义不一致:
- 时间变化导致数据不同
- 外部系统的幂等窗口过期
因此,正确的目标不是“能重跑”,而是:
- 失败后能继续,或能精确补偿。
三、设计核心:事件日志 + 状态机,让执行可恢复
把一次 Agent run 记录为事件流:
PlanCreatedToolCallStartedToolCallSucceededToolCallTimedOutSideEffectCommittedCompensationScheduledCompensationSucceeded
这样你就能回答:
- 做到哪一步了?
- 哪一步失败了?
- 是否已经产生副作用?
状态机决定下一步:继续、补偿、降级、或请求用户确认。
四、补偿模式清单:把“撤销”写成策略,而不是临时脚本
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 才真正具备“生产可用”的韧性。