当Agent需要跨系统协作、长时等待审批或经历服务重启时,同步链式调用极脆弱。建议用事件驱动架构让Agent独立工作、按需恢复,并在模型建议与实际执行间加人工策略层。
当 AI Agent 被串联成长同步链时,它们会变得非常脆弱。事件总线让它们能够独立工作、等待人工和工具介入、在重启后恢复,并在模型建议和真实操作之间放置策略层。
大多数 AI Agent 演示都在一个请求内完成:
User -> Agent -> Tool -> Agent -> Response
Agent 制定计划、调用工具、获取答案、返回响应。简单易懂,也容易演示。
然后同样的 Agent 遇到了真实的 Workflow。
它需要从多个系统获取数据。一个工具需要五分钟。另一个 Agent 需要审查结果。生产变更需要人工审批。在等待审批期间,其中一个服务重启了。
模型不再是最难的部分。协调才是。
到了这个阶段,用更好的 prompt 修不好系统了。Agent 需要一种方式独立工作、在故障中存活,并在原始请求结束后恢复。这是事件驱动架构的问题。
同步链在需要等待时就会出问题
想象一个运维 Agent 调查缓慢的结算服务。它需要收集指标、检查依赖、运行诊断任务、提出恢复操作、等待审批、执行变更、验证恢复。
用直接调用的方式,每个组件都知道下一步是什么。第一个 Agent 等待第二个。第二个等待工具。当一个人决定是否批准变更时,请求保持开放。
这在每一步都快速且可用时是有效的。在生产环境中,这个假设维持不了多久。
超时可能让工具在调用方已放弃后继续运行。重试可能执行同一个操作两次。重启可能擦除当前计划。加入安全审查意味着修改一个已经正常工作的集成。
人工审批最清楚地暴露了这个问题。一个决策可能需要几分钟或几小时。在整个等待过程中保持 HTTP 请求开放是一种糟糕的 Workflow 保持方式。
用事实替代直接调用
在事件驱动设计中,Agent 发布发生了什么。其他组件决定这个事实是否与它们相关。
ServiceLatencyIncreased
|
v
DiagnosisRequested
|
v
DependencyFailureSuspected
|
v
RecoveryProposed
|
v
HumanApprovalRequired
|
v
RecoveryApproved
|
v
RecoveryCompleted
服务健康 Agent 可以发布 DiagnosisRequested,而不需要知道哪个诊断 Agent 会处理它。诊断 Agent 可以发布 DependencyFailureSuspected,而不需要直接调用修复 Agent。
审计服务、可观测性管道和安全 Agent 都可以对同一个事件做出反应。如果某个消费者暂时不可用,它可以在恢复后处理该事件,具体取决于 broker 的保留设置。
这是事件总线的有用之处。组件参与 Workflow,而不需要相互直接连线。这与 AWS Prescriptive Guidance 对事件驱动 AI 描述的生产者-消费者分离相同,但该模式不依赖任何云或 broker。
事件不是命令
当每条消息都被视为可互换时,Agent 系统就会变得危险。
事件记录一个事实:
{
"type": "ServiceLatencyIncreased",
"eventId": "evt-204-01",
"incidentId": "incident-204",
"service": "checkout-api",
"p95LatencyMs": 1840
}
具体 schema 由系统决定。当事件跨团队或平台边界时,vendor 中立的 CloudEvents 规范为事件元数据提供了通用信封。
命令请求一个操作:
{
"type": "ScaleService",
"commandId": "cmd-204-01",
"incidentId": "incident-204",
"service": "checkout-api",
"targetReplicas": 12,
"idempotencyKey": "incident-204:scale:12"
}
Agent 决策是一个建议。它可以包含证据和置信度,但仍然是提案。
这些区别很重要。LLM 说"扩展服务"并不意味着服务已被扩展。它也不意味着该操作已获得授权。
Event -> Agent decision -> Proposed command -> Policy check
-> Authorized command -> Execution -> Outcome event
Agent 解释情况并提出操作。策略层检查权限、限制和审批要求。确定性代码执行变更。然后执行器发布实际发生的事情。
即使模型改变,这种分离仍然有用。模型可以变得更强大,而不会悄无声息地获得重启生产环境或退款的权限。
Agent 记忆不是 Workflow 状态
Agent 平台大谈记忆。对话记忆和执行状态解决的是不同问题。
记忆可能包含对话摘要、用户偏好或检索到的知识。Workflow 状态回答运营问题:
对话记录是存储这些答案的脆弱地方。它可能在摘要化、截断后,或在模型更新后被不同地解释。如果退款已发出的唯一记录是上下文窗口中的一个句子,系统最终可能再次发出退款。
显式存储 Workflow 状态。在持久化存储中保留事件 ID、命令状态、审批、重试计数和执行结果。只给模型当前决策所需的上下文。
Broker 不会替你让系统可靠
把工作转移到事件总线上会改变故障模式,但不会消除它们。
设计消费者使其能够看到同一条消息多次。跟踪稳定的事件 ID,并为改变状态的工具要求幂等键。重启服务两次或发出同一笔退款两次不是重试策略。
事件乱序到达
审批可能在提案已过期后才到达。恢复结果可能在新操作已开始后才出现。在消息上放置版本和时间戳,并拒绝与当前 Workflow 状态不再匹配的转换。
Agent A 发布一个事件唤醒 Agent B。Agent B 用一个事件回应,唤醒 Agent A。两个 Agent 可能不断生成消息和消耗 token,而不完成有用工作。
跟踪因果深度。为时间、token 和 Workflow 步骤设置限制。将重复失败路由到人工审查。
冲突决策
两个 Agent 可能为同一资源提出相反的操作。不要允许两个命令同时运行。序列化该资源的更改,或在执行前使用版本检查。
消费者本身应该很无聊。这是一种赞美:
def handle(event, store, agent, policy, executor):
if store.already_processed(event.id):
return
workflow = store.load_workflow(event.incident_id)
if not workflow.accepts(event.type, event.version):
store.mark_processed(event.id, outcome="stale")
return
decision = agent.decide(workflow.context_for(event))
verdict = policy.evaluate(decision)
if verdict.requires_human:
store.request_approval(workflow, decision)
return
if not verdict.allowed:
store.record_denied(workflow, decision, verdict.reason)
return
result = executor.run(
decision.command,
idempotency_key=decision.command.idempotency_key,
)
store.append_event(workflow, result.to_event())
store.mark_processed(event.id, outcome="applied")
模型执行模糊推理。周围代码以可测试的方式处理状态、策略、去重和执行。
不是每个 Agent 都需要事件总线
文档摘要器不需要分布式控制平面。当一个调用方期望立即得到答案、任务快速完成、重试不会造成损害时,同步请求通常就够了。
当工作超过请求超时、多个 Agent 独立行动、人工打断 Workflow、或操作具有运营或财务后果时,事件开始体现其价值。
这是有代价的。团队需要管理消息 schema、保留、追踪、失败消息处理和异步调试。在这些代价能买到可靠性时使用事件驱动设计,而不是因为架构听起来更高级。
从阻塞的那一步开始
你不需要一次性重建一个同步 Agent 系统。
找到阻塞时间最长的一步。它通常是人工审批或慢速外部工具。给那一步一个持久化状态记录和一个可以恢复 Workflow 的事件。然后给每个改变 Agent 系统外部状态的命令添加幂等键。
选取你已经在运行的一个 Agent Workflow,画出等待、重试、审批和副作用。当这些边界隐藏在单个同步链内部时,那就是第一个事件应该存在的地方。
更好的模型会改进 Agent 决策。它们不会恢复丢失的审批、防止重复命令、或恢复一个未完成的 Workflow。一旦 Agent 跨服务和时间工作,它们就继承了分布式系统的故障。
在事件驱动设计中故障仍然会发生。持久的 Workflow 边界使得安全停止和稍后恢复成为可能。