跳到主要内容

没人接线的紧急开关:因为功能从未失效

· 阅读需 11 分钟
Tian Pan
Software Engineer

发布标志运作完美。你在它后面发布了 AI 摘要生成器,在两周内将其比例从 1% 提高到 10%、50%,最后达到 100%,紧盯仪表盘,一切正常。季度末,平台团队的标志清理机器人发起了一个 PR,删除了这个已经多余的入口。你批准了。该 PR 与其他过期标志清理工作一起合并,代码库精简了 200 行。六周后的凌晨 2 点,供应商滚动更新了一个新的模型快照,你的摘要生成器开始信誓旦旦地在法律文件中编造条款,而你的值班工程师发现没有快速关闭它的手段 —— 只能重新部署。

标志完成了它的工作。但标志是错误的保留产物。发布标志回答的是“这条新代码路径是否应该是可达的?”一旦大家达成共识,删除它就是正确的清理举动。而紧急开关(Kill switch)回答的是“上游模型今天表现正常吗?” —— 这个问题永远不会过期,因为上游模型永远在变化。将它们放在一起清理,就像把烟雾报警器当作建筑许可证一样,是范畴错误:建筑物建成后,许可证会被归档,但报警器的接线必须永远保持连接,因为由于它所监控的情况仍然可能发生。

这是潜藏在每个已发布、正常工作、已“完成”的 AI 功能中的故障模式:它被当作一个确定性功能来发布,使用与新结账按钮相同的标志流水线进行管控,现在它共享了结账按钮的生命周期 —— 包括由于常规工程整理而导致其关闭杠杆消失的那一部分。

正常运作的 AI 功能并非永久稳定

大多数团队从非 AI 软件中引入的思想模型是,一个功能一旦在生产环境中稳定运行,除非你更改它,否则它就会一直稳定。这个模型适用于你控制的代码。但它不适用于最关键的依赖项 —— 模型 —— 位于一个你不拥有的 API 之后,并以你察觉不到的节奏进行更新。

行业对供应商稳定性的追踪发现,当供应商更新底层权重时,大多数提示词与模型的组合都会出现性能退化(regress),而且其中很大一部分退化并非微小的偏差,而是百分之几的准确率下降。主流供应商大约以 12 到 18 个月的弃用周期循环其模型,而较小的快照更新则更为频繁。从你的应用程序角度来看,这些都不可作为部署事件被观察到。你的代码没变,你的提示词没变。如果你运行测试,它们在两个月前编写的案例上仍然会通过。提示词下的模型与你发布时的产物已不再相同,而该产物的故障面取决于供应商本周的决定。

危险的推论是,“我们已经运行了三个月没出事”并不能证明该功能是持久稳健的。这只能说明底层模型尚未向影响你特定业务面的方向偏移。将这种“安然无恙”视为“确认无误”,其逻辑就像将一个风平浪静的年份视为你不需要洪水保险的证据一样。

发布标志和紧急开关是不同的产物

大多数功能标志系统并不按用途区分标志,这正是它们被一起清理的原因。用于管控 UI 实验的标志、用于后端灰度发布的标志,以及用于禁用运行时危害的标志,在仪表盘上看起来完全一样。它们都有名称、发布比例和审计日志。发起“删除过期标志” PR 的清理机器人无法区分它们,审阅 PR 的工程师通常也分不清。

一种有用的准则是将这些视为具有不同生命周期和所有权的两类独立配置:

  • 发布标志(Launch flags) 是临时脚手架。它们的存在是为了支持灰度发布,一旦发布完成就变成了技术债,应当在功能达到 100% 且无需回滚后立即移除。它们的生命周期以周为单位。
  • 紧急开关(Kill switches) 是永久性的运行时配置。它们的存在是为了给操作人员提供一个能在分钟级以下生效的杠杆,用于控制那些由于外部依赖不可信而无法保持稳定的功能。它们的生命周期与功能本身的生命周期一致。移除紧急开关是一个深思熟虑的决定,而不是一次清理任务。

命名在这里至关重要。如果你发布的唯一产物是 enable_ai_summarizer_rollout,机器人最终会判定这个名称已经完成了使命。如果你发布两个产物 —— 用于发布的 enable_ai_summarizer_rollout 和用于持久杠杆的 ai_summarizer_disable(或 ai_summarizer_mode,其值包括 livefallbackoff)—— 机器人可以清理第一个而保留第二个。一些团队在标志系统本身中通过“永久(permanent)”标签来标记,从而使该标志免于过期清理;一些团队则将紧急开关完全放在不同的配置库中,远离功能标志 UI,理论是混合放置会导致同样的意外。

关键不在于你选择哪种机制。关键在于紧急开关需要是一个命名的、持久的、被独立拥有的东西 —— 而不是发布标志的一个临时副产品。

没有预设降级方案的紧急开关只是半个操纵杆

一个二进制开关式的紧急开关聊胜于无,但对于大多数 AI 功能来说,它的粒度并不合适。“摘要生成器坏了 —— 关掉它”会让值班工程师陷入尴尬境地:原本显示摘要的界面现在要么空无一物,要么显示通用错误,或者显示未经处理的原始文本,这取决于在没有模型响应时代码是如何处理的。“关闭”状态的影响范围从未被设计过,因为团队在发布该功能时默认它会永久开启。

如果操作者不必在凌晨两点临时构思降级方案,紧急开关才更有意义。在设计阶段就确定降级链,并将每一步都编码为紧急开关可以切换到的不同档位。一种常见的模式:

  • 正常运行 (Live) — 正常模型和提示词 (prompt)。
  • 降级 (Degrade) — 路由到更小、更便宜、更保守且拥有更久稳定记录的模型。上限更低,下限也更低。
  • 弃权 (Abstain) — 保持功能可见,但放宽拒绝回答的条件。摘要生成器返回“此文档无法提供摘要”,而不是冒着产生“自信的幻觉”(hallucination)的风险。
  • 静态化 (Static) — 将动态输出替换为预先编写的确定性响应、空状态或未经处理的底层内容(如原始文档文本、原始邮件等)。
  • 关闭 (Off) — 完全移除该界面。隐藏摘要卡片,跳过流水线中的 AI 步骤。

选择上线哪一个级别并不重要,重要的是所有这些级别都是预先确定的。值班工程师在处理故障时的任务是根据症状选择合适的级别 —— 自信的幻觉可能需要“弃权”或“静态化”;供应商的 5xx 错误风暴可能需要“降级” —— 而不是在用户受到影响时临时设计降级方案。降级方案是功能的一部分。一个没有降级方案的功能界面其实并没有真正完成。

这也迫使团队进行一场在最初发布时往往会被悄悄忽略的设计讨论。“当模型出错时,这个产品看起来是什么样的?”是一个难题,而简单的答案 —— “现在的模型已经够好了,以后再说吧” —— 正是造成凌晨两点窘境的根源。将紧急开关连接到一组真实的降级档位,会让团队在还有时间思考时就回答这个问题。

运维手册必须指明操纵杆,而不是仪表盘

大多数 AI 功能的故障处理手册(Runbook)都是从检测的角度编写的。它们告诉值班工程师该打开哪个仪表盘,观察哪个指标,哪个 Slack 频道可能已经在讨论这个问题。它们擅长确认问题的存在,但通常不擅长告诉操作者如何停止它。

AI 功能的运维手册条目应该在第一段回答三个问题:

  1. 操纵杆是什么? 准确命名它 —— 标签键(flag key)、配置路径、管理后台 URL 或 CLI 命令。不要说“LaunchDarkly 里的紧急开关”,而要指明具体的标识符。一个从未接触过该功能的工程师应该能够找到并操作它,而无需在代码库中进行 grep 搜索。
  2. 有哪些档位? 列出所有降级级别以及每个级别对应的用户端表现。操作者不应该去猜测“弃权(abstain)”对 UI 意味着什么。
  3. 谁有权拨动它? 要么赋予值班人员广泛的授权并信任他们,要么预先授权特定的档位(例如:降级无需升级审批;关闭则需要总监批准)。含糊不清的政策是最糟糕的情况:“我不确定我是否有权操作,所以我等着有人醒来。”

仪表盘仍然在手册中,但它们排在操纵杆之后。检测是采取行动的支持性证据;行动本身才是重点。以此类推编写的手册也会暴露自身的缺陷:如果你无法写出操纵杆是什么,说明操纵杆尚不存在,而这正是手册编写练习中得出的可执行结论。

另一个有用的实践是像测试备份一样测试紧急开关。选择一个空闲时段,在镜像了线上流量特征的测试环境中拨动开关,观察降级效果的呈现,然后再切换回来。一个季度一次就足够了。你想要发现的是操纵杆是否仍然有效 —— 配置键是否在重构中被重命名,降级代码路径是否仍然能编译通过,在当前的 UI 下静态响应是否仍然合理。一个一年没被拨动过的紧急开关,等于你根本没有这个开关。

将供应商视为实时依赖会改变研发规范

在具体的开关机制和手册背后,团队必须采纳一种姿态转变:模型供应商并非 SaaS 意义上的供应商关系,其可用性和行为并非由你可以通过起诉来解决的合同所约束。它是一个被集成到请求路径中的实时、不断变化的依赖项。适用于它的运营规范更接近于消费第三方数据源的规范 —— 那些可能在无预警情况下更改 Schema 的数据源。你不会在没有熔断器的情况下接入金融市场数据源;模型也理应获得同样的对待。

这重新定义了许多原本看起来像过度工程化的决定。准备第二个备选供应商并非偏执,而是一个降级策略。一个倾向于拒绝回答的弃权阈值并非能力的倒退,而是一个标定旋钮,当模型开始表现异常时,值班工程师可以将其调低。在每个请求中记录模型版本和快照标识符并非冗余,而是将行为异常与导致异常的上游变更关联起来的唯一方法。紧急开关是这种姿态中最显眼的部分,但这种姿态本身才是更大的承诺。

这种规范的前瞻性版本是:每一个 AI 功能在发布时都应该具备三样东西,而不是一样:功能本身、告诉你功能运行异常的指标,以及让你能在几秒钟内采取行动的操纵杆。如果第三样东西不在发布清单中,那么该功能就还没算真正发布 —— 它只是在运行而已。下次供应商悄悄更新快照时,这两种状态在凌晨两点的感受会截然不同。

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