找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖
Claude、GPT 海外模型 API 接入Claude skills 从入门到精通 吴恩达亲授 AI Agent 核心技能2026 瞪哥公务员考试全攻略 行测申论一站式系统备考
Agent 文心智能蒸馏模型实战 90G 课程智泊 AI 大模型训练营 基于 LangChain 的 RAG 与提示工程实战构建企业级 AI 大脑:大模型微调与 RAG / Agent 全栈实战

6204

积分

1

好友

778

主题
发表于 2 小时前 | 查看: 5| 回复: 0

模型上线,并不意味着工作结束。

离线测试时 AUC、F1、MAE 都很漂亮,真正跑进生产环境几个月后,效果却可能一点点变差。更麻烦的是,代码没有报错、接口没有超时、服务也一直在线,模型甚至还在正常返回结果。

问题往往不在“模型坏了”,而在于模型面对的世界已经变了。

用户变了,业务规则变了,设备和渠道变了,数据采集方式变了,甚至“什么样的输入对应什么样的答案”也变了。模型仍然按照训练时学到的规律工作,但这些规律未必还适用于今天。

这类变化通常被统称为 Drift(漂移)。

理解漂移,真正重要的并不是记住几个统计检验,而是回答三个问题:

  • 到底是输入数据变了,还是输入与目标之间的关系变了?
  • 检测到分布变化,是否意味着模型性能一定下降?
  • 当真实标签不能及时拿到时,生产系统应该监控什么?

下面从这三个问题出发,把数据漂移、概念漂移、常见检测方法,以及 Python 中如何落地讲清楚。

01 先把“漂移”和“模型变差”分开

很多介绍会直接把漂移理解为“模型准确率随时间下降”,但严格来说,这两件事并不完全等价。

漂移描述的是数据或数据关系发生变化;模型性能下降描述的是这种变化最终对模型造成的结果。

一个很重要的现实是:

检测到数据漂移,不代表模型一定已经失效。

比如一个贷款模型使用年龄、收入、负债率等特征。某段时间用户年龄分布发生明显变化,但模型真正依赖的是收入和负债率,那么年龄漂移可能很明显,模型性能却几乎不受影响。

反过来也可能发生:几个输入特征的边际分布看起来都没有明显变化,但它们和目标变量之间的关系已经发生改变,模型性能仍然会下降。

因此,生产监控最好不要采用“发现某个特征漂移 → 立即重新训练”的简单逻辑,而是把漂移看成一个风险信号和排障线索。

如果已经能够拿到真实标签,应优先观察模型本身的性能指标;如果标签存在几天、几周甚至几个月的延迟,再通过输入漂移、预测漂移、数据质量等信号提前发现异常。

02 三种最值得区分的漂移

用概率分布来表示,会更容易看清它们之间的差别。

训练数据可以看成来自一个联合分布:$P(X, Y) = P(X) P(Y \mid X)$。其中:

  • $X$ 是输入特征;
  • $Y$ 是真实目标;
  • $P(X)$ 描述输入数据怎么分布;
  • $P(Y \mid X)$ 描述“什么样的输入更可能对应什么结果”。

生产环境发生变化,本质上就是这些分布中的某一部分发生了变化。

1. 数据漂移:输入的人群变了

数据漂移(Data Drift,也常称 Covariate Shift)通常指 $P(X)$ 发生变化,即:

$$P_{\text{train}}(X) \neq P_{\text{prod}}(X)$$

也就是生产环境里的输入分布,和训练时不一样了。

例如一个电商购买预测模型,训练时用户主要来自一二线城市;几个月后产品开始大规模下沉,新用户的年龄、地区、设备类型、消费能力都发生变化。

模型代码没有变,但它面对的数据已经不是原来那批数据。

常见原因包括:

  • 用户结构发生变化;
  • 新渠道或新地区上线;
  • 季节、节假日带来周期性变化;
  • 上游采集系统或埋点发生调整;
  • 传感器老化、设备更换;
  • 数据清洗和特征工程逻辑发生变化。

这里尤其要注意最后两类情况。

因为有些“漂移”其实不是业务世界变了,而是数据管道变了。比如某个字段从元改成分、缺失值填充策略发生变化、类别编码顺序被修改。这类问题通常应该先按数据质量故障处理,而不是急着重新训练模型。

2. 目标漂移:结果的基础比例变了

目标漂移(Target Drift / Prior Probability Shift)指 $P(Y)$ 发生变化:

$$P_{\text{train}}(Y) \neq P_{\text{prod}}(Y)$$

比如欺诈检测模型训练时,欺诈订单占 1%,某段时间突然上升到 5%;或者一个用户流失模型面对的整体流失率发生明显变化。

这类变化有时会直接影响模型阈值、校准结果和业务策略。

实际监控中,如果真实标签能较快返回,目标分布本身就是一个很值得观察的信号。

如果标签迟迟拿不到,也可以先观察预测结果的分布。预测漂移不能证明目标真的变了,但在没有标签时,它经常能提供一个比较及时的代理信号。

3. 概念漂移:规则本身变了

概念漂移(Concept Drift)更麻烦,它指的是 $P(Y \mid X)$ 发生变化:

$$P_{\text{train}}(Y \mid X) \neq P_{\text{prod}}(Y \mid X)$$

也就是输入和结果之间的关系发生了变化。

比如垃圾邮件识别模型过去发现“免费”“中奖”“点击链接”等模式很有效,但攻击者逐渐改变话术,旧特征仍然存在,垃圾邮件的表达方式却已经变了。

再比如信用风险模型中,同样的收入、负债和职业信息,在不同宏观经济周期里可能对应不同的违约概率。

这时并不是简单的“用户群变了”,而是模型当初学到的规律已经过时。

概念漂移通常还可以按变化过程分为:

  • 突变式漂移:某个时间点前后规律快速切换;
  • 渐进式漂移:新旧模式在一段时间内同时存在,新模式逐渐占主导;
  • 增量式漂移:数据关系持续、缓慢地朝一个方向变化;
  • 概念再现:旧模式在某个时间段重新出现,比如明显的季节性业务。

这也是为什么“固定每三个月重新训练一次”并不总是理想。不同业务的漂移速度完全不同,更合理的方法通常是根据性能和漂移信号决定什么时候进入调查、校准或重训练流程。

03 LLM 时代,漂移又多了一层

到了 大语言模型应用,事情会更复杂一些。

传统机器学习通常监控结构化特征,而 LLM 系统面对的是自然语言、Embedding、检索文档、Prompt、模型 API 和自动评估器。任意一层变化,都可能让最终输出质量下降。

其中比较值得监控的有四类。

输入和意图漂移

表面上看,用户输入仍然是一段文本,但用户真正提出的问题可能已经变了。

比如一个内部编码助手最初主要服务后端工程师,半年后数据分析人员大量进入,问题逐渐从 Java、Go 转向 SQL、Pandas 和数据处理。

平均文本长度可能几乎没变,但任务分布已经完全不同。

一种简单做法是给请求做意图分类,再监控不同意图所占比例。相比只统计字数、语言或请求量,这更接近实际业务变化。

Embedding 漂移

文本可以先转换为高维向量,再比较参考窗口和当前窗口中的 Embedding 分布。

这类方法对于 RAG、语义搜索、分类和推荐系统尤其有用,因为原始文本即使表面差异很大,也可能表达相同含义;反过来,相似的文字也可能对应完全不同的任务语义。

实践中可以使用距离度量、降维后的分布比较,或者训练一个二分类器判断某条样本来自“参考期”还是“当前期”。

如果分类器很容易分辨两批数据,通常意味着二者存在明显的整体分布差异。

检索语料漂移

RAG 系统还有一个传统模型不太明显的问题:知识库本身也在变化。

旧文档没有下线、新旧制度同时存在、索引更新不完整、Chunk 策略被修改,都可能导致检索结果和几个月前完全不同。

所以只监控用户输入还不够,还应该观察:

  • 检索命中文档的来源分布;
  • Top-K 结果的相关性;
  • 无结果率和低相关结果比例;
  • 新旧文档占比;
  • 关键知识的覆盖情况。

很多所谓“模型突然变笨”,最后排查出来其实是检索层发生了变化。

评估信号漂移

生成式任务很难像分类任务一样实时拿到标准答案,因此越来越多系统会使用规则评估、人工抽检或 LLM-as-a-Judge 来持续观察质量。

这里要区分两件事。

如果同类输入上的自动评分持续下降,它说明系统输出质量可能发生了变化;但如果评估模型、评分 Prompt 或评分标准本身被修改,那么变化也可能来自评估器,而不是被评估系统。

所以生产环境最好把“被测模型版本”和“评估器版本”同时记录下来,否则时间一长,很难判断分数究竟为什么变了。

04 真正的漂移监控,应该看哪些信号?

如果把生产模型看成一条完整链路,比较实用的监控顺序通常是:

数据质量 → 输入/预测分布 → 模型性能 → 漂移定位。

如果真实标签能够及时拿到,首先看业务真正关心的模型指标:

  • 分类:Precision、Recall、F1、ROC-AUC、PR-AUC、校准误差;
  • 回归:MAE、RMSE、MAPE 等;
  • 排序/推荐:NDCG、Recall@K、CTR 等;
  • LLM:任务成功率、事实正确性、拒答质量、人工评分等。

当这些指标下降时,再结合输入特征、目标、预测和分群的漂移去定位原因。

如果暂时没有标签,则可以先观察:

  • 缺失率、异常值、字段范围等数据质量指标;
  • 关键特征的单变量漂移;
  • 多变量联合漂移;
  • 预测分布变化;
  • 用户群、渠道、地区等重要分群的变化;
  • LLM 场景下的意图、Embedding、检索和自动评估信号。

这种方式比“每个字段都设一个报警器”更实用,因为后者很容易造成告警疲劳。

05 常见的漂移检测方法

不同检测方法回答的问题并不完全一样。实际使用时,不需要寻找一个“万能算法”,而应该根据特征类型、样本规模和监控目的选择。

K-S 检验:判断两个连续分布是否不同

Kolmogorov-Smirnov 两样本检验是一种常见的非参数检验。

它比较两个经验累积分布函数之间的最大差异,原假设是:

两组样本来自相同的连续分布。

如果 p-value 很小,就有理由拒绝这个假设。

Python 中可以直接使用 SciPy:

from scipy.stats import ks_2samp

result = ks_2samp(
    reference["age"].dropna(),
    current["age"].dropna()
)

print("KS statistic:", result.statistic)
print("p-value:", result.pvalue)

不过 p-value 不能简单理解成“漂移有多严重”。

样本量很大时,非常微小、业务上几乎没有意义的差异也可能得到很小的 p-value;样本很小时,又可能检测不到真实存在的变化。

因此生产中通常会同时看统计显著性和变化幅度,而不是只设一个 p < 0.05 就结束。

PSI:简单、直观,但阈值不是自然定律

Population Stability Index(PSI)会先把变量分桶,再比较参考数据和当前数据在各个桶中的占比差异。

它在信用评分和风控领域使用非常广,也常被用于模型监控。

常见经验规则会把 PSI 粗略解释为:

  • 小于 0.1:变化较小;
  • 0.1~0.2:出现一定变化;
  • 大于 0.2:变化比较明显。

但这些值本质上是经验阈值,不是适用于所有业务的数据定律。

分桶方式、样本量、变量本身的波动性,都会影响 PSI。因此更稳妥的做法是先用历史正常数据建立基线,再结合业务容忍度确定阈值。

Wasserstein 距离:直接衡量“搬动分布要走多远”

Wasserstein Distance 也叫 Earth Mover's Distance。

可以把两个分布想象成两堆土:要把第一堆土搬成第二堆土的形状,最少需要做多少“搬运工作”。

它非常适合连续数值变量,因为结果直接反映两个分布之间的距离,而且不像 p-value 那样随着样本量增大就天然变得更敏感。

JS 散度:适合比较概率分布

Jensen-Shannon Divergence 基于 KL Divergence,但它是对称的,而且不会像 KL 那样因为某些概率为 0 而直接变成无穷大。

对类别变量、离散分布,以及经过分桶后的数值变量都比较常用。

Page-Hinkley:更适合连续监控时间序列

前面几种方法通常是在比较“参考窗口”和“当前窗口”。

Page-Hinkley 则更接近在线变化检测:数据不断流入时,它持续累计偏离程度,用来发现序列均值发生了明显变化。

它适合监控:

  • 实时预测误差;
  • 传感器数据;
  • 连续业务指标;
  • 流式学习场景。

不过它对阈值比较敏感。阈值太低容易频繁误报,太高又可能错过真正变化,因此需要结合历史数据调参。

06 单变量没有漂移,不代表整体没有变化

生产中还有一个很容易忽略的问题:逐个特征检查,只能看到单变量漂移。

假设模型有两个特征 $X_1$ 和 $X_2$。

它们各自的分布都没有明显变化,但两者之间的相关关系发生了改变,那么模型看到的联合数据结构已经变了。

这时逐列 K-S、PSI 可能全部正常,但模型仍然处在训练时没有见过的数据区域。

一个常见的多变量检测思路是“域分类器”:

  1. 给参考数据标记为 0;
  2. 给当前数据标记为 1;
  3. 把两批数据混在一起训练一个二分类器;
  4. 看分类器能不能轻松区分两批数据。

如果分类器的区分能力接近随机,说明两批数据整体比较相似;如果区分能力很强,说明联合分布很可能已经发生变化。

对 Embedding 等高维数据,这种方法也很常见。

07 参考窗口怎么选,比算法本身更重要

很多漂移系统效果不好,问题并不出在 K-S、PSI 或 Wasserstein,而出在比较对象选错了。

通常需要两个窗口:

  • Reference Window:认为模型表现正常的一段基准数据;
  • Current Window:最近一段需要监控的数据。

Reference 不应该简单理解成“所有训练数据”。

比如电商业务有明显季节性,如果拿春节期间的数据和普通工作周直接比较,检测器几乎一定会报警,但这种变化本来就是正常业务周期。

实际可以采用几种策略:

  • 当前周 vs. 上周;
  • 当前月 vs. 去年同期;
  • 当前窗口 vs. 训练集中的对应季节;
  • 当前窗口 vs. 最近一段确认性能正常的数据;
  • 同时保留短期基线和长期基线。

窗口也不能过小,否则统计量波动太大;但过大又会把短暂异常平均掉。

所以真正成熟的漂移监控通常不会只设置一套窗口。

08 用 Evidently 快速生成数据漂移报告

如果不想自己维护每一套统计检验,可以使用开源工具 Evidently。

它可以对数值、类别、文本和 Embedding 数据做评估,并通过 DataDriftPreset 快速生成漂移报告。

下面继续使用 Adult 数据集构造一个简单示例。

1. 准备数据

import numpy as np
from sklearn import datasets

adult_data = datasets.fetch_openml(
    name="adult",
    version=2,
    as_frame=True
)

adult = adult_data.frame

# 人为构造两批分布不同的数据
adult_ref = adult[
    ~adult.education.isin(
        ["Some-college", "HS-grad", "Bachelors"]
    )
].copy()

adult_cur = adult[
    adult.education.isin(
        ["Some-college", "HS-grad", "Bachelors"]
    )
].copy()

# 再人为制造一部分缺失值
adult_cur.iloc[:2000, 3:5] = np.nan

这里的目的不是模拟真实业务,而是人为构造两批差异比较明显的数据,方便观察漂移报告。

2. 运行 DataDriftPreset

from evidently import Report
from evidently.presets import DataDriftPreset

report = Report(
    [DataDriftPreset()],
    include_tests=True
)

result = report.run(
    adult_cur,
    adult_ref
)

result

Evidently 会根据列类型和配置计算各列的漂移情况,并汇总整个数据集的漂移结果。

如果希望明确使用某一种方法,也可以在 DataDriftPreset 中指定,例如:

report = Report(
    [DataDriftPreset(method="psi")],
    include_tests=True
)

不过在真实项目里,不建议为了“统一”而强制所有字段都使用同一种方法。

连续数值、低基数类别、高基数类别、文本和 Embedding 的统计性质并不一样。更合理的做法通常是按数据类型选择方法,并为关键字段单独定义阈值。

3. 导出结果

result.save_html("data_drift_report.html")

json_result = result.json()

HTML 适合人工分析,JSON 则更适合接入监控平台、CI/CD 或告警系统。

但不要把“报告显示 Drift = True”直接等价为“自动重训”。

更稳妥的流程应该是:

检测到异常
   ↓
确认数据质量
   ↓
确认漂移发生在哪些关键特征 / 分群
   ↓
检查模型性能或获取标签
   ↓
判断是否需要调阈值、重新校准、更新数据或重新训练

漂移检测的价值,更多在于尽早发现生产环境正在离开模型熟悉的区域,而不是替代对模型性能的判断。

09 生产环境里,什么时候应该重新训练?

“漂移了就重训”听起来很合理,但实际往往太粗糙。

重新训练至少应该同时考虑三件事:

第一,性能是否真的下降。

如果指标稳定,仅仅有一个不重要特征发生漂移,重训的收益可能很小。

第二,漂移是否影响模型真正依赖的区域。

关键特征、高重要性特征、核心用户群发生变化,比边缘字段的小幅波动更值得关注。

第三,新数据是否已经足够代表新的环境。

漂移刚发生几天就立即重训,可能只是把一次短期活动、节假日或异常事件写进模型。

因此,更合理的生产策略通常是:

  • 漂移作为预警;
  • 性能作为核心判断;
  • 业务影响决定优先级;
  • 重训只是修复手段之一。

有时候真正需要做的是修复上游数据、重新校准阈值、更新特征工程、调整 RAG 索引,甚至只是等待短期波动结束。

10 写在最后

模型在训练完成的那一刻,学习到的其实只是过去某个时间窗口里的世界。

真正困难的是上线以后。

数据持续变化、用户持续变化、业务持续变化,而模型不会因为环境变化自动知道自己的认知已经过时。

所以漂移监控真正要解决的,并不是“有没有一个统计量超过阈值”,而是建立一套持续判断机制:

现在的数据还像训练时吗?模型还可靠吗?如果不可靠,问题到底发生在哪一层?

把这三个问题持续回答好,模型监控才真正从“看几个指标”进入生产级 MLOps。

参考资料

  1. Jie Lu, Anjin Liu, Fan Dong, et al. Learning under Concept Drift: A Review.
  2. SciPy Documentation: scipy.stats.ks_2samp.
  3. Evidently Documentation / Open-source ML Observability Course: Data Drift、Embedding Drift 与 Drift Detection Methods.
  4. Evidently GitHub: DataDriftPreset 当前 API 与示例。
  5. NannyML Documentation: Covariate Shift、Concept Drift 与模型性能监控。



上一篇:顺序消息如何不乱序?RocketMQ与Kafka有序消费实战
下一篇:MCHA内存中心架构:多智能体RL较A100最高加速2457倍,主存访问占比仅5.4%
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-9-25 03:10 , Processed in 0.815173 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表