你的 AI 功能可靠性受限于无人负责的上游 ETL 流水线
AI 功能拥有仪表板。提示词(Prompt)有版本控制。评估套件(Eval suite)有轮值表。然后是一个写于 2022 年的上游定时任务(cron job),由一个在两次重组前就退出了分析部门的团队负责,它生成了构建你的检索索引所需的 CSV 文件。那个定时任务没有 SLA。那个 CSV 没有 Schema 契约。负责它的团队根本不知道它正在为一个 AI 功能提供数据。当它发生变化时——它一定会变——AI 团队将花费三周时间去调试一个完全没有出错的提示词。
你即将追踪的 AI 质量回退几乎从来不是 AI 问题。它是一个穿着 AI 外衣的 ETL 问题。需要落实的规范是两者之间的衔接点——契约、血缘(lineage)、新鲜度信号、成对的轮值——而没有将其正式化的团队,所交付的 AI 功能的可靠性将受限于公司里最不受待见的定时任务。
隐形的依赖
AI 功能是一个流水线。这条流水线的最后 20%—— 提示词、模型、评估框架(eval harness)——是工程投资集中的地方,也是每次复盘开始的地方。而前 80%——摄取任务、规范化步骤、去重处理、每日快照、从第三个上游系统合并进来的列——是在任何人在会议中提到“Agent”这个词之前就构建好的。它由那些认为自己拥有的是一个面向分析用户的数仓的人负责。他们不知道下游有一个 LLM。
这种不可见性就是故障模式。数据团队像对待 Tableau 后端一样对待他们的流水线:重命名一个列是常规清理,每日运行延迟到隔天运行是可接受的降级,Schema 的“改进”只是在 Slack 的分析频道发个通知。这些沟通都没有传达到 AI 团队,因为 AI 团队从未被注册为消费者。没有任何契约规定嵌入(embedding)流水线依赖于 customer_segment 是字符串而不是整数。没有任何消费者注册表会在下游 RAG 索引读取数据团队的输出时向他们发送告警。
与此同时,AI 团队将上游视为绝对真理。他们的评估是针对过去某个时间点拍摄的数据快照进行的。他们的检索之所以有效,是因为列都在他们预期的位置。他们的微调是在他们假设平稳的分布上训练的。每一个假设都是一份从未签署的契约,而上游团队今天下午就可以随意违反其中的每一项,因为没有人告诉过他们自己曾经达成过任何协议。
被记录为“模型回退”的故障模式
这种模式重复得如此频繁,以至于几乎成了一种典型。AI 团队注意到每周评估中的质量下降了四个百分点。延迟 正常,错误率正常,模型版本没变,提示词也没变。他们花了一周时间调整提示词。又花了一周尝试不同的分块(chunking)策略。第三周对检索流水线进行消融实验。最终,有人将一批糟糕的输出追溯到某个特定文档,找到了该文档,查看了它最后一次摄取的时间,发现上游流水线在两周前开始过滤掉某一类记录,原因是进行了一次“无害的清理”,删除了标记为“内部”的记录。而该 AI 功能正依赖于这些记录。
第二种模式:上游流水线开始输出精度不同的列。以前是以毫秒为单位的时间戳,现在变成了秒。检索层原本使用时间戳来解决相关性排名的冲突。突然间,冲突解决变得不可预测,同样的查询在不同的日子返回不同的文档,评估套件开始出现波动。模型没问题。检索没问题。数据差了一个小数点。
第三种:由于缩减成本的计划降低了非关键任务的优先级,上游流水线的运行频率从每小时降到了每天。RAG 索引现在有长达 24 小时的滞后。AI 功能开始用落后一天的数据回答关于“最新”信息的问题。没有任何地方触发告警——流水线运行成功,索引更新成功,模型响应成功——唯一的信号是客户满意度在一个季度内悄然下降。
第四种:上游流水线由于有人更改了数仓列类型,静默地将一个长字符串字段截断为 256 个字符。RAG 索引现在包含的分块(chunk)在每个长文档的后半部分都缺失了。检索仍然返回分块。只是分块是不完整的。模型基于不完整的上下文进行回答。幻觉率上升。团队归咎于模型。
在所有这些案例中,AI 团队的前三个假设都是关于模型的。这些假设没有一个是正确的。第四个假设最终指向了数据。数据几乎总是答案,而几乎从来不是人们首先寻找的地方。
必须存在的契约层
上游流水线与 AI 功能之间的缝隙必须成为一等产物,而这个产物就是数据契约(data contract)。契约不是一条 Slack 消息,也不是一个 Wiki 页面;它是一个带有版本控制、可由机器校验的规范,定义了模式(schema)、新鲜度、完整性以及生产方承诺且消费方依赖的变更策略。
模式子句定义了 AI 功能读取的每一个列,包括其类型、允许值及语义。重命名列属于违约行为。拓宽类型属于违约行为。新增一个可为空(nullable)的列是可以的;但将一个非空列转变为可为空列则属于违约。生产方在不升级契约版本的情况下不能进行这些更改,而升级契约版本会触发对每个已注册消费方的通知。
新鲜度子句定义了允许 AI 功能看到的数据的最大账龄。“至少每四小时更新一次”是一个新鲜度 SLA。违反该条款的流水线即为违约流水线,无论文件内部的记录是否依然正确。消费方被允许——甚至是要求——拒绝提供超过新鲜度阈值的上下文,并将陈旧性展示给用户,而不是默默地基于旧数据提供回答。
完整性子句定义了必须到达的预期记录百分比。“至少 98% 的源记录必须出现在输出中,缺失的 2% 归因于已记录的过滤器”是一个完整性 SLA。即使产生了输出,仅达到 95% 阈值的运行也违反了契约。静默截断是上游引起的 AI 退化中最常见的情况,而完整性子句正是为了捕捉这类问题而存在的。
变更策略子句定义了生产方如何演进契约。“不向后兼容的更改需要提前 30 天通知并升级契约版本;小的增项可以随时进行”就是一种变更 策略。如果没有它,每一次更改都会变成通过 Slack 解决的协调问题,而这种协调最终会失败,因为 AI 团队通常不在正确的频道里。
血缘、所有权与配对轮值
仅有契约是不够的。契约是一个承诺;血缘(lineage)则是谁向谁承诺了什么的地图。数据血缘图将喂给 AI 功能的每一个字节追踪回产生它的上游流水线,并将拥有该流水线的团队确定为责任方。如果没有血缘,当功能出现退化时,AI 团队甚至无法识别是谁的流水线出了问题;他们必须取证式地重建从“糟糕的输出”到“糟糕的列”到“糟糕的任务”再到“糟糕的团队”的路径,而每一步都要花费数小时。
血缘将 AI 功能变成了一个已注册且可见的消费者。上游团队可以在仪表盘上看到,他们的 daily_customer_facts 表供应给三个下游消费者,其中之一就是 AI 支持智能体。上游团队现在在社交和协作上都能意识到,“无害的清理”并非真的无害。消费者不再是隐形的了。
下一步是配对轮值(paired on-call)。当 AI 功能退化且根因在上游时,上游团队会被呼叫。这并非是对 AI 团队呼叫的补充——而是当根因在他们那边时,直接呼叫他们。AI 团队针对质量退化的运维手册(runbook)以“检查上游契约状态”开始,如果违反了契约,则将报警路由给上游负责人。这听起来很官僚,直到这种事发生过两次,上游团队内化了这样一个认知:他们的定时任务(cron job)有一个通过报警(而非仅仅通过仪表盘)来“付费”的客户。行为转变会非常迅速。
具备新鲜度感知的检索策略是消费端的补充。检索层知道它所提供的每份文档的时间戳,知道源数据的新鲜度 SLA,并拒绝提供已过时的上下文。它被允许向用户展示陈旧性——“我掌握的关于此项的最新数据是 36 小时前的;我可以据此回答,但如果你需要更新的数据请告知”——而不是默默地降级。这把静默失败转化成了明显的失败,而明显的失败是团队唯一能采取行动的失败类型。
架构层面的实现
AI 功能是两条流水线缝合在一起的产物,而这种缝合处在几乎所有组织中都是不可见的。上游流水线是 2010 年代的产物:为分析而建,由数据团队拥有,像基础设施一样运行。下游功能是 2020 年代的产物:为推理而建,由 AI 团队拥有,像产品一样运行。两者之间的缝隙是 2025 年的问题,在这两个十年中都没有人负责,而没有将其正式化的团队所交付的 AI 功能,其可靠性上限将由上游链路中插桩(instrumentation)最少的环节决定。
需要落地的纪律并不光鲜。它是具有约束力的数据契约,是标明所有权的血缘图,是穿透检索层传播的新鲜度信号,以及遵循数据流向而非组织架构图的轮值机制。这些都不是科研。这全都是介于一个可运行的 AI 演示(demo)与一个可运行的 AI 产品之间那些乏味的工程细节。能够大规模交付可靠 AI 功能的团队,是那些当上游数据团队提议进行“小幅清理”时会将契约摆在台面上,以及当上游团队忘记契约存在时会触发报警轮值的团队。
下次你的 AI 功能退化时,不要先忙着调整提示词(prompt)。先去读读血缘图,问问这周上游发生了什么变化。答案几乎总是在那里。而你原本打算花三周时间重写的提示词,几乎肯定是在准确执行它该做的任务——只不过是基于那些悄悄变得不再符合你评估套件假设的数据。
- https://www.acceldata.io/blog/how-data-contracts-guarantee-pipeline-reliability-data-quality-slas
- https://www.montecarlodata.com/blog-implementing-data-contracts-in-the-data-warehouse/
- https://www.informationweek.com/data-management/nobody-told-legal-about-your-rag-pipeline-why-that-s-a-problem
- https://datahub.com/blog/data-lineage-for-ml/
- https://atlan.com/know/context-drift-detection/
- https://www.dataworldbank.net/2026/04/26/context-decay-orchestration-drift-and-the-rise-of-silent-failures-in-ai-systems/
- https://www.montecarlodata.com/blog-what-is-data-observability/
- https://platformengineering.org/blog/the-agent-reliability-score-what-your-ai-platform-must-guarantee-before-agents-go-live
- https://streamkap.com/resources-and-guides/real-time-data-pipelines-genai
- https://dzone.com/articles/why-embedding-pipelines-break-at-scale
- https://www.telm.ai/blog/data-quality-for-vector-databases/
- https://materialize.com/blog/your-vector-search-is-probably-broken/
- https://www.getdbt.com/blog/data-slas-best-practices
