Brownout 模式:当你的 LLM 供应商响应迟缓而非宕机时
凌晨 3 点因为宕机而把你吵醒的告警其实是简单的。供应商返回了 40 分钟的 503 错误,你的回退机制生效了,运维手册(runbook)启动了,复盘报告(post-mortem)几乎可以自动完成。而那些没有吵醒你的告警——那些在所有仪表盘都显示绿色的情况下,让你的支持队列在 6 小时内堆满的告警——才是渐变故障(brownout)。供应商的 API 仍然有响应。状态页依然显示“运行正常(operational)”。你的 p99 延迟已悄然从 2.1 秒漂移到 14 秒,错误率从 0.1% 上升到 4%,而唯一察觉到的人是那些已经流失的用户。
供应商的可用性并不是非黑即白的二元状态。大多数团队编写的回退逻辑——“如果供应商宕机,则切换到备用方案”——本质上是用一个只有两种状态的状态机去应对一个连续变量,当供应商处于“惨淡运行”而非“彻底宕机”的状态时,这种机制根本不会触发。为渐变故障(brownouts)而设计是一个与处理宕机完全不同的设计问题,我所见过的几乎每一个生产环境中的 Agent 调度框架在发布时都没有解决这个问题。
渐变故障模式在 2026 年的重要性比一年前更高。Anthropic 的 Claude API 在最近的 90 天窗口期内可用性下降到了大约 98% —— 对于承载生产工作流的基础层来说,每季度宕机三天并不是一个理想的数字。OpenAI 自 2025 年初以来记录了 294 起事故,其中大多数是部分失效:某个区域超时而另一个区域 5xx 错误激增;某组端点的延迟向上漂移;某个模型变体的结构化输出损坏;响应连贯性在无声无息中下降,因为峰值负载被路由到了一个返回 200 OK 但质量受损的量化模型上。这些都没有触发二元宕机检测器,而且在有人诊断出问题之前,大多数事故都已经损耗了数小时的用户感知质量。
那些无法触发回退机制的失败模式
教科书式的回退链在纸面上看起来很完美:主模型,然后是同一供应商的廉价同类模型,接着是不同的供应商,最后是自托管的兜底方案。这条链路假设了一个二元信号——主模型要么工作,要么不工作。生产环境的现实则更为混乱:主模型在工作,但只是“部分”工作。有些调用在 1.8 秒内返回,有些则需要 22 秒;错误率维持在 3.5%,而不是你编写 SLO 时预设的 0.1%。你的熔断器配置为在连续失败时触发,但连续失败从未发生。你正无限期地处于一种“半损坏”的状态下运行。
问题在于,当供应商处于渐变故障状态时,大多数团队监控的核心信号——错误率——是错误的维度。错误率保持在基准线附近,但延迟增加了三倍;用户放弃了该功能,而你的错误率告警却从未触发。同样地,仅限延迟的告警在处理合法的长上下文请求时会频繁误报,并在引入后的一周内就被静音。孤立的任何一种指标都是不够的。
真正有效的检测器是一个联合信号:在滑动窗口内,延迟超过阈值 且 错误率也超过阈值,将两者结合评分而非独立判断。由于 p99 延迟能捕捉到异步的情况(即供应商在丢弃长尾请求,而非明显的全面失败),同时在正常波动期间保持安静,因此将其设定为基准线的三倍以上是一个有用的二级触发器。窗口长度也很重要:60 秒可以捕捉到真实的渐变故障,而不会因为单次突发的坏请求而触发。大多数团队为了实现方便,会针对固定次数的阈值(如连续 10 次失败)编写检测器,但半年后他们会发现,渐变故障根本无法触发它。
作为状态机的分级回退机制
一旦你接受了供应商健康度是连续的这一事实,回退策略就需要两个以上的具名状态。最小的有效集合是五个,它们应该有明确的名称,以便工程师和运维手册能够通过状态而不是触发它们的症状来引用它们。
首选状态是 首选供应商(preferred provider) —— 你默认供应商上的默认模型。第一个降级步骤是 次选供应商(secondary provider) ,在不同的供应商上运行相同级别的模型,为了恢复延迟而接受质量和成本上的差异。第二个步骤是 主供应商的廉价同类模型(cheaper sibling on primary) ,你保留原有的供应商,但切换到更小、更快的模型 —— 当渐变故障集中在特定模型变体而非整个 API 时,这非常有用。第三个步骤是 缓存或预设响应(cached or canned response) ,对于高流量查询,你从预计算缓存中返回最可能的正确答案,接受质量被限制在缓存内容范围内的现实。最后一步是 带有致歉的功能关闭(feature off with apology) ,你返回一个结构化的“暂时不可用,请稍后再试”响应,它不会产生幻觉,不会重试,也不会锁定用户界面。
状态机基于信号而非硬编码的阈值在这些状态之间切换。转换应该是不对称的 —— 易于降级,缓慢恢复 —— 因为在不同状态之间来回抖动(flapping)比停留在错误的状态更糟糕。一个常见的错误是延迟一旦在单个窗口内下降就立即恢复;你应该在返回更高一级状态之前,要求持续的恢复(例如连续 5 到 10 个健康的窗口)。这与 Netflix 用于优先级负载均衡(load shedding)的逻辑相同:快速降级,带有滞后效应地(hysteresis)缓慢恢复。
成本框架本末倒置
反对运行分级回退(graduated fallbacks)的论点通常被表述为成本问题:“我们不想为备用供应商支付费用。”这种框架是错误的,它之所以存在,主要是因为出现在仪表盘上的成本是推理费用,而没有出现的成本则是用户信任和支持负载。
诚实地算一笔账。一场持续 90 分钟、错误率为 4% 且延迟增加 6 倍的服务降级(brownout),在每小时处理 1 万个请求的功能上,上限大约会造成 600 名受挫的用户,以及需要一天时间才能处理完的海量支持工单。将其中一小部分调用通过备用供应商路 由 90 分钟的边际推理成本——即使每次调用的溢价高达 30%——也比用户成本低两到三个数量级。正确的比较不是“备用推理成本”与“主推理成本”;而是“备用推理成本”与“功能降级 90 分钟加上调试所需的工程时间以及声誉损失”之间的比较。回退路径几乎总是胜出,而那些不进行此类对比的团队,最终只能靠写出更详尽的复盘报告(post-mortems)来补救。
掩盖这一点的会计陷阱是:推理成本是来自单一供应商的单一账目项,且财务部门按月跟踪;而你的 Agent 的其他销售成本(COGS)——向量数据库负载、检索端的嵌入(embedding)推理、遥测存储、支持人力——则分布在不同的团队和预算中。“没有回退机制的成本”体现在其他账目中,而那里没有人密切关注到足以将其归因于供应商的健康状况。
面向用户的诚实模式
当系统处于降级状态时,用户需要知情——但不能以泄露供应商名称、模型版本或实现细节的方式告知。有效的模式是在不解释来源的情况下承认质量下降。“为了保持响应速度,我们目前正在使用一个速度更快但细节较少的模型”这类消息可以建立信任。“Anthropic 返回了 429 错误,所以我们切换到了 GPT-4o”则会破坏信任,这既是因为用户并不关心你的供应商组合,也是因为它告诉了你的竞争对手和对手你具体在调整哪些参数。
降级横幅应该是针对具体功能层面的,而不是全站范围的。如果 Agent 在聊天功能中处于“廉价替代(cheaper sibling)”状态,但产品的其他部分正常,那么只有聊天界面需要显示横幅。全站性的降级消息会“训练”用户去忽略它们。横幅还应包含预计恢复时间(如果有的话)——即使只是粗略的“预计 15 分钟内恢复”,也比状态页上传统的“我们正在调查”要好得多,后者会被解读为“我们毫无头绪,你短期内别指望会有新消息”。
事情的另一面是你对工程师说的话。内部可观测性需要明确暴露命名的状态。如果客户报告质量问题,支持工程师应该能够查出请求发生时功能处于什么状态——首选(preferred)、备用(secondary)、廉价替代(cheaper sibling)、已缓存(cached)、关闭(off)——而无需从延迟图表中重新推演。大多数团队没有在请求追踪(request traces)中捕获这种状态,结果导致服务降级期间的支持工单被重新路由到模型质量调查中,而真正的根本原因却未被识别。
在服务降级发生前进行测试
生产环境中服务降级处理失败的最主要原因是它从未经过测试。停机测试(Outage testing)已经非常成熟——混沌工程、停掉 API、观察结果。服务降级测试之所以罕见,是因为故障模式并非彻底中断;它是一种持续的性能扭曲,而故障注入库默认并不提供此类模拟功能。
服务降级处理的评估套件需要将模拟降级作为一等公民:注入延迟的调用(返回正确答案,但在 18 秒后)、部分错误响应(4% 的调用返回 5xx)、慢流式分块(响应到达但每秒仅 5 个 token)以及隐性质量下降(在报告来自主模型的同时返回较小模 型的响应)。每一个测试都锻炼了探测器和状态机的不同部分。将它们放在一起运行——12% 的错误率加上 3 倍延迟,再加上 30% 的响应连贯性下降——可以暴露出单故障测试会忽略的检测维度之间的交互问题。
能发现最多 Bug 的测试是:在模拟负载测试期间注入 40 分钟的服务降级,并验证测试机制是否正确地经历了 首选 → 备用 → 廉价替代 的状态转换,验证用户在每一步是否看到了正确的横幅,验证没有请求超过设定的超时时限,以及验证系统在降级清除后的定义窗口内恢复到 首选 状态。大多数团队从未运行过这种测试,因为他们没有注入服务降级的工具,因此他们是在实际发生服务降级且有付费用户在线时,才发现自己的回退策略是错误的。
补充的训练是在生产环境中影子运行(shadow-running)服务降级检测。当真实的供应商健康状况低于阈值时,记录状态转换以及系统原本会采取的操作——暂不执行——并每周审查日志。这可以在探测器引起不必要的故障转移之前发现其中的误报,并暴露团队之前不知道的服务降级。Anthropic 悄悄未达标的可靠性目标对大多数 API 消费者来说是不可见的,因为没有人运行这种影子探测器。运行你自己的探测器吧。
供应商可用性是一个连续变量
这一切背后的架构认知是:你的可靠性方案所针对的故障模型——即供应商“在线”或“掉线”——与供应商实际表现出的故障模型并不匹配。供应商可用性是一个连续变量,任何将其视为二进制状态的系统,在面对简单情况时尚可运作,但在面对常见情况时则会悄无声息地失效。这种“部分断电”(Brownout)模式并非对停机处理的细化改进;它是一个完全不同的设计问题,涉及不同的信号、不同的状态、不同的成本框架以及不同的测试。
那些在 2026 年交付可靠智能体(Agent)产品的团队,正是那些已经内化了这一认知的团队。他们在评估套件中运行着延迟与错误联合检测器、命名的多状态回退策略、非对称转换逻辑、针对每个功能的面向用户坦诚度,以及合成的“部分断电”测试固件。他们的供应商并不比其他人的更好。他们只是对供应商故障的真实样貌有更好的建模,并围绕现实而非那种便于报警系统处理的虚构模型来设计系统框架。为“供应商掉线”编写的回退方案,在面对“供应商处于亚健康状态”时是完全错误的,而重写这套方案正是大多数团队尚未完成的工作。
- https://www.requesty.ai/blog/implementing-zero-downtime-llm-architecture-beyond-basic-fallbacks
- https://www.requesty.ai/blog/handling-llm-platform-outages-what-to-do-when-openai-anthropic-deepseek-or-others-go-down
- https://www.getmaxim.ai/articles/retries-fallbacks-and-circuit-breakers-in-llm-apps-a-production-guide/
- https://gitplumbers.com/blog/the-circuit-breaker-that-saved-our-llm-fallbacks-guardrails-and-observability-th/
- https://netflixtechblog.com/keeping-netflix-reliable-using-prioritized-load-shedding-6cc827b02f94
- https://netflixtechblog.medium.com/performance-under-load-3e6fa9a60581
- https://aws.amazon.com/builders-library/using-load-shedding-to-avoid-overload/
- https://www.pymnts.com/artificial-intelligence-2/2026/anthropic-outage-shows-digital-reliability-cracking-under-ais-weight/
- https://explore.n1n.ai/blog/circuit-breakers-llm-api-sre-reliability-patterns-2026-02-15
