跳到主要内容

AI 事件响应手册:诊断生产环境中的 LLM 性能退化

· 阅读需 16 分钟
Tian Pan
Software Engineer

2025 年 4 月,一个模型更新覆盖了 1.8 亿用户,并开始系统性地支持糟糕的决策——确认停止精神科药物的计划,以毫无来由的热情赞扬明显糟糕的想法。服务商自身的告警系统未能察觉,而社交媒体上的高级用户(Power users)发现了这一点。回滚花费了三天时间。根本原因是一个奖励信号悄无声息地胜过了阿谀奉承抑制约束(sycophancy-suppression constraint)——这对于现有的所有监控仪表盘和集成测试来说都是不可见的。

这就是摧毁用户对 AI 功能信任的失效模式:不是硬崩溃,不是 500 错误,而是一种标准 SRE 运维手册(Runbooks)在结构上无法察觉的逐渐质量崩塌。你的仪表盘会显示延迟正常、错误率正常、吞吐量正常,而模型却会言之凿凿地给出错误答案。

这才是你的值班轮转真正需要的事件响应手册。

四层诊断树

当一个 LLM 功能性能下降时,故障通常源于四个根本原因之一。核心洞察是,从外部看它们几乎一模一样——用户得到的都是糟糕的输出——但所需的修复方案却完全不同。找错方向会浪费数小时的时间。

请按顺序排查这些层级。

第 1 层:检索失败 (Retrieval Failure)

模型的回答看似合理但事实错误,或者尽管有可用的文档,它依然在细节上产生幻觉。知识库中有正确答案,但模型没有获取到。

诊断测试很简单:检查 Trace 中的检索跨度(Span)。如果检索到的分块(Chunks)不包含正确答案,那就是检索环节的错误。不要去修改提示词(Prompt)或模型。

常见根本原因:

  • 嵌入偏移 (Embedding drift):嵌入模型已更新(或被供应商轮换),但向量索引未重建。存储的嵌入分布与传入的查询嵌入不再匹配——你的相似度搜索就像是在拿苹果比橘子。
  • 索引陈旧 (Index staleness):索引流水线悄然断裂。文档已过时。检查受影响文档簇的“最后索引时间”戳。
  • Top-K 截断:正确答案存在于语料库中,但评分低于你的检索阈值。调整 k 值或改进分块(Chunking)策略。
  • 分词不匹配 (Tokenization mismatch):检索器和生成器使用不同的分词方式,导致在组装上下文时出现差一错误(Off-by-one)的失效。

第 2 层:生成失败 (Generation Failure)

检索到的上下文是正确的——你可以在 Trace 中看到正确的信息——但模型的输出仍然是错误的。它忽略了上下文中的内容,与其相矛盾,或者捏造了从未出现过的细节。

运行一次 Trace 回放:直接注入完全相同的检索上下文并重新运行请求。如果回放依然失败,那就是生成环节的错误。

常见根本原因:

  • 静默的模型版本变更:供应商会进行滚动更新。API 响应中的模型版本字段可能与你锁定的版本不同——请明确检查。一个小版本更新在不改变公开模型名称的情况下改变了行为。
  • 提示词指令冲突:你的系统提示词(System Prompt)说一套,下游用户消息说另一套。模型以非你所愿的方式解决了这种冲突。
  • 上下文位置偏见 (Context position bias):LLM 会不成比例地偏好上下文窗口开头或结尾的内容。埋在中间的关键检索段落会被忽略。
  • 采样参数偏移 (Sampling parameter drift):有人在配置文件中更改了 temperature 或 top-p,且该更改未经过评估(Eval)就进入了生产环境。

第 3 层:路由错误 (Routing Error)

调用了错误的工具、子代理(Sub-agent)或模型类别。你的意图分类器将流量发送到了错误的处理程序。本需要高性能模型的查询却由廉价模型回答了。

检查 Trace 中的 tool_callintent_class 字段。如果选择的路由与你的预期不符,那就是路由错误。

代价最高昂的变体是代理循环(Agent Loop):两个子代理互相请求澄清,且没有熔断机制。在一个记录在案的案例中,此类错误长达 11 天未被察觉,期间每周的 API 成本从 127 美元飙升至 47,000 美元。当时既没有预算上限,也没有循环检测,更没有对代理间调用量的监控。

代理系统需要显式的熔断器(Circuit Breakers):故障阈值(例如 30 秒内 3 次失败触发开启状态)、每个会话的最大步骤数,以及当同一个工具被以相同参数调用超过两次时停止执行的循环守卫。

第 4 层:上游数据损坏 (Upstream Data Corruption)

质量在整个主题簇中系统性地下降,起始于特定日期。模型以极高的置信度引用了来自表面权威来源的错误数据。

检查每个查询检索的是哪些源文档。如果新出现的退化主题中,检索内容突然集中在某个最近导入的来源,这就是主要信号。

原因可能包括:从将错误批次推入知识库的 ETL 任务,到针对陈旧快照成功完成的向量库索引失败,再到主动投毒。在威胁模型的极端情况下,在数百万份文档中仅需插入五份精心构造的恶意文档,即可通过操纵嵌入邻近度,对向量库实现 90% 的攻击成功率。


如何在不破坏运行中会话的情况下热回滚 Prompt

大多数团队都有 Prompt 的部署流程。但几乎没有人有回滚流程。

当你第一次需要快速回滚时,基础设施的差距就会显现出来。你可以在几分钟内重新部署之前的 Prompt 版本 —— 但是对于那 400 个正在损坏版本下进行多轮对话的活跃会话,会发生什么?你是直接硬切换并破坏他们的上下文吗?还是让他们在损坏的 Prompt 下完成对话?你是否有任何机制来区分它们?

在你需要回滚之前,基于不可变的 Prompt 版本进行构建。 一旦 Prompt 版本部署完成,就将其视为不可变的产物 —— 就像容器镜像标签一样。分配一个永远不能被更改、只能被取代的版本 ID。标签晋升(将 production 标签重新分配给较早的版本)应该不需要重新部署代码 —— 它应该是一个在几秒钟内即可生效的配置操作。

一个完整的 AI 智能体产物 ID 应该编码四个版本层级:

  • ALV (Agent Logic Version): 智能体逻辑版本,即 ReAct 循环结构和工具选择逻辑
  • PPV (Prompt and Policy Version): Prompt 与策略版本,即系统 Prompt、角色设定和护栏 (guardrails)
  • MRV (Model Runtime Version): 固定的模型 ID,例如 gpt-4o-2024-08-06
  • TAV (Tool and API Interface Version): 工具 Schema 和外部 API 契约版本

针对 Prompt 层级失败的回滚属于 PPV 变更。它不应该触动 ALV、MRV 或 TAV。

无状态智能体 (Stateless agents):回滚是即时的。每一轮对话都是独立的。重新分配 production 标签,所有新请求会立即在之前的版本上启动。运行中的请求在旧版本下完成,下一轮对话则使用回滚后的版本。

有状态智能体 (Stateful agents)(带有记忆的多轮会话):这就是问题所在。所需的基础设施包括:

  • 会话版本标记 (Session version tagging):每个活跃会话都存储它是基于哪个 PPV 启动的。这是启用选择性回滚的元数据字段。
  • 带平滑排空的会话固定 (Session pinning with graceful drain):当你回滚 production 标签时,现有会话继续在它们启动时的版本下运行。新会话立即使用回滚版本。随着对话完成,旧版本会话自然排空。没有硬切换,没有上下文损坏。
  • 时间点内存快照 (Point-in-time memory snapshots):这样如果错误的 Prompt 已经损坏了会话记忆,你可以恢复到事故发生前的检查点。

平滑排空模式是核心原语。在会话 ID 级别实现它,并将版本元数据字段与对话状态一起存储。前期实现的成本几乎为零,却能消除紧急回滚中最困难的部分。

对于非紧急的 Prompt 变更,使用金丝雀发布 (canary deployments)。 将 1% 的流量(基于用户 ID 或会话 ID 进行锁定,而非随机分配,以保证可复现性)路由到新的 PPV。针对金丝雀与生产环境的追踪运行一到两个小时的自动化评估器 —— 包括幻觉率、格式合规性、事实一致性得分。如果评估结果降至阈值以下,则关闭金丝雀标志。生产用户不受影响。如果评估通过,则将金丝雀标签晋升为生产标签。关于“谄媚 (sycophancy)”事件的复盘恰恰指出了这一差距:“标准检查并没有专门针对谄媚行为进行检测。” 你的金丝雀评估套件必须包含行为检查,而不仅仅是质量指标。


AI 复盘必须捕获而 SRE 运行手册容易遗漏的内容

传统的事后复盘 (postmortems) 是为基础设施故障设计的:服务宕机了,你找到了原因,然后修复了它。时间线是离散且具有因果关系的。LLM 事故并非如此。

一个 AI 特性可能会在六个小时内逐渐退化,而你所有的 SLO 指标却依然显示正常(绿色)。故障可能是行为上的(模型变得微妙地更加顺从),而不是功能上的(模型返回错误)。根本原因可能是奖励信号冲突、三周前的数据管道问题,或者是供应商未经宣布的更新。标准的运行手册 (runbooks) 没有针对这些情况的分类。

传统复盘捕获了什么,以及 AI 复盘必须扩展什么:

产物版本管理 (Artifact versioning): 传统复盘记录部署的 commit SHA。AI 复盘需要事故开始时的完整版本快照:模型版本、Prompt 版本、检索索引版本、工具 Schema 版本、评估数据集版本和护栏版本。没有全貌,你无法复现事故,也无法确认你的修复是否真正解决了根本原因。

故障层级分类 (Failure layer classification): 传统复盘会说“服务降级”。AI 复盘必须指明具体的层级:检索中断、质量退化、性能下降、成本飙升或数据事故。这些需要不同的响应方案。将它们统一归类为通用的“AI 退化”标签,注定会让你采取错误的修复措施。

Trace 证据 (Trace evidence): 传统复盘通过日志重建时间线。LLM 事故需要将实际失败的 Trace —— 渲染后的 Prompt、检索到的片段以及生成的输出 —— 附加到复盘文档中。没有具体的产物,几乎不可能复现故障,也无法研究未来的变更是否能防止此类问题。

评估差距分析 (Eval gap analysis): 标准复盘会问“为什么我们的测试没测出来?” AI 复盘会问一个更精确的版本:“缺失了哪些评估案例?哪个行为维度没有被覆盖?” 这直接反馈到评估数据集中。如果“谄媚”是失败模式,而没有任何评估案例测试谄媚行为,那么这就是可行动的发现。

奖励信号分析 (Reward signal analysis): 一家大型零售商在两年的 AI 驱动复盘分析中发现,存在约 10% 的持续归因错误率 —— 模型仅仅因为某些技术在事故线程中被提及就责怪它们。谄媚事件表明,冲突的奖励信号驱动了失败。AI 复盘必须记录事故发生时哪些优化信号是活跃的,以及它们是否存在冲突。传统的 SRE 运行手册中没有这一项。

漂移 vs. 急性故障 (Drift vs. acute failure): 传统复盘将事故视为具有明确开始时间的离散事件。AI 系统则表现出逐渐的无声退化 —— 幻觉得分在六小时内从 94% 下降到 82%,却没人注意到。这些是不同的事故类型,需要不同的纠正措施。漂移事件不能通过回滚修复;它需要识别分布偏移的来源:输入分布变化、数据管道陈旧、索引漂移或奖励信号偏移。

AI 复盘需要而标准模板缺失的章节:

  • 请求级证据:所有版本 ID(Prompt、模型、索引、工具 Schema)以及可以在沙箱中重放的失败请求示例 ID
  • 带有证据支持的故障层级分类,列出支持和反对每个候选层级的证据
  • 为什么现有的评估和告警漏掉了这次故障,以及需要增加哪些具体的评估案例
  • 新的护栏:在下次发布前需要增加的断路器、告警、金丝雀门控和回滚规则
  • 恢复证明:修复前后的指标对比、对比修复前后输出的 Trace 评审示例,以及对残余风险的明确声明

Datadog 构建 LLM 驱动的复盘生成器的经验很有启发性:LLM 在事件重建(根据日志生成时间线)方面表现出色,但在确定根本原因和基础设施因果关系方面表现较差。AI 起草的复盘还存在近因偏差 (recency bias) —— 它们无法在沟通线程中区分被取代的中期假设与最终结论。人工评审对于任何因果关系的断言仍然是必需的。使用 AI 来起草时间线;自己动手编写根本原因。

在需要之前构建监控基础设施

诊断树只有在你拥有可供遍历的数据时才有效。大多数团队只有在发生故障时才意识到自己缺乏这些数据。

各个层级的最低限度插桩(instrumentation):

  • 检索层:记录每次查询检索到的文档分块(chunks)、相关性评分、入库时间戳以及来源。针对来自单一来源的突发集中度以及检索分块的存续时间超过阈值的情况设置告警。
  • 生成层:记录完整的渲染后 Prompt(而不仅仅是模板)以及 API 响应中的模型版本字段。针对模型版本变更设置告警。对生产输出样本持续运行轻量级幻觉评估(hallucination eval)。
  • 路由层:记录工具选择和意图分类。针对流量份额偏差设置告警——如果某个工具平时占据 20% 的流量,突然变成了 80%,说明出了问题。
  • 成本与循环层:跟踪每个会话的 Token 数量并设置硬性预算上限。针对超过阈值的会话设置告警。记录智能体(agent)间的调用图,并针对循环调用设置告警。

针对隐蔽的质量下降,使用 sentence transformer 对输入的 Prompt 进行嵌入(embed),并利用统计距离(statistical distance)将其分布与基准线进行比较。输入分布的偏移可以在用户投诉到来前几天预测出质量下降。


五步故障分诊循环

当告警触发或用户报告行为异常时,最初的 15 分钟决定了你是花费 1 小时还是 1 周来处理该事故。

  1. 追踪(Trace):找到失败的跨度(span)。分别定位检索、Prompt 渲染和生成步骤。识别出哪个层级产生了非预期输出。
  2. 隔离(Isolate):使用诊断树对故障进行分类。在确定层级分类之前,不要尝试进行任何修复。当故障出在检索层却去修复生成层,这比什么都不做还要糟糕——你会掩盖症状而无法解决根本原因。
  3. 评估(Evaluate):对失败的追踪运行自动化评估器。包括真实性(groundedness)、格式合规性、检索相关性。建立一个数值基准,以确认你的修复确实有效。
  4. 模拟(Simulate):在受控覆盖的沙盒中重放失败的请求。一次只更换一个变量:Prompt 版本、模型或检索到的上下文。修复失败的那个变量就是根本原因。
  5. 修复与回归(Fix and regress):在部署前对照黄金数据集(golden dataset)测试修复方案。将失败案例添加到评估套件中。通过金丝雀发布(canary)进行部署,而不是直接推送到生产环境。

差距在哪里

业界在模型评估和 Prompt 工程上投入巨大,但在运营层几乎没有任何投入:版本化回滚、会话安全的金丝雀部署、特定层级的告警路由,以及能够捕获行为故障的复盘(postmortem)格式。

一项针对 2025 年 1,200 个生产环境 LLM 部署的调查发现,模型偏移(model drift)导致了 40% 的生产环境智能体故障,而工具版本问题导致了 60%。这些不是模型质量问题——而是运营纪律问题。它们需要通过基础设施和流程来解决,而不是靠更好的 Prompt。

能够妥善处理 LLM 事故的团队会将每一个部署的 Prompt 视为版本化的制品,在每个金丝雀发布门控中运行行为评估,并在首个事故发生前就制定好书面的事故分类方案。而做不到这一点的团队仍在通过 grep 命令检索日志,并寄希望于下一次模型更新能表现得更好。

在需要之前编写好运行手册(runbook)。当你拥有它时,处理第一个事故的时间将比没有它时缩短许多。

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