跳到主要内容

供应商 99.9% 的 SLA 对你的 Agent 来说衡量边界错了

· 阅读需 14 分钟
Tian Pan
Software Engineer

一个模型提供商发布了 99.9% 的可用性 SLA。采购团队将其理解为“三个九,每年四个小时的停机时间,对于非 0 级(非核心)工作负载是可以接受的”。六个月后,智能体(Agent)功能上线,值班仪表板显示用户感知的任务成功率约为 98% —— 这个数字没有写进任何合同,在提供商的状态页面上也找不到,而且没有人为此负责。提供商满足了他们的 SLA,而产品却没达到其 SLO。两者同时成立,而这种差距并不是一个 bug —— 这是一个算术问题。

大多数团队都忽略了算术这部分。提供商的 99.9% 是针对同步请求工作负载进行衡量的 —— 一个用户,一个提示词,一个响应,一个计费事件。而智能体并不会产生这种工作负载。一个用户感知的任务会扇出(fan out)为 8 到 20 次推理调用,它会对瞬时错误进行重试,对慢速调用进行对冲(hedge),并聚合部分输出。每一次调用都是对提供商故障分布的一次独立抽样,如果任何关键调用失败,任务就会失败。SLA 覆盖的边界和用户感受到的边界并不是同一个边界。

这篇文章讨论的是背后的数学逻辑、本应存在但实际缺失的合同条款,以及在用户发现之前揭示这种差距的可观测性工作。一个反复出现的主题是:供应商的 SLA 是对其进行基准测试的工作负载的声明,而你的智能体产生的并不是那种工作负载。

无人协商的组合数学

串联可用性(Series availability)是一个教科书级的案例。如果一个系统依赖于 N 个组件,每个组件的可用性为 A,且当其中任何一个组件失败时任务就会失败,那么总可用性大约为 A^N。三个可用性均为 99% 的组件组合在一起,总可用性只有 97%。二十个可用性均为 99.9% 的组件组合在一起,总可用性为 98.0%。数学是无情的:冗余可以帮你恢复,但一连串的独立调用会使故障概率倍增,而不是成功概率。

带入行业中的真实数字。据报道,在最近的 90 天窗口内,某主要模型 API 的提供商可用性低至 98.95%,另一家整体约为 99.76%,其 API 组件偶尔会长时间跌至 99% 以下。这些是真实的、近期的运行数据 —— 而不是营销口号里的 99.99% —— 它们之所以存在,是因为基础模型基础设施还很年轻,且受到的容量限制是成熟的云 API 所不曾有的。

现在将其与智能体循环结合。假设你的智能体为每个用户任务进行 12 次推理调用 —— 1 次规划器(planner)调用、4 次检索接地(retrieval-grounding)调用、4 次工具结果摘要调用、2 次重新规划以及 1 次最终综合。在每次调用可用性为真实的 99.5% 时,任务可用性约为 0.995^12 ≈ 94.2%。这意味着每月有超过 30 小时的任务失败,而对应的提供商在合同层面却完美达成了 99.5% 的目标。在单次调用 99.9% 的情况下,你得到的任务可用性是 98.8% —— 仍然比提供商状态页面显示的要差一个数量级的错误率。

你签署的 SLA 描述的是提供商负载均衡器可以测量的边界处的单次调用可用性。而你的用户所感受到的数字是你的产品所属边界处的单次任务可用性。这里没有阴谋 —— 只是两个不同的分母而已。

重试无法修复问题;它们在另一个维度上让情况变得更糟

第一直觉是增加重试。来自速率限制器的 429、来自故障区域的 503、来自慢速节点的超时 —— 这些大多数会在几秒钟内恢复,重试可以恢复调用。于是团队增加了带抖动的指数退避(exponential backoff with jitter),并认为问题解决了。

事实并非如此。重试改变了故障分布,但它们引入了三种提供商 SLA 未覆盖的新故障模式:

成功但缓慢路径上的延迟税。 超时重试策略会将一个慢速调用变成“慢速调用+重试调用”。如果 5% 的调用触发了 10 秒超时,并重试后在 2 秒内成功响应,你就将 P95 延迟提高了一倍,而用户感知到的这种减速是任何单次调用 SLA 都无法捕捉到的。在预热过的提供商层级上运行串行调用的评估平台永远看不到这一点。

反馈至速率限制的重试风暴。 发生故障的提供商区域返回 429。你的重试策略向同一区域又发送了三个请求。每一个这样做的智能体都会将负载放大 3 到 4 倍。如果在故障期间你的集群中有 10% 正在重试,那么有效负载会在提供商最无法处理的时候剧增。提供商并没有违反他们的 SLA —— 他们返回了正确的 429 —— 但你的系统自我放大了问题。重试风暴在几秒钟内将负载放大 10 倍,是智能体集群中已证实的生产环境模式。

失败路径上的成本放大。 一个包含 12 次调用的任务,如果在最糟糕的一次调用上重试三次,就变成了 15 次调用。在故障期间的整个集群中放大这一点,你就会看到一笔可观的每月成本支出,而这仅仅是因为提供商稍微有些不稳定。你的财务团队会在你的 SRE 团队发现原因之前先看到账单。

重试策略正在准确执行它的设计功能。问题在于,“瞬时错误”和“用户感知的任务失败”是不同的事件,为前者校准的修复方案并不能改善后者。

那些应该存在但尚未出现的合同条款

大多数 LLM 供应商的合同都继承了同步 Web API 合同的 SLA 架构。它们以单次请求为界限,探讨可用性百分比和赔偿额度阈值。而真正能保护智能体(Agent)工作负载的条款通常是缺失的。一旦采购团队理解了其中的计算逻辑,在续约时争取这些条款将是杠杆率最高的举措之一。

针对扇出(Fanout)的速率限制突发余量(Burst Headroom)。 标准的速率限制条款是一个稳态上限:每分钟 N 次请求。Agent 不会产生稳态负载——它们产生的突发负载与用户的任务到达模式一致,每个任务会快速连续触发 10-20 次调用。相比于将稳态上限提高 50%,在短时间内(例如 15 秒内达到稳态限制的 4 倍)提供明确的突发预算条款要有用得多。

针对瞬时故障的重试容错赔偿。 大多数 SLA 赔偿触发条件是基于供应商视角的“请求”计算出的错误率超过某个阈值。你应该协商一种赔偿核算方式,将“重试后最终成功”的调用也视为部分失败——虽然供应商的指标在第二次尝试时将其计为完全成功,但它们消耗了你的延迟和 Token。

Token 间延迟(Inter-token latency)上限,而非仅仅是首个 Token 耗时(TTFT)。 流式传输 SLA 通常只覆盖首个 Token 耗时。用户感知到的是 Token 间的抖动,而不是首个 Token 的延迟。供应商可能达到了 TTFT 上限,但在响应中途出现了 3 秒的停顿,这在用户看来就是“挂了”。应争取将 p99 Token 间延迟写入合同指标,或者至少作为公开的 SLI。

具有 Prompt 版本一致性的多区域故障转移。 当一个供应商区域发生故障,你路由到另一个区域时,模型版本、Prompt 缓存状态,甚至分词器(Tokenizer)版本都可能存在细微差异。如果合同条款要求跨区域锁定模型版本并承诺协调滚动更新(这样你就不会在区域切换期间遇到跨版本偏差),就能避免一整类看起来像回退(Regression)实则是路由副作用的事故。

协商这些条款的成本相对于交易规模通常很小。而不具备这些条款的代价,则会在三个季度后转化为繁重的事故处理工作。

多供应商路由改变了计算逻辑,但并非没有代价

应对组合性问题的自然反应是多供应商路由——如果任何单一供应商的可用性是你的上限,那么通过两个供应商进行扇出,你的组合可用性就会提升。这确实有效,但有前提条件。到 2025 年中期,大约 40% 的生产级 LLM 团队已经实施了多供应商路由,主要动机是两大主流供应商都发生过明显的停机事故。

从数学上讲,并行冗余提高了可用性。两个可用性均为 99.5% 的供应商可以提供 1 - (1 - 0.995)^2 = 99.9975% 的并行可用性——让两个“三九”变成了接近“四九”。但这种计算假设了独立性(相关性故障,如共享底层云供应商,会打破这一假设)、假设了质量等效(廉价的备用方案可能通过了可用性检查,但在质量检查中发生回退),并假设了无缝切换(当 Prompt 针对每个模型进行微调时,这比听起来要难)。

需要预留预算的运营现实:

  • Prompt 可移植性是一项非平凡的工程项目。 针对模型 A 有效的 Prompt 经常在模型 B 上发生回退,原因是指令遵循偏好、分词器行为或输出格式先验知识的差异。评估套件(Eval suite)是最后一道防线,但在两个供应商之间维护并行的评估套件是一项持续性的工作。
  • 跨供应商的工具调用(Tool-call)Schema 漂移。 每个供应商在函数/工具调用、结构化输出和错误语义方面都有略微不同的约定。抽象这些差异的中间件必须针对每个供应商实际产生的失败模式进行测试,而不仅仅是针对正常路径。
  • 热备容量的成本。 将一部分有意义的流量保持流向次要供应商,以使其保持“热”状态并确保你拥有最新的质量数据,这并非免费。将其作为故障转移时才激活的冷备运行,意味着故障转移后的第一波流量将遇到冷缓存和延迟退化,而这恰恰发生在最糟糕的时刻。

多供应商路由对于大规模的大多数 Agent 工作负载来说是正确答案,但它将问题从“我的可用性是多少?”提升到了“我的可用性、质量和成本分别是多少?”,答案不再是仪表盘上的一个简单数字。

可观测性:将供应商指标与测试框架统计数据结合

大多数团队构建不足的部分是可观测性层,该层应将供应商指标与你自己的测试框架(Harness)统计数据结合,形成一个任务级的可用性数字。供应商的状态页面显示的是他们的视角,你的 APM 显示的是你代码的视角。两者都无法显示用户的视角。

一个有效的设置需要缝合以下三点:

  • 区分调用结果的单次调用插桩(Instrumentation)。 不是“成功或失败”,而是“第一次尝试成功”、“N 次重试后成功”、“耗尽重试后失败”、“切换到备用供应商后失败”。每种情况都有不同的成本和延迟含义。
  • 定义用户可见边界的任务级聚合。 一条追踪(Trace)记录,将每次扇出调用映射回启动它的用户请求,并带有一个任务成功标签,该标签取决于 Agent 自身对完成的定义,而不是单个调用的状态码。
  • 供应商 SLI 与你的 SLI 之间差距的漂移告警。 当供应商的 API 可用性下降 0.2 个百分点时,你的任务可用性通常会下降 1-2 个百分点。针对这种**发散(Divergence)**进行告警——即你的指标下降速度快于他们的指标——能在任何一方的绝对数值突破 SLO 之前,发现自放大的重试风暴或跨调用的级联故障。

漂移告警是杠杆率最高的部分。绝对的任务成功率是一个滞后指标,在事故发生后很容易产生争论。供应商可用性与任务可用性之间的发散告诉你是组合层中的某些因素——重试策略、扇出模式、重新规划逻辑——正在将上游的微小波动放大为下游的剧烈震荡。这是你可以在事故处理过程中采取行动的信号,而不是事后。

本季度实际该做的事情

如果你的团队正在根据供应商的 SLA 交付 Agent 功能,那么操作手册只有一页:

  1. 计算你的扇出系数 (Fanout factor)。 观察一天的真实流量。中位数用户任务会产生多少次供应商调用?P95 是多少?你可能并不了解这个数字,而它正是所有其他决策的输入依据。
  2. 进行数学组合计算。 将单次调用的供应商可用性乘以扇出系数。将其与你的任务成功率 SLO 进行对比。如果组合后的数值低于 SLO,那么无论供应商在 SLA 范围内的表现有多出色,都无法挽救你的业务。
  3. 审计重试策略。 对于每一个可重试的错误,请思考重试是在恢复调用,还是仅仅在放大负载。针对语义错误进行重新规划 (Replanning),以及在发生关键错误时取消未完成的扇出,通常比进行第四次重试具有更高的杠杆率。
  4. 在续约时协商正确的条款。 突发容量余量 (Burst headroom)、感知重试的额度计费、Token 间延迟上限、固定区域的模型版本。这些条款在签约时要求成本很低,但事后弥补却代价高昂。
  5. 建立偏差告警。 监控“供应商 SLI 减去任务 SLI”的数值,针对两者的差距而非绝对值进行告警。这个指标能捕捉到供应商状态页未能反映的事故。

架构上的核心结论很简单:“我们运行在可用性为 99.9% 的供应商之上”这句陈述,描述的是供应商进行基准测试时的负载,而不是你的 Agent 所产生的负载。用户感知的业务可用性是一个综合体——包括供应商可用性、重试策略、扇出模式、聚合逻辑——而每一个环节都需要你亲自设计。合同是底线,数学决定了上限。

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