跳到主要内容

异步 Agent 的静默失败:为何你的 AI 任务悄然终止却无人察觉

· 阅读需 9 分钟
Tian Pan
Software Engineer

异步 AI 任务有一个传统后台 Worker 没有的问题:它们会静默而自信地失败。一个文档处理 Agent 返回 HTTP 200,输出格式规整的结果,然后继续执行——而实际输出却悄悄出错了:可能不完整,可能建立在三步前幻觉出的事实上。你的仪表盘依然绿色,值班工程师照常入睡,客户最终才发现异常。

这不是边缘情况,而是未经可观测性设计的异步 AI 系统的默认行为。让传统分布式系统中后台作业队列保持可靠的工具——死信队列、幂等键、Saga 日志——同样适用于 AI Agent。但失败模式足够不同,需要做一些"翻译"。

为何异步 AI 失败不同于普通作业失败

传统后台作业的失败模式是可识别的:抛出异常、超时、队列消息未确认。每种失败都有明确信号,重试逻辑介入,耗尽重试后死信队列捕获消息,工程师可以回放或检查失败的 payload。

AI Agent 作业包含上述所有失败方式,再加上几种新的:

  • 语义失败:从队列角度看,Agent 成功完成了——它返回了结果、消耗了 token、更新了数据库——但结果是错的。库存充实 Agent 编造了一个商品 SKU,摘要 Agent 删掉了最重要的条款,多跳研究任务"回答"了问题却自信地引用了错误来源。
  • 静默部分完成:Agent 处理了 6 步工作流中的前 4 步,然后在中途停滞。由于最终回调触发,作业被标记为完成,而第 5、6 步从未执行。
  • 重试引发的重复:LLM 调用在 28 秒后超时,调用方重试,而原始调用在 3 秒后完成。同一操作的两次调用都触发了——与数据库写入不同,发送邮件或调用外部 API 默认可能不是幂等的。
  • 幽灵循环:由于提示词轻微格式错误引发的重试风暴,在一个周末烧掉了 1.5 万美元的 API 费用,无人知晓,直到账单到来。

贯穿所有这些的线索是:AI 作业将执行成功与正确性混为一谈。基础设施层面的指标——作业完成率、队列深度、错误数——无法捕获 Agent 是否真正做了正确的事。

死信队列作为控制面,而非垃圾桶

大多数工程师把死信队列当作处置机制:消息在其他一切都失败后落入其中,某人最终会查看它们。这种思维对 AI Agent 系统来说过于被动。

为 AI 作业设计良好的 DLQ 是一个控制面。它捕获原始 payload、完整重试历史、失败原因以及相关实体 ID。它提供回放接口,并将不同失败类型路由到不同处理程序。

对于 AI 来说,失败类型的区分比传统作业更重要。瞬态失败——触达速率限制、上游超时、瞬时网络错误——值得用指数退避自动重试。永久性失败——格式错误的提示词、违反策略、上下文窗口溢出——重试无益,应直接送人工审核。

对所有失败一视同仁的朴素重试策略会在不可恢复的错误上耗尽重试次数,同时浪费 token 并产生不必要的费用。更糟糕的是,它会静默丢弃那些看起来像瞬态失败、实则是语义错误的消息——这类失败会返回成功响应码,却污染下游状态。

将 AI 特有的失败类型路由到特定 DLQ 通道还能产生有用的遥测数据:上下文溢出失败的突然激增意味着输入分布发生了变化;策略违规失败的集群可能预示着提示注入攻击。死信队列成为生产漂移的被动传感器。

每一步都加幂等键,而不仅仅是入口处

大多数团队只在 API 层加幂等键——每个入请求生成一个键,在队列入口做去重。这是必要条件,但对多步 AI 工作流来说远远不够。

问题出在工作流的中间环节。设想一个 5 步文档处理流水线:提取、分类、增强、转换和存储。第 1 到 3 步完成,第 4 步超时。编排器从最后一个检查点重试——但如果第 3 步没有自己的幂等键,增强调用就会再次触发。根据被调用的工具,这可能无害(纯查找),也可能灾难性(创建记录、发送消息或向客户收费的操作)。

正确的模型是逐步幂等:每个有副作用的操作都获得一个由工作流执行 ID 和步骤索引派生的键。编排器在调用操作前检查这个键是否已记录为完成。若已完成,跳过该步骤;若未完成,触发操作并原子性地存储结果。

这与 Saga 文献针对微服务分布式事务的推荐模式相同。AI Agent 的特殊之处在于某些步骤是非确定性的——用相同输入两次调用同一 LLM 可能产生不同输出。如果你的工作流需要跨重试保持一致性,就需要存储和回放 LLM 响应,而不是重新调用模型。这个存储需求在初始设计阶段经常被忽视。

用 Saga 日志实现多步恢复

当异步 AI 工作流在中途失败时,决定恢复是否安全的关键问题是:当前世界处于什么状态?

传统作业通常可以用简单的布尔值回答这个问题——作业成功了还是没有?多步 AI 工作流在工具调用、外部 API 写入和内存更新之间积累状态变化。部分失败意味着你拥有部分状态:一些已提交,一些尚未提交。

Saga 模式通过使每个步骤的正向操作与补偿操作配对来处理这个问题——针对该特定步骤的回滚。更实用地说,对于 AI 系统,这意味着维护一个持久执行日志,记录哪些步骤已完成、其输出是什么,以及是否有任何补偿操作需要运行。

这个日志在生产中有两个用途。第一,它支持安全恢复:失败后重新拾起作业时,执行器读取日志并跳过已完成的步骤,而不是重新运行它们。第二,它提供审计追踪:当客户反映 AI Agent 做了意想不到的事情时,你可以追溯产生该输出的精确决策和工具调用序列。

这种审计能力在系统设计期间被低估,却在你需要它的那一刻变得至关重要。没有 Saga 日志,调试异步 AI 失败意味着从 LLM 提供商、应用层和任何被调用的外部 API 的分散日志中重建发生了什么。有了它,你就拥有了一个以工作流执行 ID 为索引的单一事实来源。

静默失败在实践中的样子

异步 AI 作业的监控问题不是"作业完成了吗?"而是一组更具体的问题:

  • 作业是否在预期 token 预算内完成? 超支表明推理循环失控或输入分布意外变化。
  • 经历了多少次重试? 经过两次超时后在第三次尝试成功的作业,与第一次就成功的作业是不同的健康信号。
  • 所有预期步骤都运行了吗? 作业完成事件应包含步骤清单——预期了哪些步骤,实际执行了哪些。
  • 死信率是否发生变化? 按失败类型细分的死信率趋势,是提示词或数据质量问题的领先指标。
  • 每作业成本趋势如何? 在任何用户可见症状出现之前,每作业平均 token 消耗量的突然上升,往往预示着下游质量退化。

这些指标要求作业基础设施发出结构化事件,而不仅仅是成功/失败信号。每个步骤都应该发出一个 span:运行了什么、花了多长时间、消耗了多少 token、进行了哪些工具调用、结果如何。这比大多数团队在经历严重生产事故之前愿意添加的检测工作要多——但静默失败的本质是,你不知道自己需要这些检测手段,直到事故已经悄然而过。

实用的起步顺序

你不需要第一天就把所有东西都检测到位。有用的优先级排序如下:

  1. 添加真正的死信队列,配备结构化 payload 和失败分类。停止静默丢弃失败消息。
  2. 为每个调用外部 API 或有副作用的工作流步骤添加逐步幂等键
  3. 为超过两步的工作流添加步骤完成日志。哪怕只是一条简单的 {workflow_id, step_name, status, timestamp} 记录,也能大幅缩短调试时间。
  4. 对死信率而非作业失败率发出告警。一个失败后落入 DLQ 的作业,往往好过一个以损坏输出"成功"的作业——但你需要前者的可见性才能采取行动。

目标不是在上线前实现完美可观测性,而是搭建最小脚手架,将不可见的失败转变为可见的失败。静默失败只有在保持沉默时才是危险的。

分布式系统工程师花了十年时间为传统微服务学会这个教训。AI Agent 系统正在更快、更大压力下重新学习它,还要应对额外的复杂性——当输出是概率性的时,"正确"更难界定。那些模式——死信队列、幂等键、Saga 日志——转移得很好。尽早应用它们的紧迫感却没有随之转移。

References:Let's stay in touch and Follow me for more thoughts and updates