Agent 工作流设计:从单次对话到多步骤自动化 · 第 5 / 6 节

第 5 课:错误处理和重试策略

学习目标:

  • 区分瞬态错误和永久错误
  • 掌握重试策略和退避算法
  • 学会设计补偿操作和回滚机制

前置要求:第 4 课:状态管理和上下文传递 | 下一课 第 6 课 >>

错误是工作流的常态

你的工作流完美运行了 10 次。第 11 次,在第 8 步,API 返回了 503 错误。工作流崩溃。

你加了 try-catch,捕获错误,打印日志,继续执行。第 12 次,数据库连接超时。工作流继续执行,但写入失败,数据不一致。

错误处理不是"加个 try-catch"那么简单。

在工作流中,错误处理需要回答三个问题:1

  1. 这个错误是暂时的还是永久的? (网络抖动 vs 权限不足)
  2. 应该重试、跳过还是中止? (重试可能解决 vs 重试会加剧问题)
  3. 如果中止,如何清理已完成的步骤? (回滚数据库 vs 发送取消通知)

如果失败的是可选步骤(比如发通知),跳过它继续往下走,这种"非关键的地方失败了不耽误整体"的处理方式就叫优雅降级;但如果失败的是关键步骤,跳过反而会留下不一致状态,应该直接中止。

没有答案,你的工作流要么太脆弱(一个小错误就崩溃),要么太危险(忽略错误继续执行,留下不一致状态)。2

错误分类:瞬态 vs 永久

瞬态错误(Transient Errors): 暂时性的,重试后可能成功。3

常见瞬态错误:

  • 网络超时
  • 服务暂时不可用(503 Service Unavailable)
  • 速率限制(429 Too Many Requests)
  • 数据库连接池已满
  • 临时锁冲突

特征: 通常由资源竞争、网络波动、临时过载引起,等一会儿重试通常能成功。

永久错误(Permanent Errors): 重试也不会成功,需要修复代码或配置。2

常见永久错误:

  • 权限不足(401 Unauthorized, 403 Forbidden)
  • 资源不存在(404 Not Found)
  • 输入格式错误(400 Bad Request)
  • 业务逻辑错误(余额不足、库存为 0)
  • 代码 bug(空指针、除零)

特征: 由配置错误、代码 bug、业务规则违反引起,重试只会浪费资源。

判断方法:

重试策略

对于瞬态错误,重试是第一选择。但重试本身也有学问。3

策略 1: 固定延迟重试

问题: 如果服务过载导致错误,所有客户端同时重试会加剧过载(惊群效应)。

策略 2: 指数退避(Exponential Backoff)

好处: 每次重试间隔加倍,给服务更多恢复时间,避免持续施压。3

策略 3: 指数退避 + 抖动(Jitter)

好处: 抖动避免多个客户端在完全相同的时间重试,分散负载。3

这是生产环境的推荐策略。4

策略 4: 选择性重试

关键: 只重试瞬态错误,永久错误立即抛出,避免无意义的重试。5

断路器模式(Circuit Breaker)

问题: 如果一个服务持续失败(如数据库崩溃),每个请求都重试 3 次,会白白消耗资源并拖慢整个工作流。如果这个服务还是别的服务的依赖,失败会一路传导下去,变成级联故障。

断路器: 当错误率超过阈值时,暂时停止调用失败的服务,直接快速失败,避免资源浪费。1

三种状态

关闭(Closed) ──错误率 > 阈值──→ 打开(Open)     ↑                              ↓     └──测试成功──← 半开(Half-Open) ←─超时后

关闭状态: 正常工作,请求正常通过,统计错误率。

打开状态: 服务被认为不可用,请求直接快速失败,不调用服务。

半开状态: 超时后尝试少量请求,如果成功则恢复关闭状态,否则继续打开。

实现

使用场景: 调用外部服务、数据库、文件系统等可能批量失败的依赖。1

补偿操作和回滚

问题: 工作流执行了 3 个写操作(写数据库、发邮件、更新缓存),第 4 步失败了。如何撤销前 3 步?2

模式 1: 事务性操作

适用场景: 所有操作都在同一个支持事务的数据库中。

局限: 无法跨系统(如数据库 + 文件系统 + API 调用)。

模式 2: 补偿操作(Saga Pattern)

思路: 为每个操作定义一个补偿操作,失败时执行补偿操作撤销已完成的步骤。4

关键点:

  1. 每个步骤都有 forward(正向操作)和 compensate(补偿操作)
  2. 失败时,反向执行已完成步骤的补偿操作
  3. 补偿操作本身也可能失败,需要记录并通知人工介入4

模式 3: 幂等性设计

幂等: 执行 N 次和执行 1 次效果相同。2

好处: 如果步骤因为网络问题执行了两次(第一次超时但实际成功了),幂等性确保不会产生副作用。2

错误处理的层次

好的工作流在三个层次处理错误:

层次 1: 单个操作

层次 2: 工作流步骤

这一步把每次失败都写进 workflowState.errors,步骤名、错误信息、发生时间都留了下来——这就是错误日志,排查问题时靠的就是这份记录而不是记忆。

层次 3: 整个工作流

三层防护: 操作层重试、步骤层记录、工作流层恢复和通知。


下一课: 第 6 课:真实场景工作流 — 综合运用所有知识,构建三个生产级工作流:代码重构、文档生成、测试自动化

Footnotes

  1. Vasanthan:处理基于代理的工作流中的失败 — https://medium.com/@vasanthancomrads/handling-failures-in-agent-based-workflows-c0fd9489b2ee 2 3

  2. Agents Arcade:代理系统中的错误处理 — https://agentsarcade.com/blog/error-handling-agentic-systems-retries-rollbacks-graceful-failure 2 3 4 5

  3. Augment Code:异步 AI 代理工作流如何在失败中生存 — https://www.augmentcode.com/guides/async-ai-agent-workflows 2 3 4

  4. AWS Marketplace:代理编排 — https://aws.amazon.com/marketplace/build-learn/ai-agent-learning-series/agent-orchestration 2 3

  5. Temporal:AI 代理编排的 11 种生产失败模式 — https://www.xgrid.co/resources/temporal-ai-agent-orchestration-failure-patterns/

练习

01

为下面三个错误设计处理策略(重试/快速失败/补偿):

Level 1: 分类错误并设计重试策略

错误 A: 调用支付 API 时收到 ETIMEDOUT 错误

错误 B: 插入数据库时收到 duplicate key 错误

错误 C: 上传文件到 S3 时收到 403 Forbidden 错误

要求:

  • 判断每个错误是瞬态还是永久
  • 说明应该如何处理(重试几次、用什么策略、或快速失败)
  • 如果需要重试,写出重试代码片段
完成标准 · 本地勾选
02

一个"用户注册"工作流包含 4 个步骤: (1) 在数据库创建用户记录 (2) 创建用户目录 /users/{userId}/ (3) 发送欢迎邮件 (4) 添加到邮件列表。如果步骤 3 或 4 失败,如何回滚前面的步骤?

Level 2: 设计补偿操作

要求:

  • 为每个步骤设计补偿操作
  • 写出 Saga 模式的伪代码(包含正向和补偿)
  • 说明哪些补偿操作可能失败,失败了怎么办
完成标准 · 本地勾选

我的笔记

记下想法、痛点、没懂的地方。只写进这门课的附录,正课文件不动。