3. 数据与AI资产的版本控制

在Databricks的AI DataOps实践中,版本控制不是“把Notebook放进Git”这么简单。一个可发布的AI资产通常由五类对象共同构成:Notebook/代码、Delta表结构与数据契约、MLflow模型、特征表定义以及配置文件。它们的变化节奏不同、存储位置不同、可回滚程度也不同。如果只对代码做版本控制,而模型、特征和配置仍靠人工记录,发布时就无法回答“这次上线的模型对应哪份特征定义、哪套参数、哪版表结构”。因此,本节的核心目标是建立一套以Git为单一可信源、以不可变版本标识串联五类资产的管理方式。

一、五类资产分别“版本化什么”

首先要区分“文件版本”和“数据版本”。Git擅长管理文本,不擅长管理大规模数据文件。因此对Delta表,我们版本化的不是Parquet文件本身,而是表结构(Schema)、数据契约、分区与约束、以及指向具体数据快照的版本标识。对MLflow模型,版本化的是模型注册表中的模型版本号、Run ID、签名(Signature)与依赖环境,而不是模型权重文件本身。对特征表,版本化的是特征定义、实体主键、时间窗口、计算逻辑与物化表名。对配置文件,版本化的是YAML/JSON原文,包括集群规格、任务依赖、环境变量与阈值参数。

下表给出五类资产的版本化对象与Git中的承载形式,可作为团队约定的基础:

资产类型版本化对象Git承载形式不可变标识
Notebook/代码源码、函数、测试.py / .sql / .ipynbcommit SHA
Delta表Schema、契约、分区DDL / schema.yaml表版本号 + commit SHA
MLflow模型模型版本、签名、依赖model_ref.yaml模型版本号 + Run ID
特征表特征定义、窗口、主键feature_def.yaml特征表版本 + commit SHA
配置文件参数、集群、依赖config/*.yamlcommit SHA

二、分支模型:主干保护 + 短生命周期特性分支

推荐采用“main + release + feature”三层分支模型。main分支始终保持可发布状态,任何直接push都应被禁止,只能通过Pull Request合并。release分支对应具体发布批次,例如release/2024.11,用于冻结候选版本并打Tag。feature分支命名建议带工作项编号,如feature/AID-231-feature-store-v2,生命周期不超过3天,避免长期分叉导致合并冲突。

关键约束是:模型、特征、配置的变更必须与代码变更在同一个PR中提交。例如调整特征窗口从7天改为14天,不能只改Notebook,而应同时更新feature_def.yaml中的window_days字段,并在PR描述中说明对模型的影响。这样合并后的commit SHA就能唯一锚定“代码+特征+配置”的一致状态。

五类资产与Git版本锚定关系 Git 仓库 commit SHA 为唯一锚点 Notebook / 代码 .py / .sql / .ipynb Delta 表 schema.yaml / DDL MLflow 模型 model_ref.yaml 特征表 feature_def.yaml 配置文件 config/*.yaml 发布 Tag release/2024.11 同一 PR 内提交代码、特征、配置变更,合并后 commit SHA 锚定全部资产版本

三、代码评审流程:从“看代码”到“看资产一致性”

AI项目的评审不能只审逻辑正确性,还要审资产一致性。建议在PR模板中固定以下检查项:

  • Schema兼容性:Delta表字段是否新增/删除/改类型?删除字段属于破坏性变更,必须走单独评审并标注影响范围。
  • 特征一致性:Notebook中引用的特征名是否都在feature_def.yaml中声明?窗口、主键是否与定义一致?
  • 模型引用:model_ref.yaml中的模型版本是否已注册?签名输入是否与当前特征表匹配?
  • 配置差异:config/下是否有未说明的参数变更?阈值、集群规格变化是否附带影响评估?
  • 可回滚性:本次变更能否通过回退commit SHA恢复?是否涉及不可逆的数据迁移?

评审至少需要一名领域Owner和一名平台Owner。领域Owner判断业务逻辑与特征合理性,平台Owner判断Schema、模型注册与发布流程是否合规。对于破坏性变更,建议要求两名Owner同时批准。

四、实操示例:一次特征窗口调整的完整提交

假设我们要把用户活跃度特征的统计窗口从7天调整为14天。正确做法不是只改Notebook,而是同步修改三处文件并提交到同一分支:

# feature_def.yaml
feature_name: user_active_score
entity: user_id
window_days: 14          # 由 7 改为 14
aggregation: count
source_table: silver.user_events
materialized_table: gold.user_active_score_v2

# config/training.yaml
feature_table: gold.user_active_score_v2
model_name: user_churn_model
threshold: 0.62

# notebooks/train_churn.py
feature_df = spark.read.table("gold.user_active_score_v2")

提交后,PR描述中应写明:窗口变化会影响特征分布,需重新训练模型;materialized_table改为v2以避免覆盖旧特征表;训练配置中的feature_table同步指向v2。合并后,CI流水线会校验Schema、注册新模型版本,并把commit SHA写入模型Tag,例如git_commit=9f3c2a1。这样在发布时,只需查看模型版本上的Tag,就能反查到对应的特征定义与配置。

建议在MLflow模型版本上写入三个Tag:git_commit、feature_table_version、config_commit。这三个值构成发布时的“资产指纹”,任何一项对不上都不应进入生产。

五、Delta表与特征表的版本策略

Delta表本身提供时间旅行能力,可通过DESCRIBE HISTORY查看表版本。但表版本不等于代码版本,二者需要显式关联。推荐在schema.yaml中记录table_version字段,并在每次Schema变更时递增。特征表则建议采用“版本化表名”策略,例如gold.user_active_score_v1、_v2,避免直接修改原表导致下游模型输入漂移。旧版本保留至少一个发布周期,确认无引用后再归档。

不要用DROP TABLE或OVERWRITE直接替换生产特征表。正确做法是新建版本表、切换配置引用、观察一个周期后再下线旧表。否则一旦模型效果异常,将无法快速回退到旧特征。

六、发布Tag与资产清单

当release分支通过全部评审与CI后,打上语义化Tag,例如v2024.11.0。Tag对应的commit中应包含一份自动生成的release_manifest.yaml,列出本次发布涉及的Notebook、Delta表版本、MLflow模型版本、特征表版本与配置commit。这份清单是发布审计和回滚的依据,也是AI DataOps中“可追溯”的具体落地形式。

总结来说,Git管理的不只是代码,而是代码、表结构、模型引用、特征定义与配置的联合版本。分支模型保证变更隔离,评审流程保证资产一致,Tag与清单保证发布可追溯。三者结合,才能让AI资产在持续交付中保持可控、可回滚、可审计。