跳到主要内容

固化功能陷阱:当你的 AI 差异化优势沦为维护累赘

· 阅读需 10 分钟
Tian Pan
Software Engineer

在 2022 年,一支团队花了三个月时间微调一个基于 BERT 的分类器,用于对客户支持工单进行分类。这是一次实实在在的胜利——准确率达到了 94%,而他们旧的基于规则的系统最高只有 70%。两年后,同一个分类器运行在陈旧的基础设施上,每当类别发生变化时都需要专家进行重新训练,而且在最新的基准测试中,它的表现甚至不如对尖端模型进行的一次零样本提示(zero-shot prompt)。没人敢碰它。开发它的工程师已经离职了。现在的团队担心弃用它会破坏某些功能。该功能就此被冻结了。

这就是“冻结功能陷阱”(frozen feature trap)。它是 AI 技术债中一种较为隐蔽的形式,且正在整个行业中蔓延。各支团队逐渐发现,曾经看起来像是护城河的东西,实际上是一个他们一直在往里砸钱的无底洞。

冻结功能是如何形成的

冻结功能最初并不是错误。它们始于对现实约束的理性解决方案。

当各团队在 2020–2022 年左右开始认真采用语言模型时,那些模型存在严重的局限性。上下文窗口非常小——4K token 很常见,8K 已经算慷慨了。推理能力不稳定。命名实体识别(NER)需要专门的模型。分类任务需要微调才能达到生产级的准确率。如果没有复杂的脚手架支持,多步规划就会分崩离析。

于是,工程师们构建了各种方案来填补这些空白:

  • 自定义分块策略,以将文档塞进微小的窗口中
  • 重排序流水线,以补偿检索质量的不足
  • 多跳提示链,以引导 GPT-3 完成复杂的推理
  • 为每个特定领域的标注任务微调分类模型

这些都是明智的工程决策。系统运行良好。团队顺利交付。

问题出在后来:模型在进步,但系统却止步不前。

尖端模型的上下文窗口从 4K 扩大到 8K、32K、128K,甚至 200K token 以上。推理能力得到了显著提升——在 2022 年需要复杂思维链脚手架的任务,到 2024 年只需一条指令就能可靠完成。模型内部的检索质量提升到了如此程度,以至于外部重排序器有时反而会主动降低结果质量。使用编写良好的提示词进行零样本分类,其表现开始匹配甚至超过微调后的专用模型。

然而,这些自定义系统依然存在。模型更新可以通过解决已不存在的问题,使周边 40% 的脚手架失效——但这些脚手架并不会自行消失。

冻结功能的解剖

冻结功能往往集中在几种反复出现的模式上。

自定义上下文管理是最常见的。各团队构建了复杂的压缩方案、滑动窗口逻辑和层级化摘要流水线,以绕过早已不复存在的上下文限制。这些系统不仅没被使用,反而会主动截断现代模型本可以直接处理的信息,以“遵守”一个在 18 个月前就已解除的约束,从而引入错误。

检索重排序流水线紧随其后。早期的 RAG 部署需要显式的交叉编码器(cross-encoder)重排序来修复检索质量,因为底层模型不擅长判断文档的相关性。其中一些重排序器至今仍在生产环境中运行,而底层模型的检索判断力已经提升到让重排序器的修正大多变成错误的程度。

基础模型已超越的领域微调。 一个在 2022 年基于你公司支持数据训练的微调模型,当时可能以显著优势击败了 GPT-3。而同一个模型在不做改变的情况下,现在运行速度更慢、单次推理成本更高,且表现不如当前尖端模型的一个系统提示词。微调模型的准确率优势已荡然无存,剩下的只有运维成本。

为弱推理机构建的多步提示链。 各团队构建了复杂的提示词分解逻辑,以补偿 GPT-3.5 容易在长推理链中丢失上下文的倾向。这种逻辑涉及产生多个顺序调用,每个调用处理一个狭窄的子任务,并由应用程序代码拼接输出。此后的模型已经能端到端地处理这些任务。但流水线依然存在,仍在维护中,并引入了原本可以通过单次调用消除的延迟和故障模式。

为什么团队无法放手

造成冻结功能的组织动力比技术因素更顽固。

可见性不对称。 构建一个新的 AI 功能会产生合并请求(PR)、演示日、Slack 公告和绩效评估亮点。而删除一个旧功能则什么都没有。移除那些“尚能运作”的脚手架并没有职业激励,即使“尚能运作”仅仅意味着“最近没崩溃,且没人衡量它是否依然必要”。

知识流失。 构建功能的工程师了解其边界情况、隐性依赖和故障模式。当这些工程师离开时——在 AI 工程师人才市场如此火热的背景下,这经常发生——他们的接班人继承了复杂性,却失去了背景信息。新团队不知道重排序流水线中哪些奇特的设计是承重的,哪些只是偶然。最稳妥的做法看起来就是维持现状。

运行安全的错觉。 一个在生产环境中运行的冻结功能是有记录可查的。它没有明显引发过事故。这让人觉得它是有效的证据,但实际上这只是说明没人仔细审视它。延迟退化、维护开销以及相对于新基准的准确率漂移不会触发报警,它们只是在默默地累积。

沉没成本思维。 团队投入了真正的努力并带着自豪感构建了这些功能。停用一个自定义微调模型感觉就像在承认最初的决定是错误的。其实不然——这在当时针对那时的约束是正确的。但这种心态让对话变得比实际需要的更困难。

识别从护城河到锚点的转变

最清晰的信号是对比基准。上一次你将自定义组件与基础模型在没有该组件的情况下的表现进行基准测试是什么时候?

如果答案是“在我们构建它时”,那么你就是在盲目飞行。模型的能力每季度都在复合增长。一个在 2018 年优于基础模型的功能,到 2026 年可能就变成了纯负资产——不仅是表现相当,而且是在主动降低结果质量。唯一的了解方法就是测试。

次要信号更容易被察觉:

  • 该组件需要专门的知识来维护,而团队中拥有这些知识的人越来越少。
  • 该功能的入职文档已过时或缺失。
  • 系统增加的延迟超出了如果由基础模型直接处理该任务所拥有的延迟预算。
  • RAG 质量即使在没有人更改代码的情况下也会随时间自然下降——因为数据管道没有得到维护,而基础模型的标准已经提高。
  • 该功能的错误率高于通过简单的 Prompt 方法在快速抽查中所实现的结果。

其中任何一个都值得调查。多个信号同时出现则强烈表明,你维护的是一个锚点,而不是在防守护城河。

退出准则:退役自定义组件的框架

在停用一个组件之前,你需要诚实地回答三个问题。

这种做法解决了模型的什么局限性? 请具体说明。“这个重排序器(re-ranker)补偿了嵌入模型(embedding model)检索准确性不足的问题”或者“这个分块器(chunker)处理了超过 8K 上下文窗口的文档”。如果你无法说出具体的局限性,或者该局限性现在的衡量标准是以年而非月为单位,那么这就是你的答案。

那个局限性还存在吗? 在你生产环境流量的代表性样本上测试当前的基础模型(不带该组件)。不要使用合成基准测试——要用你的实际数据。如果基础模型达到或超过了你组件的输出,那么保留该组件的理由就消失了。

真实的维护成本是多少? 计算全面成本:工程工时、基础设施、延迟代价,以及它为每个新团队成员带来的入职磨合成本。将其与使用更简单方法替换它的成本进行比较。一旦你计入隐藏成本,数学上的差距通常非常明显。

如果这三个问题都指向退役,那么路径就是记录结果(你的目标性能是什么以及为什么),运行一段两个系统同时运行的并行部署期,然后在有明确回滚计划的情况下进行切换。回滚计划是让沟通变得更容易的关键——它将“我们要删除一个有效的东西”转变为“我们要进行一个实验”。

防止堆积的规划节奏

当没有定期流程去质疑时,陈旧的功能就会不断堆积。

最有效的做法是对每个自定义 AI 组件进行季度审计——不是审计它在原始基准测试中的表现,而是审计它相对于基础模型今天在没有它的情况下能做的事情的表现。一名工程师,一天时间,一个新的基准测试。结果记录在组件健康文档中,一列为“依然合理”,另一列为“待弃用候选”。

这相当于软件工程中的依赖项审计。你不会发布一个运行在三年前库版本上的服务,而不去检查是否有安全补丁。同样的纪律也适用于针对可能不再适用的模型约束而构建的 AI 组件。

做法的另一半是在创建时进行文档记录。当你构建一个自定义组件来补偿特定的模型局限性时,请在代码中记录该局限性。注明它适用于哪个模型版本、哪个基准测试确定了这一需求,以及基础模型的什么改进会使该组件变得多余。这为未来的工程师提供了运行对比的背景信息——以及一个明确的触发条件。

底层原则

目标并不是要避免构建自定义 AI 功能。许多构建在基础模型能力之上的功能提供了真实且持久的价值——针对私有数据调整的特定领域检索流水线、校准到你的质量标准的评估框架、特定于你产品的工作流集成。这些都值得构建和维护。

目标是将随着底层模型改进而保持价值的功能,与最初为了补偿模型局限性而构建的功能区分开来。第一类功能的价值会不断复合。第二类则不会——它只会堆积成本。

“陈旧功能陷阱”就是团队无法做出这种区分时发生的情况。摆脱困境的方法是诚实地衡量、果断地退役,并且只构建当前一代模型无法完成的功能。

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