4、特征版本控制:版本化策略、回滚机制与兼容性管理
特征版本控制,说白了就是给每个特征打上标签,记录它的「前世今生」。我见过太多团队,特征上线后出了问题,想回退却找不到旧版本,最后只能重跑全量数据,那叫一个痛苦。
这一章,我把自己踩过的坑和沉淀下来的方法,都摊开来讲。
4.1 特征版本化策略
版本化不是简单记个数字。你得想清楚:什么变了就算新版本?
我个人习惯,把版本号拆成三段:
| 版本段 | 含义 | 变更触发条件 |
|---|---|---|
| 主版本 | 特征语义或计算逻辑重大变更 | 业务口径调整、聚合方式重写 |
| 次版本 | 兼容性增强或参数调整 | 窗口期变化、缺失值策略修改 |
| 修订号 | Bug修复或性能优化 | 数据源字段名修正、缓存逻辑优化 |
举个例子:user_purchase_avg_7d.v2.1.3,一眼就能看出这是第2版主逻辑,第1次兼容性调整,第3次修bug。
核心原则:版本号一旦发布,不可修改。每次变更必须生成新版本,旧版本只读存档。
我在项目中遇到过一种情况:有人偷偷改了线上特征的计算脚本,没更新版本号。结果模型离线评估和线上效果对不上,排查了整整两天。后来我强制要求:版本号必须与代码仓库的tag绑定,改代码不改版本号,CI直接拒绝。
4.2 特征回滚机制
回滚不是「把文件换回去」那么简单。特征回滚涉及数据管道、存储、在线服务三个层面。
我建议按这个流程来:
- 触发回滚:监控告警或人工发现特征异常(比如分布偏移、空值率飙升)。
- 定位版本:从特征注册中心查到当前版本和上一个稳定版本。
- 数据管道回滚:将离线批处理或实时流任务切换到旧版本代码。
- 存储回滚:如果特征值已写入在线存储,需要重建旧版本数据。
- 服务切换:更新模型服务的特征获取逻辑,指向旧版本。
- 验证:对比新旧版本输出,确认回滚成功。
注意:回滚不是万能的。如果特征值已经用于训练并产出了模型,回滚特征不会自动回滚模型。我曾经吃过这个亏——特征回滚了,但模型还是用新特征训练的,线上线下不一致,A/B测试全乱套。
所以,我现在的做法是:特征版本和模型版本必须联动。每次特征变更,都生成一份「特征-模型兼容性清单」,回滚时一并检查。
4.3 特征兼容性管理
兼容性管理,是特征版本控制里最容易被忽视、但后果最严重的一环。你想想看,一个特征改了,下游十几个模型、几十个报表可能全崩。
我把兼容性分成三个维度:
| 兼容性类型 | 定义 | 破坏性变更示例 |
|---|---|---|
| 数据兼容性 | 新旧版本输出值的分布是否一致 | 聚合窗口从7天改为30天 |
| Schema兼容性 | 特征名称、类型、维度是否变化 | 字段类型从int改为float |
| 语义兼容性 | 特征的业务含义是否改变 | 「活跃用户」定义从7天登录改为3天登录 |
嗯,这里要注意:语义兼容性最难自动化检测。数据分布可以算PSI,Schema可以比对,但业务含义变了,机器看不出来。我建议每次版本发布前,必须由特征Owner在评审会上说明语义变更,并签字确认。
我的小技巧:在特征注册中心里加一个「兼容性检查清单」,每次发布新版本自动跑一遍。比如检查输出字段数是否变化、空值率是否在容忍范围内、均值方差是否显著漂移。跑不过就不让上线。
4.4 版本控制的核心架构
说了这么多,画张图帮你理清整体逻辑。
4.5 实战中的几个关键决策
最后,分享几个我在实战中反复纠结过的问题,以及我的最终选择。
- 版本号存哪里? 我建议存在特征注册中心,而不是特征值本身。特征值里带版本号,存储膨胀太厉害。
- 回滚要不要自动触发? 我个人习惯是半自动——系统检测到异常后发告警,人工确认后再执行回滚。全自动回滚风险太大,万一误判就麻烦了。
- 兼容性检查谁来写? 最好是特征Owner自己写,因为只有他最清楚特征的业务语义。平台团队可以提供工具框架,但检查逻辑必须业务方负责。
一句话总结:特征版本控制不是技术问题,是工程规范问题。工具再强,流程不落地,照样白搭。