跳到主要内容

没人写的 AI 功能下线指南

· 阅读需 14 分钟
Tian Pan
Software Engineer

每个 AI 组织都有一个坟场。不是服务的坟场——服务会有操作手册(runbook)、弃用横幅、30 天的迁移窗口,以及在平台团队季度路线图上的位置。这个坟场是属于 功能 的:从未转正的智能摘要 Beta 版、两个大客户据此构建了工作流的自动分类器、演示效果极佳但在灰度发布后无人问津的 Agent 流程。弃用一个端点很容易。但与之关联的其他四个东西——提示词(prompt)、评测员(judge)、回归测试集(regression set)和事故记忆(incident memory)——才是真正需要一个季度才能搞定的,而且团队中没人写过这种手册,因为没人会因为下线某个功能而获得晋升。

这就是差距。大多数关于“模型弃用”的公开讨论都是针对供应商侧的下线:GPT-4o 在某天停止服务,Assistants API Beta 版在 8 月 26 日下线,DALL-E 3 在 5 月 12 日退休,而你的平台团队有一个通知期来进行迁移。这个问题有现成的手册,因为供应商发布了日期,迁移是被迫的,而且工作量可以塞进一个 Sprint 中。而“内部”版本——当你决定你构建的一个功能未能转正并必须将其撤除时——则没有任何这类强制因素。弃用日期由你说了算。迁移路径由你来构建。而且你必须退役的产物不是单个端点,而是一堆纠缠在一起的、与模型相关的资产,你的监控系统几乎感觉不到它们的存在。

接下来的内容是我希望在第一次不得不从生产环境中撤除 AI 功能时,有人能递给我的手册。它假设最简单的部分——下线面向用户的界面——是你已经知道如何操作的部分。它侧重于那四个默认不会被退役,并且在功能本该消失后的几个季度里持续产生财务成本、噪声和潜在风险的东西。

你真正要下线的五件事

在进行任何操作之前,先列出资产。传统的服务弃用只有一两个资产:端点,也许还有数据库表。一个 AI 功能至少有五个,而且它们有不同的所有者、不同的衰减率和不同的退役流程。

面向用户的界面。 按钮、UI 元素、客户接触到的 API 路由。这是产品经理和传播团队考虑的内容。这也是最简单的部分。你添加一个弃用头信息(header),贴一个横幅,设定一个日期,并遵守该日期。搞定。

提示词及其版本历史。 为该功能发布到生产环境的每个提示词现在都存在于某个地方——提示词注册中心、配置文件、功能旗标(feature flag)载荷、Helm chart 中的环境变量,或者某个程序员忘了重构的 Python 模块中的内联字符串。成熟的注册中心支持“已弃用”标签,在对新 SDK 获取隐藏版本的同时保留审计历史,这是正确的模式。但如果你没有注册中心——大多数运行已发布 AI 功能不到两年的团队都没有——你的提示词版本历史实际上分布在三个仓库、两个配置系统和一个 Slack 讨论串中。

评测员 (The judge)。 如果该功能有任何形式的 LLM-as-judge 评估架构,你至少构建了一个自定义的评测员,它有自己的评分准则、自己的校准日志,以及悄悄按自己节奏演进的提示词。评测员是最容易被遗弃的资产,因为它不直接面向用户,不出现在产品团队关注的任何仪表盘上,而且只有构建它的工程师知道它的存在。除非你关掉它,否则它会一直运行在定时任务中。

回归测试集。 每次功能出故障时添加的评估案例。每个案例都有其来源:它防止在特定事故中出现的特定失败模式再次发生。如果你整体删除评估集,你就会失去关于这些失败模式为何重要的组织记忆。如果你留下它,它会针对一个不再驱动该功能的模型永远运行下去,产生会被未来工程师误读的噪声。

事故记忆。 Slack 讨论串、复盘报告、提示词修改推导、“我们针对用户给出 DD/MM/YY 格式日期且模型假设为美国区域的情况进行了调整”的决定,这些仅作为提交信息(commit messages)和部落知识(tribal knowledge)存在。当负责该功能的工程师离职时,大多数团队都会默默地失去这些。

如果你的下线计划没有指明这五类资产中每一项的位置以及谁负责退役它们,那么你的下线计划只是一个沟通计划,而不是一个退役计划。

客户工作流问题(即使是 Beta 版)

Beta 版的前提是客户不应该依赖它。但现实是,任何具有非平庸输出质量的 AI 功能都会在几周内被嵌入到客户的工作流中,因为模型正在完成客户之前付钱请人做的工作,而那个人现在已被重新分配。到你决定该 Beta 版不予转正时,你前 50 名客户中的 3 个已经在 Zapier 流程中使用了它,一个已经针对你的私有 API 编写了脚本,而你的企业团队已经悄悄将其添加到两周前关闭的续约路演 PPT 中。

这种问题的礼貌供应商版本会带有至少 90 天的通知期、明确的替代模型和迁移指南。更难的内部版本是你可能没有替代品。功能没能转正正是因为未达到成功标准;引导客户去使用“新版本”的前提是有新版本,但通常并没有。

诚实的手册应该是这样的:在内部宣布下线之前,识别哪些客户工作流依赖该功能,每个工作流的次优选项是什么(有时“再次手动操作”就是答案),以及每个层级真正需要的通知期。在续约承诺中包含该功能的开发大客户需要的下线节奏,与免费层级的自助服务用户完全不同。将他们一视同仁会导致支持请求升级,从而将下线过程拖跨两个季度。

需要内化的不对称性:组织中所有其他弃用规则(数据库迁移、API 版本控制、移动应用强制升级)都有相应的流程。AI 功能之所以没有通过这些流程发布,是因为它们“只是一个 Beta 版”,所以还没形成这种肌肉记忆。现在就开始构建它,否则以后就要支付支持成本。

在不抹除演进血缘的情况下停用提示词 (Prompt)

关于清理提示词(Prompt),直觉做法是在代码库中全局搜索(grep)该提示词的标识符,删除相关引用,然后宣布大功告成。但这只完成了工作的一半,而且是错误的那一半。

正确的工作是:在管理该提示词的任何注册表中将其标记为弃用(deprecated),保留曾支撑过生产流量的每一个版本,并确保版本历史在至少一个完整的审计周期内是可查询的——通常是 12 个月,如果该功能涉及受监管领域,时间则需更长。这样做并非出于怀旧,而是因为:当 18 个月后,某个客户提出计费争议,或合规审查提出关于特定输出是如何生成的问题时,你需要能够重构产生该输出的提示词版本。如果你删除了它,你将无法回答这些问题,也就意味着你无法为输出结果辩护。

你应该删除的是:幽灵引用(ghost references)。包括:每一个将该提示词列为候选变体的配置文件;每一个控制该弃用版本流量的功能标志(Feature Flag);每一个断言该提示词仍能解析的 CI 测试;每一个针对每日评估集重新运行该提示词以捕捉漂移的定时任务(Cron job)。这些是会增加标志债务(Flag Debt)的孤儿配置——关于这方面的 SaaS 文献已经说得很清楚了:如果不进行审计,孤儿标志会以每季度翻倍的速度累积。而 AI 版本的标志债务问题更严重,因为每个“标志”都携带了 4KB 的提示词载荷,而且没人敢动它。

提示词停用的具体清单(按顺序):

  1. 在注册表中将与该功能相关的所有提示词版本标记为 deprecated。将生产标签(Production Label)设为空,使 SDK 在尝试调用时抛出异常,而不是静默回退。
  2. 在代码库中搜索对该提示词 ID 的硬编码引用,并将其替换为弃用错误,而非静默回退。静默回退会让提示词在没人知晓的代码路径中多存活半年。
  3. 移除功能标志以及控制该提示词流量的配置条目。添加一个 CI 检查,如果该提示词 ID 在任何新的代码变更中重新出现,则报错。
  4. 将提示词的提交历史、设计意图文档和事故引用移至长期归档库,而不是留在注册表的工作集中。注册表应反映当前在线的内容;归档库则反映过去的内容。

裁判模型与回归测试集:不同的处理决策

这两个资产看起来很像——它们都位于评估端,都按计划运行,都由 AI 工程团队所有。但它们的停用方式不同,将二者混为一谈是一个错误。

裁判模型 (The Judge) 通常应随功能一起停用。针对特定功能的失败模式调优过的裁判模型,在不重新校准的情况下很难泛化到后继功能上,而重新校准本质上就是创建一个新裁判。让旧裁判继续运行会产生噪声:它针对的功能已经不再使用,评估的模型输出基于一个已经不再发布的提示词,而它触发(或停止触发)的告警无法提供任何可操作的信息。把它关掉。归档评分准则(Rubric)、校准日志和提示词。如果出现了后继功能,下一位工程师无论如何都会重新构建裁判——旧的评分准则只是参考资料,而非可重用的基础设施。

回归测试集 (The Regression Set) 则不同。回归测试集中的单个案例是失败模式的单元测试——而失败模式的寿命比功能更长。一个因为模型在 DD/MM/YY 区域设置下产生日期幻觉而添加的测试案例,对于未来任何涉及日期解析的功能都有价值,而不仅仅是它最初所属的那个功能。正确的做法是迁移回归测试集,而不是停用它:根据它们防御的失败模式(而不是它们所属的功能)重新打上标签,将它们移动到共享的回归测试命名空间,并确保它们继续针对你其余功能所依赖的模型运行。

这种“重新打标”是很多团队会跳过的步骤。没有它,标签为“来自 [旧功能] 评估集”的回归案例会在六个月后被清理掉,因为没人能确定它们是否仍然相关,关于它们为何存在的组织记忆也会随之蒸发。而有了它,回归测试集将成为失败功能中少数能持续产生复利价值的遗产。

在工程师离职时保留事故记忆

最后一项资产是大多数团队真正会丢失的。构建该功能的工程师掌握着一些未被记录的知识:尝试过哪些提示词修改但没奏效;哪次裁判模型校准被哪次提示词变更搞乱了;哪次模型迁移破坏了哪种下游行为以及是如何修复的。当这位工程师调岗或离职,且该功能不久后被下线时,这些知识也会随之消失。

防御性举措是在功能下线之前将其记录下来,而不是下线期间。在停用日期前三周提交的“下线回顾”至少应涵盖:该功能原本要做什么,实际做了什么,为什么没能成功转化,关于失败模式学到了什么,哪些失败模式是通用的(应该保留)而哪些是特定的(可以归档),以及如果这位工程师有继任者,他会告诉继任者什么。

这份文档不是事后总结(Postmortem)。事后总结是关于事故的;而这是关于功能的。大多数组织没有这种模板,因为大多数组织还没有经历过足够多的 AI 功能停用来形成这种肌肉记忆。模板不需要太复杂——一页纸就够了——但它必须存在,并且必须是下线的必要产出物,而不是可有可无。

领导层需要意识到:AI 功能的下线并非只是使用了不同 SDK 的普通服务弃用。它们有自己的资产清单、自己的客户依赖动态、自己的保存难题。如果一个组织用通用的弃用流程来对待它们,就会不断丢失那些能捕捉下一个 Bug 的回归案例、能挺过下一次模型迁移的裁判校准经验,以及那些因为产出只是 30 行系统提示词差异而非 5000 行服务重写而被忽视的工程师经验。

“完成”到底意味着什么

只有满足以下所有条件,一个功能的下线(sunset)才算真正完成,而不仅仅是端点返回 410 状态码:

  • 面向用户的界面已被移除,并根据实际依赖关系(而非假设的依赖关系)向各级客户提供了适当的通知。
  • 每一版曾服务过生产流量的 Prompt 版本都已保存、标记为弃用、无法从任何实时代码路径访问,并可供审计查询。
  • 评估器(judge)已关闭,其评分标准(rubric)和校准日志已作为参考资料存档,并且没有任何自动化流程仍在针对它进行评分。
  • 回归测试集已拆分:特定于该功能的案例已连同出处(provenance)一起存档,通用失败模式案例已重新标记并迁移到该功能销毁后仍保留的共享回归集命名空间中。
  • 存在一份由功能工程师负责的下线回顾报告,涵盖了所学到的教训以及哪些成果应该在功能下线后继续保留。
  • 与该功能相关的所有 Feature Flag、配置条目和 CI 检查都已移除,并设有 CI 门禁防止它们被重新添加。

如果你无法针对上述每一项指出具体的交付物或 Commit,那么下线工作就没有完成。它处于一种会在接下来的几个季度里悄悄产生隐形成本、噪音和风险的状态,直到有人被迫回来收尾——通常是在更糟糕的情况下,缺乏上下文,且原始工程师已经离职。

编写这份剧本(playbook)——命名资产、定义退役步骤、要求进行回顾——的理由并不是说跳过任何单个功能的下线会造成灾难性的后果。而是因为现在的 AI 组织交付的功能如此之多,跳过这些步骤的累积成本是巨大的,而第一次就做对的边际成本却很小。你以这种方式进行的第一次下线会让你觉得大材小用。到第五次时,你会觉得这是唯一理智的运作方式。到第十次时,这种肌肉记忆已经建立,而在该剧本发布后入职的工程师会认为 AI 功能理应如此终结。最后这句话就是我们要达到的目标。

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