Agent服务故障:自动化为什么必须能排队

自动化 Agent 最危险的误解之一是:

触发了
=
执行了

OpenAI 状态页记录了一次 Workspace Agents 与 ChatGPT Work 错误率升高事件:8月27日18:00左右开始确认异常,19:07进入恢复监控,22:14确认全部恢复。

这类故障本身很正常。真正需要工程团队提前设计的是:

如果Agent平台暂时不可用,
你的业务事件去哪?

例如新邮件、PR更新、客户工单、审批到达和定时任务。如果这些触发直接调用 Agent:

Webhook
→ Agent API

Agent 失败时,事件就可能直接丢失。

事件触发和Agent执行必须解耦

正确结构:

Event
↓
Durable Inbox
↓
Task Queue
↓
Agent Runtime

Agent 挂了:

Queue堆积

平台恢复:

继续消费

故障影响的是处理延迟,而不是业务数据完整性。

Inbox先保证“事件没丢”

create table agent_event_inbox (
    event_id varchar(128) primary key,
    source varchar(64) not null,
    resource_id varchar(256) not null,
    payload_ref varchar(512) not null,
    received_at timestamptz not null,
    status varchar(32) not null
);

Webhook 收到以后:

写Inbox
→ ACK

不要等 Agent 完成才 ACK。

如果 Agent 要跑 5 分钟,而 Webhook Provider 只等 10 秒,后者会误以为失败并重试,最后你得到重复事件。

Task Queue再保证“可以慢慢做”

public enum AgentTaskStatus {
    PENDING,
    RUNNING,
    RETRY_WAIT,
    COMPLETED,
    FAILED,
    DEAD_LETTER,
    EXPIRED
}

Agent API 出现:

429
5xx
timeout

通常进入:

RETRY_WAIT

而不是立即 FAILED。

Retry一定要指数退避

最差做法:

每秒重试

平台故障时只会制造 Retry Storm。

更合理:

5s
15s
45s
2m
5m
15m

并加 Jitter。

import random

def backoff(attempt, base=5, cap=900):
    delay = min(
        base * (2 ** attempt),
        cap
    )

    return delay * random.uniform(
        0.8,
        1.2
    )

这样多个 Worker 不会在同一秒一起冲击恢复中的服务。

不是所有失败都能Retry

429
5xx
timeout

多半是临时故障。

401
403
invalid input
policy denied

通常不能盲重试。

可以分类:

public enum FailureClass {
    TRANSIENT,
    THROTTLED,
    AUTH,
    POLICY,
    INVALID_REQUEST,
    UNKNOWN
}

策略:

TRANSIENT:
Retry

THROTTLED:
Respect Retry-After

AUTH:
Refresh Credential or Stop

POLICY:
Stop

INVALID_REQUEST:
Dead Letter

UNKNOWN:
Reconcile

UNKNOWN为什么最危险

假设 Agent 正在:

发邮件

真实流程:

Tool执行成功
↓
响应返回途中断线
↓
Agent平台只看到timeout

如果你简单重跑整个任务:

用户可能收到两封邮件

这不是普通失败。

它是:

外部副作用状态未知

必须先 Reconcile。

Side Effect Ledger不能省

create table agent_side_effect (
    idempotency_key varchar(256) primary key,
    run_id varchar(128) not null,
    capability varchar(128) not null,
    action_hash varchar(64) not null,
    status varchar(32) not null,
    provider_receipt varchar(512)
);

状态至少:

PLANNED
EXECUTING
CONFIRMED
FAILED
UNKNOWN

如果状态是 CONFIRMED,Retry 只恢复后续步骤。

如果是 UNKNOWN

先查询Provider

不能再次执行。

Provider恢复不代表业务恢复

状态页变绿:

22:14 Resolved

并不代表你的业务队列已经清空。

假设故障期间积压:

20,000 Tasks

恢复后还需要:

Backlog Recovery

所以内部 SLO 不能只看 Provider Status。

还要看:

Oldest Task Age
Queue Depth
Recovery ETA

恢复时最怕“洪峰”

服务恢复瞬间,20,000 个 Task 同时发出去:

又把服务打挂

所以需要 Recovery Ramp:

第1分钟:并发10
第2分钟:20
第3分钟:40
第4分钟:80

不断观察:

Error Rate
P95
429
Queue Drain Rate

再增加。

Priority Queue很重要

积压任务不应该 FIFO 一把梭。

例如:

P0:
安全告警
支付确认

P1:
客户工单

P2:
PR Review

P3:
日报/摘要

恢复时:

P0先清
P3最后

旧任务不一定都要补跑

例如:

每5分钟生成Slack摘要

故障3小时:

积压36个任务

全部补跑毫无意义。

更合理:

36个
→合并成1个“最新状态摘要”

所以 Task 要带:

Missed Schedule Policy

三种Missed Schedule策略

public enum MissedSchedulePolicy {
    CATCH_UP,
    LATEST_ONLY,
    SKIP
}

例子:

月度对账:
CATCH_UP

10分钟摘要:
LATEST_ONLY

过时监控报告:
SKIP

定时 Agent 没有这个字段,故障恢复时很容易疯狂补历史任务。

Task还需要Expires At

public record AgentTask(
        String taskId,
        String taskType,
        int priority,
        Instant createdAt,
        Instant expiresAt,
        String idempotencyKey,
        MissedSchedulePolicy missedPolicy) {
}

过期任务:

EXPIRED

不要继续占模型额度。

自动Fallback不能一刀切

Provider A 故障:

切Provider B

听起来简单,但有两个问题。

第一:

B是否真的可用?

第二:

B是否允许处理这类数据?

比如主模型满足:

Region=EU
Zero Retention

备用模型不满足。

所以 Failover 必须重新过:

Tenant Policy
Data Class
Region
Model Policy

Failure Domain也要先判断

故障可能在:

Agent Product
Model Provider
Region
Tool Provider
Internal Runtime

如果只是 Web UI 故障,底层 API 可能正常。

如果是内部 Tool 故障,换模型没有任何帮助。

定义:

public enum FailureDomain {
    AGENT_PRODUCT,
    MODEL_PROVIDER,
    REGION,
    TOOL_PROVIDER,
    INTERNAL_RUNTIME
}

根据 Domain 决定:

Retry
Fallback
Queue
Degrade
Stop

UI状态必须区分“排队”和“失败”

差:

Task failed

好:

Queued
Delayed
Retrying
Waiting for provider recovery

如果用户知道任务还安全地在队列里,就不会不断重复点击。

重复点击反而制造新的任务和成本。

我会监控这8个指标

agent_task_queue_depth
agent_task_oldest_age_seconds
agent_task_retry_total
agent_task_dead_letter_total
agent_provider_error_rate
agent_recovery_throughput
agent_task_expired_total
agent_duplicate_side_effect_blocked_total

其中最有价值的是:

Oldest Task Age

它直接告诉你业务真正延迟了多久。

Recovery SLO

例如:

Provider恢复后
95% P1任务
30分钟内完成

这比:

“Provider已经恢复”

更接近业务体验。

最好做一次Chaos Test

主动阻断 Agent Provider 30 分钟:

Event继续进入
Provider全部失败

然后检查:

事件是否丢失
Retry是否风暴
队列是否正确堆积
Side Effect是否重复
恢复后是否限流
Priority是否正确
过期任务是否合并

不做这种测试,排队设计往往只停留在架构图里。


Agent 服务出现故障并不可怕。

真正危险的是业务系统默认:

调用失败
=
事件消失

成熟的自动化应该做到:

事件先落地
任务可等待
副作用可去重
恢复可限流
过期可合并
Fallback重新鉴权

这样 Provider 故障最终表现为:

延迟上升

而不是:

业务状态缺失

这是 Agent 从“好用工具”进入关键自动化系统必须补上的可靠性层。


更多企业级 AI 应用、Agent、RAG 与模型工程化内容,我会继续整理在 智元界

https://www.zyentor.com/