跳到主要内容

182 篇博文 含有标签「reliability」

查看所有标签

跨团队 Agent SLA 无法简单叠加:你的组织遗漏预算的 99% 数学陷阱

· 阅读需 13 分钟
Tian Pan
Software Engineer

A 团队的智能体宣传其成功率为 99%。B 团队的智能体也宣传 99%。调用这两者的全新联合工作流在状况良好时成功率为 98%,而在状况不佳时仅为 96% —— 负责该联合工作流的团队现在成了两个他们不拥有、无法在本地复现、且未编写评估集的系统的事实上的 SRE。每个上游团队都达到了其 SLO(服务水平目标)。但复合产品却未达标。边界正确一侧的报警器却始终保持沉默。

这是独立失败率的数学问题,自从组织开始允许智能体相互调用以来,它就一直潜伏在显而易见的地方。五个可靠性为 99% 的组件会给你带来 95% 的端到端可靠性。十个组件则会降至 90%。一个每步成功率为 95% 的 20 步流程,其最终成功率仅为 36% —— 超过一半的操作在完成前就会失败。当一个工作流链接了 50 个组件时 —— 一旦企业级智能体开始调用子智能体,再由子智能体调用工具智能体,这种情况并不罕见 —— 一个每个环节都“99% 可靠”的系统,在大约十次请求中就会失败四次。

研究人员在分析了超过 150 个任务中的五个流行多智能体框架后,发现失败率在 41% 到 87% 之间,其中排名前三的失败原因是:步骤重复、推理与行动不匹配,以及对终止条件的忽视 —— 观察发现,与单智能体基准相比,非结构化的多智能体网络会将错误放大高达 17 倍。这其中的数学逻辑并不深奥。问题在于,组织的 SLO 表、仪表板、轮值安排和 PRD 仍然是以单个智能体为单位进行定义的。

人类注意力预算是你的 HITL 系统在默默透支的约束条件

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的审核员今天早上做出的第 50 个决策与第 1 个决策的质量并不相同。架构图不会显示这一点。容量模型不会显示这一点。跟踪“每小时审批量”的仪表盘甚至在主动掩盖这一点。然而,你的人机回环(Human-in-the-loop,简称 HITL)系统的整个前提——即由人来捕捉模型产生的错误——从队列开始填充的那一刻起就在无形中退化。

大多数 HITL 设计将审核员的时间视为一种无限的、可互换的资源。团队设置一个置信度阈值,将所有低于该阈值的项路由到人工队列,并宣布系统是“安全”的。六周后,审批率已悄然升至 96%,队列深度是人员配置模型假设的两倍,抽样审计显示审核员正在对他们在第一天会标记出来的边缘案例点击“批准”。系统并没有崩溃,它只是通过“橡皮图章”式的盲目审批,让自己看起来运转良好。

70% 可靠性恐怖谷:AI 功能丧失用户信任的深渊

· 阅读需 13 分钟
Tian Pan
Software Engineer

一个故障率高达 70% 的功能是无害的。用户在一周内就会发现他们必须验证每一条输出,将系统视为一个不可靠的助手,并做出相应调整。而一个成功率达到 70% 的功能则更糟糕。它正确的频率足以让用户停止验证,而错误的频率又足以让失败变得集中、显眼且具有针对性。用户的心理模型会崩塌为“我不知道什么时候该信任它” —— 这种产品体验从根本上比“我知道不要信任它”更糟糕。

这就是 70% 的恐怖谷,也是过去两年中构建的大多数 AI 功能所处的位置。团队衡量综合准确率,看着数值超过某个“足够好”的阈值,然后发布。实际的用户体验并不随着这个数字单调提升。在大约 60% 到 85% 的准确率之间,产品随着准确率的提高反而变得更差,因为用户因疏于检查而导致的错误成本,超过了他们无需验证正确答案所带来的价值。

那些在不考虑可预测性问题的情况下发布 70% 准确率产品的团队,发布的并不是一个 95% 产品的拙劣版本。他们发布的是一个完全不同的产品:一个主要的失效模式是隐形的产品。

智能体记忆漂移:为什么一致性对齐是你缺失的关键环

· 阅读需 12 分钟
Tian Pan
Software Engineer

你长期运行的智能体(agent)所做的最危险的事情,也是它做得最自信的事情:根据记忆回答。客户的地址在上周二更改了。智能体认为“开启”的工单在昨天被人工关闭了。智能体拥有整洁解释笔记的产品功能,其实际交付的形式与智能体三周前阅读的规范不同。在教科书定义上,这些都不属于幻觉——模型准确地召回了它存储的内容。只是在智能体看向别处时,世界已经发生了变化。

大多数团队将记忆视为一个写入问题:智能体应该记住什么、我们如何总结、嵌入(embedding)策略是什么、如何防止存储爆炸。这种思维方式产生的架构会随着错误程度的增加而变得更加自信。更难的问题——那个决定你的智能体在第三周后是否仍然有用的问题——是对账(reconciliation):这是一个明确的、持续的闭环,用于比较智能体认为真实的情况与底层系统当前显示的真实情况。

无真值情况下的智能体 SLO:为无法实时评分的输出建立错误预算

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的智能体平台连续一年每季度都达到了 99.9% 的“响应成功率”SLO。但工单量增加了 40%。受智能体引导的用户群体的留存率却在下降。轮值运维感到无聊,产品经理在恐慌,而管理层评审一直在问,为什么仪表盘显示一切正常,而支持队列却显示情况一团糟。仪表盘没有撒谎。它只是衡量了错误的东西 —— 因为编写 SLO 的 SRE 将成功定义为“模型 API 返回了 200”,而这正是遥测系统最初唯一能表达的成功定义。

这是智能体可靠性工程的核心问题:成功的信号不是状态码。它是一种关于智能体是否针对特定任务做了正确事情的判断,而这种判断在请求时是无法获得的,通常在会话时也无法获得,有时只有在几天后,当用户提交工单、修改输出或悄无声息地流失时,才能揭晓。你无法在一个尚不存在的列上标记“200 对比 500”的布尔值。

常见的反应是等待获得基准真相(ground truth)后再宣布 SLO。这是错误的。可靠性工作不会在你构建标注流水线时暂停。正确的做法是针对你明知不完美的代理指标(proxies)编写错误预算,将它们命名为代理指标,设定团队在指标触发时的响应策略,并在产生基准真相后将其回填到计算中。这篇文章将探讨如何在不自欺欺人的情况下做到这一点。

取消安全的智能体:你的“停止”按钮背后已经产生的副作用

· 阅读需 12 分钟
Tian Pan
Software Engineer

用户点击“停止”,因为智能体(agent)误解了请求。UI 界面闪烁着“已停止”。在加载图标消失时,智能体已经发送了两封邮件,在你的日历上安排了周二的会议,针对错误的分支开启了一个草稿拉取请求(pull request),并排队发送了一条正在通过工具层追赶取消信号的 Slack 消息。模型已经听话地停止了生成 token。但外部世界并未停止对它三十秒前生成的 token 做出反应。

这是智能体演示中没人提及的失败模式。同步代码中的取消操作本身就是一个难题,背后有一整代协作式取消理论的支持:Go contexts、Python 的 asyncio.cancel、带有任务组的结构化并发,以及“礼貌请求、谨慎升级、不留资源”的整套语法。智能体在这个本就困难的问题上又增加了一层复杂性:规划器不知道用户在第 4 步和第 5 步之间撤回了授权,而它在第 4 步启动的工具在第 5 步被取消时也不会收到通知。“停止”只是一个 UI 交互功能。其背后的系统必须经过专门设计。

当需求是悬崖而非曲线时,如何进行 GPU 产能规划

· 阅读需 13 分钟
Tian Pan
Software Engineer

当 Agent 平台第一次崩溃时,事后分析报告(Postmortem)通常包含这样一句话:“周五我们还有八周的冗余容量。到了周一下午,我们已经达到了已配置容量的 140%。”没有人撒谎。容量模型本身是正确的,只是被应用到了一个它从未被设计用来应对的工作负载上。传统的容量规划假设需求沿着一条平滑曲线增长,周季节性是主导信号,最坏的情况是可以提前六个月规划的“黑色星期五”。Agent 工作负载彻底打破了这一假设。

Agent 需求的形态不是曲线,而是悬崖。有三件事造成了这种悬崖效应,并且它们会产生复合影响。一个企业级客户的入驻,就能根据你已经签署的合同通知,在通宵之间将基线移动 10 倍。一个 Agent 循环可以将微小的用户活动增长放大为扇出倍增的浪潮,对推理端的冲击比面向用户的图表显示的要高出 30 倍。单个产品变更——例如启用工具调用、延长上下文、切换到更大的模型——可以在用户数量不变的情况下,将单个任务的 Token 消耗提高一个数量级。

如果你的容量规划以 QPS 为单位,且你的冗余预算是“75% 的利用率是健康的”,那么你不是在规划。你是在赌这三个“悬崖”不会在同一个星期降临。

JSON 模式是一种方言,而非标准:你备选路径中的隐形崩溃

· 阅读需 13 分钟
Tian Pan
Software Engineer

我第一次看到备用路由引发的事故比它试图缓解的停机故障还要严重时,复盘文档的标题是这样写的:“主服务降级 11 分钟。备用服务导致我们的解析器降级了 6 天。” 没人写错代码。没人跳过 Schema 评审。18 个月前连接备用服务时的二级供应商集成测试还是通过的。其间发生的事情是,两个供应商之一悄悄收紧了其枚举强制转换(enum coercion)策略,而我们下游解析器所遵循的契约——我们认为“或多或少就是 JSON Schema”的契约——已经从共享标准漂移成了两个略微不兼容的方言。

这是我不断看到的失败模式,而且它总能让那些本该更明白的团队感到惊讶。“JSON 模式”听起来像是一个你开启的功能。其实不然。它是一个你需要维护的契约——针对你可能路由到的每一个供应商分别维护——而且随着供应商演进其结构化输出技术栈,这个契约每季度都会发生漂移。你签署合同时供应商文档中所暗示的“无缝替换”,在生产环境中其实是一个需要维护的转换层。如果没有这个层,你的备用路径就会变成一个纸面上的合规产物:存在于架构图中,但在你真正需要它的那天却是坏的。

负载降级是为人类设计的,而 Agent 会放大你正在抵御的风暴

· 阅读需 13 分钟
Tian Pan
Software Engineer

对人类来说,503 意味着一个“稍后再试”的页面和一段咖啡休息时间。对 Agent 来说,503 只是在七次重试中的第一次尝试前那 250 毫秒的挫折,而且规划器(planner)已经开始询问 LLM 是否有其他工具可以绕过这个失效的依赖项。第一种行为为过载的服务提供了恢复空间。第二种行为则是过载服务的噩梦:数以千计的关联重试,每一次都比人类的操作更廉价、更快速,其中一半还会扩散(fan out)到下一个依赖项,因为规划器认为那是一个富有创意的变通方案。

负载脱落(Load shedding)—— 即通过丢弃低优先级任务来维持高优先级路径可用的准则 —— 是在流量发送主体主要是键盘前的人类,或者是具有手动调优重试策略且行为良好的服务的时代设计的。当 Agent 集群出现时,这两个假设都会瞬间崩塌。Agent 重试速度更快,能同时从更多地方发起重试,绕过故障重新规划,并把你返回的 503 视为负载均衡的暗示,而不是你本意中希望达成的协作式背压(back-pressure)信号。

本文将探讨为什么标准的负载脱落策略在面对 Agent 客户端时会失效,上游服务需要什么样的原语才能真正卸载 Agent 流量,以及 Agent 本身在工具层和规划层必须做些什么,才能不再成为别人事故报告中的恶意流量。

重新规划而非重试:为什么大多数智能体错误并非瞬时性的

· 阅读需 12 分钟
Tian Pan
Software Engineer

一次日历写入返回了 409 Conflict。框架默认的错误处理器开始介入:退避 200ms,重试。同样的冲突。退避 400ms,重试。同样的冲突。退避 800ms,重试。等到智能体放弃并告诉用户“我无法预订会议”时,它已经浪费了三秒钟的延迟预算,去证明第一条响应就已经告诉它的事实:该时段已被占用。世界没有改变。它也不会在 800 毫秒内改变。重试永远不会奏效,因为这个错误中没有任何瞬时性的成分。

这是智能体系统中最为常见的错误处理 bug,而且它就隐藏在当今几乎每一个发布的框架之中。带有指数退避的重试模式是从无状态 HTTP 客户端中照搬过来的——在那里这种模式完全正确——但被引入到有状态的规划循环中时,它就完全错误了。对于智能体中的工具错误,正确的默认处理方式不是重试,而是重新规划。

并行工具扇出的结构化并发:谁来负责部分失败?

· 阅读需 13 分钟
Tian Pan
Software Engineer

当你的智能体(Agent)扇出五个并行工具调用——跨三个索引进行搜索、查询两个数据库、调用一个外部 API——的那一刻,你已经跨越了一道无形的界限。你不再是在编写“提示-响应”(prompt-and-response)代码,而是在编写一个并发程序。大多数智能体框架都假装你没有在这样做,而账单会在凌晨 2 点准时送达。

这种假象是令人愉悦的。规划器(Planner)发出一个工具调用列表,运行时环境(Runtime)启动它们,收集返回的任何结果,最后由规划器消费这些汇总数据。从万英尺的高空俯瞰,这就像一个扇出 / 扇入(fan-out / fan-in)流水线,大多数团队在生产环境给他们上课之前,也确实是这样对待它的。问题在于,二十年的并发编程研究——部分失败语义(partial-failure semantics)、结构化取消(structured cancellation)、背压(backpressure)、确定性错误归因(deterministic error attribution)——已经解决了你即将重新发现的那些失败模式。而你的智能体框架在默认情况下,没有引入其中的任何一项。

供应商 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 覆盖的边界和用户感受到的边界并不是同一个边界。