跳转到主要内容

AI 系统中的功能交互故障:当两个正常运行的组件结合时发生崩溃

阅读需 1 分钟Tian PanTian Pan

你的流式传输正常工作。你的重试逻辑正常工作。你的安全过滤器正常工作。你的个性化功能也正常工作。但当你将它们部署在一起时,奇怪的事情发生了:流式传输中途出现的速率限制错误导致用户看到的是一段被截断的响应,而系统却将其记录为成功。重试机制触发了,但流式传输已经结束。个性化层提供了一个定制化的响应,而安全过滤器本应拦截这个响应——除非过滤器看到的是 Prompt 的脱敏版本,而不是个性化层所处理的那个版本。

每一个功能都通过了你编写的各项测试。然而系统还是让用户失望了。

这就是功能交互故障(feature interaction failure),它是当今 AI 系统中最容易被误诊的生产环境 Bug。

为什么单一测试无法发现交互故障

测试 AI 系统的标准思维模型通常是这样的:为每个功能编写测试,确保每个测试都通过,然后发布。当各功能相互独立时,这种模型运作良好。但当功能共享状态、按顺序执行,或对其他功能已经完成的工作做出隐含假设时,这种模型就会彻底失效。

数学规律是无情的。五个可靠性均为 99% 的组件组成的系统,其整体可靠性仅为 95%。再增加五个组件,可靠性就会降至 90%。但可靠性并不是真正的问题,隐性失败(silent failure)才是。在传统的软件系统中,5% 的失败率会出现在你的错误日志中。但在一个组合式 AI 系统中,这 5% 的失败通常表现为看起来正确的输出:连贯的句子、有效的 JSON、没有抛出任何异常。系统认为自己成功了,但用户收到的却是错误的内容。

关于多智能体系统的研究发现,简单的组合产生的错误大约是单智能体系统的 17 倍,而且其中大多数在组件级别是不可见的。在被归类为“规格说明失效”(specification failures)的 42% 故障中(即系统行为偏离了意图,但技术上没有任何组件发生故障),几乎全都是伪装下的交互故障。

让生产团队头疼的三种冲突模式

交互故障的清单很长,但有三种模式经常出现,以至于每一个构建组合式 AI 系统的团队最终都会至少遇到其中一种。

流式传输 + 重试逻辑

流式传输和重试机制对于请求如何完成有着截然不同的假设。重试逻辑假设如果请求失败,你可以重新执行它。流式传输则假设部分输出已经交付给了客户端。

冲突发生在衔接处。在一个 1000 token 的响应中,如果在第 400 个 token 处出现速率限制错误,意味着部分内容已经显示在用户的浏览器中。重试机制看到了 429 错误并重新执行了整个请求——这在技术上是正确的——但客户端现在收到的却是一个重复的开头,并拼接在之前截断的第一个响应之后。或者重试机制根本没有触发,因为在流中出现错误之前,请求在技术上已经返回了 200 状态码。

这种失效模式在单元测试中是不可见的,因为重试逻辑的单元测试通常模拟的是在返回任何 token 之前就失败的请求。流式传输集成测试则验证 token 是否到达。没有任何测试会构建出在实时重试循环中流式传输中途发生错误的情景。

解决办法是架构层面的:将生成过程与客户端连接解耦。LLM 调用存在于一个可以独立重试的服务层;客户端连接则订阅输出队列。这意味着重试机制和流式传输机制永远不会触及相同的状态。

缓存 + 新鲜度要求

缓存可以降低延迟并减少成本。新鲜度要求则意味着某些数据必须反映世界的当前状态。这两个目标之间存在直接的张力,当两个功能都不知道对方存在时,它们会产生糟糕的交互。

一个带有语义缓存的客服机器人可能会根据 47 分钟前有效的缓存条目来回答“订单 #12345 的状态是什么?”。而订单在此期间已经发货了。响应是连贯的、具体的,但却是错误的。系统没有抛出异常。准确率指标也捕捉不到这一点,因为它测量的是响应是否格式正确,而不是底层数据是否是最新的。

在多跳场景中,这种失效更为严重。智能体检索缓存的用户偏好(“寄送到办公室地址”),然后检索缓存的地址记录,最后生成确认信息。每一次缓存查询独立看起来都是正确的。但用户今天早上更改了地址,现在正等着一个会寄送到错误大楼的包裹。

RAG 系统也面临类似的变体:在嵌入(embedding)时准确的向量索引,随着源文档的更改会悄然变得陈旧。近似最近邻检索没有新鲜度的概念——它寻找的是语义相似的文档,而不是当前准确的文档。构建实时应用的团队发现,只有当用户询问昨天发生变化的事情时,他们才会发现每晚重新索引的计划造成了 24 小时的新鲜度差距。

这里的交互审计针对每个缓存层提出了一个简单的问题:当用户的查询需要特定事件发生之前就被缓存的数据时,会发生什么?列出这些事件(记录更新、政策变更、价格变动),然后追踪接触这些记录的每一个功能。

个性化 + 安全过滤

个性化和安全过滤通常被实现为独立的中间件层,且每一层在隔离状态下都能正常工作。个性化根据用户历史记录或明确的偏好来定制响应;安全过滤则拦截违反政策的响应。

当这两层在同一个请求的不同表示形式上运行时,冲突就发生了。个性化层可能会在将请求传递给模型之前对其进行转换(例如 “像海盗一样回答,语气随意”)。安全过滤器可能会评估原始请求、转换后的请求或最终响应——在许多实现中,它会评估任何检查成本最低的表示形式。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 10 分钟

人工接管作为一等功能:设计能够优雅降级至人工控制的 AI 系统

大多数 AI 系统将人工接管视为错误状态,而非设计模式。以下是如何将接管协议构建为一等操作路径而非事后补救的方法。

insider
ai-engineering
阅读需 10 分钟

当你的 AI 功能过时:生产环境中的知识切断与时间溯源

基于具有固定训练切断点模型构建的产品,会随着世界与训练数据的偏离而失效。本文将介绍如何检测由知识切断引起的故障、管理 RAG 的新鲜度,并在时间漂移演变为隐蔽的生产回归之前进行针对性设计。

insider
ai-engineering
阅读需 9 分钟

最后一公里可靠性问题:为何 95% 的准确率往往意味着 0% 的可用性

95% 的准确率听起来很好,直到你意识到这意味着你的 20 步 AI 工作流只有 36% 的时间能成功运行。本文介绍失败分类法和真正能弥合最后一公里差距的架构修复方案。

insider
llm
阅读需 10 分钟

当你的模型偶尔出错时,99.9% 的可用性意味着什么

传统的 SLA 对于成功与否具有概率性的 AI 功能而言毫无意义。本文将介绍合同用语和内部 SLO 设计,让工程团队在不承担无限责任的情况下发布 AI 功能。

insider
ai-engineering
阅读需 9 分钟

演示到生产的失败模式:为什么AI原型在真实用户到来时会崩溃

演示使用精心挑选的输入、预热缓存和有耐心的评估者。生产环境面对的是对抗性查询、分布偏移的请求以及8秒内就会放弃的用户。以下是缩小差距的预发布方法论。

insider
ai-engineering