ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Multi-Agent故障恢复:从崩溃到无缝续跑

Multi-Agent故障恢复:从崩溃到无缝续跑 前面的文章已经解决了 Multi-Agent 中的控制问题任务怎样拆分、Agent 之间传什么、下一步由谁执行以及运行过程中如何管理 Context、State 和 Memory。然而流程设计正确不代表任务一定能够执行完成。一个任务可能运行几十分钟调用几十次模型和外部工具。期间任何一次网络超时、API 限流、进程重启等都可能让执行中断。本文我们主要讨论怎样让已经确定的流程可靠地执行下去并在发生故障后继续完成。这也是 Multi-Agent 从原型进入生产环境后须补上的一层防护机制Execution Runtime执行运行时。一、流程控制与可靠执行我们首先区分两个容易混在一起的问题流程控制与可靠执行。假设一个研究任务需要三个 AgentPlanner | ├── Agent A研究市场 ├── Agent B研究竞品 └── Agent C研究技术 | ▼ SynthesizerPlanner 决定创建哪几个 Agent以及完成之后进入哪个步骤这属于控制流。但真正运行时还会遇到另一类问题Agent A ✓ Agent B ✓ Agent C ───── X timeout此时系统已经知道下一步应该做什么问题在于 C 没有执行完成。如果程序直接退出再重新启动整个任务那么 A、B 已经完成的搜索、模型调用和计算都会被重新执行。对于几秒钟的流程这可能还能接受。对于运行十几分钟甚至更久的 Agent这种方式则不能接受。Anthropic 在其 Multi-Agent Research 系统的生产经验中提到Agent 会长期运行并持续维护状态错误也会随着执行步骤累积。因此他们会结合 checkpoint、retry 等机制让失败后的任务从现有进度继续而不是每次从头开始。所以流程控制与可靠执行的职责分别是Control Plane 决定接下来做什么 Execution Runtime 保证这件事最终能够执行完成接下来要介绍的 Checkpoint、Retry、Idempotency都围绕执行运行时Execution Runtime确保 Agent 可靠地执行完成。二、Checkpoint 保存执行进度实现故障恢复的第一步是保存执行进度。这种保存点通常称为 Checkpoint。可以把一次长任务理解为下面这条时间线t0 t1 t2 t3 start checkpoint checkpoint crash | └──────────→ resume如果系统只在t0保存输入那么t3崩溃以后只能重新开始。如果t1、t2都保存了执行状态那么系统可以找到最近一次有效状态从那里继续。例如Checkpoint #12 task_id: research-001 A: status: completed artifact: artifact-a.json B: status: completed artifact: artifact-b.json C: status: running恢复以后就不需要重新执行 A 和 B。运行时只需要知道A completed → 跳过 B completed → 跳过 C unfinished → 继续执行这就是持久化执行Durable Execution的核心思想之一执行过程中的关键状态不能只存在于当前进程内存中。LangGraph 的 persistence 机制采用 checkpointer 保存 Graph State。执行过程中可以通过thread_id关联到同一条运行线程之后继续读取已经保存的状态。它的 checkpoint 通常发生在 Graph 的节点边界因此节点划分也会直接影响恢复粒度。例如把任务设计成search ↓ analyze ↓ write如果analyze失败通常只需要重新执行当前节点。但如果把三项操作全部塞进一个节点search analyze write即使最后一步失败也可能需要重新执行整个节点。因此节点粒度除了影响代码结构也会影响故障恢复成本。不过 checkpoint 也不能无限细。每一个微小步骤都写一次数据库会增加存储和协调开销。更实用的做法是优先保存那些成本较高的模型调用结果已经完成的子任务外部系统返回的重要 ID后续步骤无法轻易重新计算的数据人工确认后的决策。Checkpoint 的目标不是记录所有变量而是确保发生故障以后已有成果不会轻易丢失。三、Retry 处理临时故障有了 checkpoint还需要处理另一类更常见的问题临时性的失败。例如HTTP 429 HTTP 502 connection reset request timeout database connection unavailable这些错误有一个共同特点稍后再执行一次有可能成功。因此系统通常会进行 Retry也就是重试。最简单的策略是失败 ↓ 等待 ↓ 重试但生产环境里的 Retry 通常还需要三个限制。1. 最大重试次数例如max_attempts 3如果已经连续失败三次就不要无限尝试。否则一个下游服务故障可能让几百个 Agent 不断发送请求进一步放大故障。2. BackoffBackoff 指每次失败后逐渐增加等待时间。例如第 1 次失败 → 等 1 秒 第 2 次失败 → 等 2 秒 第 3 次失败 → 等 4 秒这就是常见的 Exponential Backoff指数退避。它可以避免大量失败任务同时立即重试。3. Retry Budget系统还可以给整个任务设置重试预算。例如整个任务最多允许 20 次 Tool Retry 3 次 Agent Retry 10 分钟恢复时间这样能够防止一个异常任务无限消耗 token、API 配额和计算资源。LangGraph 的官方示例也把错误分成不同类型网络错误、限流等临时问题适合自动 Retry需要用户补充信息的问题可以暂停未知错误则应该暴露出来供调试。因此一个重要原则是Retry 只适合有较大概率自行恢复的错误。相反类似参数本身错误HTTP 400 invalid schema unsupported tool permission denied连续执行十次通常也不会改变结果这一类错误不应使用 Retry 策略。因此可靠系统需要先判断失败类型再决定是否重试。四、幂等避免重复执行Retry 看起来很简单但执行时可能会隐含着问题。假设 Agent C 的任务是创建一个客服 Ticket第一次调用外部系统Agent C | ├── create_ticket() | Ticket System | Ticket #1001 创建成功 | X response timeout这里出现了一个不正常的状态。Agent 看到的是timeout于是 Runtime 判断任务失败并再次执行create_ticket()结果可能变成Ticket #1001 Ticket #1002事实上第一次已经成功只是响应没有成功返回。因此能够 Retry并不代表能够安全 Retry。这里就要引入 Idempotency幂等性。幂等要求同一个逻辑操作执行多次最终结果仍然与执行一次相同。例如查询GET /customer/123重复执行多次结果都完全一样。但下面这些操作多次执行可能存在幂等问题创建订单 发送邮件 写数据库 扣款 提交工单 发布内容一旦自动 Retry就必须考虑重复执行。常见做法是给一次逻辑操作生成唯一的 operation_idoperation_id research-001-create-ticket-C第一次执行create_ticket( operation_idresearch-001-create-ticket-C )第二次 Retry 仍然使用相同 ID。外部系统如果发现这个 operation 已经成功处理就直接返回第一次的结果operation already completed ticket_id 1001这样可以避免重复创建。如果目标系统本身不支持幂等键还可以在自己的数据库中保存operation_id status external_resource_id然后在执行前进行去重检查。对于无法做到严格幂等的操作还可以使用 Compensation补偿操作。例如创建资源 ↓ 后续失败 ↓ 删除刚才创建的资源这种思路在分布式系统中非常常见。因此真正可靠的 Retry 通常要和三件事一起设计Retry Idempotency Compensation五、同步执行与异步执行Multi-Agent 系统还会遇到一个运行方式上的选择同步还是异步。假设三个 Agent 并行执行A ───────── 15s B ───────────────── 30s C ───────────────────────── 60s同步模式下Coordinator 通常会等待await A await B await C只有全部完成之后才进入下一步。这种方式的优势非常明显状态简单 结果容易聚合 错误传播容易理解因此很多系统最开始都会采用同步执行。Anthropic 当前公开的 Multi-Agent Research 架构也提到Lead Agent 会等待一批 Subagent 完成后再继续。这降低了协调复杂度但一个执行很慢的 Subagent 也可能阻塞整个过程。异步模式则允许结果独立到达A finished ↓ 立即处理 A B finished ↓ 立即处理 B C 继续运行甚至 Coordinator 可以在 A 返回以后又创建新的 Agent DA result | └── spawn D B result C running D running吞吐量和并行能力会明显提高。但 Runtime 也必须处理更多问题哪个结果已经到达 哪个任务还在执行 某个 Agent 失败是否影响其他 Agent 结果到达顺序改变怎么办 Coordinator 什么时候可以继续这些都属于状态协调问题。在实践中原则上任务规模较小时优先同步当等待时间和并行度已经成为明显瓶颈再引入异步执行。异步可以提高性能但它同时会增加恢复、状态一致性和错误传播的设计成本。六、一次完整的故障恢复现在把前面的机制放进同一个例子。一个任务同时启动三个 AgentA ───────────── completed B ─────────────────── completed C ───────────── X timeoutA 和 B 已经产生 Artifact。系统此时存在一个 checkpointCheckpoint #18 A: status: completed artifact: artifact-a B: status: completed artifact: artifact-b C: status: runningC 调用了外部 Ticket APIoperation_id: job-123-agent-c-ticket外部系统实际上已经创建Ticket #8421但响应返回过程中发生网络超时。Runtime 捕获异常以后首先判断Timeout → transient error → 可以 Retry随后读取 checkpointA completed → 不执行 B completed → 不执行 C failed → retryC 再次调用create_ticket( operation_idjob-123-agent-c-ticket )外部系统发现相同 operation 已经处理return Ticket #8421C 得到结果C completed artifact-c saved随后写入新的 checkpointA ✓ B ✓ C ✓Coordinator 再进入后续汇总阶段。整个过程可以表示为Checkpoint | ├── A artifact ✓ ├── B artifact ✓ └── C pending | retry | idempotency check | resume | C artifact ✓ | next stage从这个例子可以看到真正的故障恢复并不是简单地“失败以后再调用一次”。它至少涉及Checkpoint 知道已经完成了什么 Retry 重新执行可恢复的失败 Idempotency 避免重复执行而产生错误结果。 Resume 从已有状态继续流程缺少其中任何一个环节都可能让恢复过程重新产生新的问题。总结很多 Multi-Agent Demo 的重点放在 Agent 怎么调用、Prompt 怎么写、Supervisor 怎样决定下一步。这些内容解决的是“系统如何思考和调度”。进入真实业务以后必须要解决另一类更基础的问题任务跑到一半会不会丢 API 超时以后怎么办 已经完成的步骤会不会重新执行 重试会不会创建两张订单 系统升级会不会破坏正在运行的任务这些问题已属于典型的分布式系统工程范围。Temporal 这类 durable workflow 系统的核心价值也正是在进程崩溃、网络故障或基础设施中断以后仍然能够利用持久化的执行历史恢复工作流。而在 Agent Runtime 中同样可以借鉴这些成熟思想。最终一个可靠的 Multi-Agent 执行层可以概括为State 持久化 Checkpoint Retry Policy Idempotency Timeout Observability流程设计告诉系统下一步应该运行谁。可靠执行则保证在模型失败、工具超时、进程重启和系统升级都可能发生的环境里已经确定的工作仍然能够继续向前推进并最终得到一个可确认的结果。这也是 Multi-Agent 从“能够运行”走向“能够长期运行”必须补上的工程基础。
返回列表