常规软件的降级是可见的。慢查询就是慢。失败的请求返回一个错误。用户看得见出了问题,运维也看得见。

AI 功能的降级是不可见的。供应商比平时慢,于是超时截断了检索步骤,于是模型用比它应该拥有的更少的证据回答 —— 一样流畅、一样的语气、一样的长度,一样没有任何保留措辞。响应里没有任何东西写着”这一条我是用一半上下文答的”。系统没有失败。它安静地产出了一个更差的答案,而这件事唯一留下痕迹的地方,是一个没有人在看的指标。

所以我们在功能之前先写降级路径。

先回答的那个问题

在设计”功能正常时做什么”之前,我们先回答一个更窄的问题:它在没有把握的时候返回什么?

诚实的答案只有几种,而在其中做选择是产品决策,不是工程决策:

不在这份清单上的是”照样回答”。这是所有未被特别交代过的 AI 系统的默认行为,也是单次事故里信任损耗最高的行为。

为什么必须先写

事后补的降级路径是补丁。先写的降级路径会反过来约束设计 —— 而这个约束是有生产力的。

一个必须能说”我不知道”的功能,需要一个”证据不足”的定义,这迫使检索契约变得明确。一个必须能回退到确定性路径的功能,需要那条路径真的存在,这给”产品有多少部分可以依赖模型答对”划了上限。一个必须显示缓存答案时效的功能,需要在管线里追踪来源,而这套管道恰好就是让事故可调试的那套。

这些工作我们本来也想做。按这个顺序,我们在它变紧急之前就做了。

我们在管线里建什么

每个阶段都要为”输入缺失或过期”定义行为。 不是抛异常,是一个行为。检索返回零篇文档是一个有既定答案的寻常状态,不是在生产里才被发现的边缘情况。

工具失败必须以失败的形式对模型可见。 把报错载荷当作数据塞进上下文,是产出自信错误答案最可靠的一种方式。模型必须能分辨,而系统必须能在这个分辨重要的时候阻止它继续。

置信度必须来自系统,不是来自措辞。 问模型它有多确定,你会得到一个范围正确、分布错误的数字。我们从自己能控制的东西里推导它:检索到多少证据、证据有多旧、本该应答的工具是否应答了、反复运行的结果是否一致。

降级过的响应要标注在载荷里,而不只在日志里。 如果调用方分辨不出完整答案和降级答案,所有下游消费者都会把两者当成完整的,降级于是在上一层重新变得不可见。

运维的那一半

从来没跑过的降级路径不是降级路径,是一个未经测试的分支,而它第一次遇见生产将会是在一次事故当中。所以它必须被刻意演练:eval 套件里的故障注入,以及一个能在预发环境强制走降级路径的开关 —— 好让用户在最坏情况下看到的东西,是团队真的看过的东西。

事后我们盯的数字不是可用率,而是降级路径服务的响应占比及其趋势。可用率说明系统答了。这个占比说明它是用什么答的。

这件事真正在说什么

AI 系统的可靠性,不是没有状态不好的日子。供应商会变慢,索引会过期,工具会返回畸形结果。可靠性是:系统如实告诉你今天是哪种日子。

先设计这条路径,功能就会被它塑形。最后才设计它,你会交付一个”最糟的行为恰好是最自信的行为”的系统。