拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

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

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

前面的文章已经解决了 Multi-Agent 中的控制问题:任务怎样拆分、Agent 之间传什么、下一步由谁执行,以及运行过程中如何管理 Context、State 和 Memory。

然而,流程设计正确,不代表任务一定能够执行完成。

一个任务可能运行几十分钟,调用几十次模型和外部工具。期间任何一次网络超时、API 限流、进程重启等,都可能让执行中断。

本文我们主要讨论:怎样让已经确定的流程可靠地执行下去,并在发生故障后继续完成。

这也是 Multi-Agent 从原型进入生产环境后须补上的一层防护机制:Execution Runtime,执行运行时。

一、流程控制与可靠执行

我们首先区分两个容易混在一起的问题:流程控制与可靠执行。

假设一个研究任务需要三个 Agent:

Planner | ├── Agent A:研究市场 ├── Agent B:研究竞品 └── Agent C:研究技术 | ▼ Synthesizer

Planner 决定创建哪几个 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. Backoff

Backoff 指每次失败后逐渐增加等待时间。

例如:

第 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_id:

operation_id = "research-001-create-ticket-C"

第一次执行:

create_ticket( operation_id="research-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 D:

A result | └── spawn D B result C running D running

吞吐量和并行能力会明显提高。

但 Runtime 也必须处理更多问题:

哪个结果已经到达? 哪个任务还在执行? 某个 Agent 失败是否影响其他 Agent? 结果到达顺序改变怎么办? Coordinator 什么时候可以继续?

这些都属于状态协调问题。

在实践中,原则上:任务规模较小时优先同步;当等待时间和并行度已经成为明显瓶颈,再引入异步执行。

异步可以提高性能,但它同时会增加恢复、状态一致性和错误传播的设计成本。

六、一次完整的故障恢复

现在把前面的机制放进同一个例子。

一个任务同时启动三个 Agent:

A ───────────── completed B ─────────────────── completed C ───────────── X timeout

A 和 B 已经产生 Artifact。

系统此时存在一个 checkpoint:

Checkpoint #18 A: status: completed artifact: artifact-a B: status: completed artifact: artifact-b C: status: running

C 调用了外部 Ticket API:

operation_id: job-123-agent-c-ticket

外部系统实际上已经创建:

Ticket #8421

但响应返回过程中发生网络超时。

Runtime 捕获异常以后,首先判断:

Timeout → transient error → 可以 Retry

随后读取 checkpoint:

A completed → 不执行 B completed → 不执行 C failed → retry

C 再次调用:

create_ticket( operation_id="job-123-agent-c-ticket" )

外部系统发现相同 operation 已经处理:

return Ticket #8421

C 得到结果:

C completed artifact-c saved

随后写入新的 checkpoint:

A ✓ 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 从“能够运行”走向“能够长期运行”必须补上的工程基础。

返回列表