离线模型晋级项目与自测
项目目标
本项目不训练、不加载真实模型,不访问网络、Registry、Kubernetes 或云服务,也不需要密钥。它用 Python 标准库把四类容易混淆的 MLOps 证据串起来:
- 候选 manifest 绑定数据、标签、代码、环境、训练配置、模型摘要和签名;
- promotion gate 比较测试、整体指标、关键切片、延迟、大小和接口兼容性;
- 线上观察先绑定已通过的候选门指纹、固定制品与参考身份,再区分 shadow 和 Canary;
- 显式检查总样本、有标签样本、关键切片样本与标签覆盖,区分健康、证据不足、只有漂移、标签确认的质量退化和技术故障;
- 决策输出 release、阶段、策略版本、证据指纹、理由以及继续、调查、阻断 rollout 或回滚动作。
所有阈值只是本地教学策略,不是行业推荐值。真实阈值必须由业务损失、样本量、测量波动、风险容忍度和 SLO 共同确定。
项目文件
- promotion_gate.py:严格 schema 校验、晋级门、线上判定和 CLI。
- candidates.json:策略、Champion 基线和两个候选 manifest。
- observations.json:一个固定发布与五种 shadow/Canary 观察窗口。
- test_promotion_gate.py:52 个
unittest,覆盖重复 JSON key、非标准常量、坏输入、候选门绑定、阶段、样本分母、漂移、回滚和 CLI。
candidates.json 中的摘要是格式正确的教学占位符,不对应真实模型文件。项目验证的是证据组织与控制逻辑,不是模型质量。
运行环境
以下代码块按顺序从同时包含 docs/ 与 .website/ 的项目根目录开始运行;语法检查结束后会返回项目根目录:
Push-Location -LiteralPath 'docs\MLOps' # 进入项目目录;文末的 Pop-Location 会恢复工作目录。
python --version # 先确认当前环境实际调用的 Python 版本。脚本只使用 Python 3 标准库,不需要 pip install。若希望隔离解释器,请按照 目录中的环境路线 在 vault 外创建 .venv,再返回本目录运行。不要在知识库内创建 .venv。
第一步:检查候选晋级
证据完整且通过本地策略
python -B .\examples\promotion_gate.py candidate --id candidate-safe # 对完整候选运行离线晋级门;-B 不写入字节码缓存。
$LASTEXITCODE # 显示刚才 CLI 的稳定退出码,便于与文中 0/1/2 契约对照。预期 decision 为 promote,退出码为 0。输出同时包含 policy_version 和由候选、基线与策略生成的 evidence_fingerprint。
整体指标更高,但关键切片和数据测试失败
python -B .\examples\promotion_gate.py candidate --id candidate-regression # 运行含关键切片与数据失败的候选 fixture。
$LASTEXITCODE # 预期为 1,表示脚本正确完成并阻断晋级。预期 decision 为 block,退出码为 1。理由应包含 required test failed: data 和关键切片低于策略门槛。这个例子说明平均指标不能抵消关键切片或数据契约失败。
manifest 中的血缘
每个候选必须有:
- 不可变数据快照和标签版本;
- 代码提交、环境摘要和训练配置摘要;
- 模型制品摘要、格式、大小、输入/输出 schema;
- 明确的测试结果与整体、切片、延迟指标。
校验器拒绝未知字段、缺失字段、latest、非法 SHA-256、布尔型伪数值、非有限数和重复 ID。严格 schema 的代价是升级时需要显式迁移,收益是不会静默忽略拼错字段。
线上 fixture 还必须证明:部署的 candidate 已通过当前策略,promotion_evidence_fingerprint 与该次候选决策完全一致,模型 ID、制品摘要和观察参考身份互相匹配。指纹绑定能发现“评测后换制品”或“沿用旧策略结论”这类明显错绑;它不是签名,也不能证明声明的外部制品真实存在。
第二步:解释漂移和回滚
健康窗口
python -B .\examples\promotion_gate.py observe --id window-healthy # 评估证据充分的健康线上窗口。预期 action 为 continue,退出码为 0。
有输入漂移,但真值覆盖不足
python -B .\examples\promotion_gate.py observe --id window-drift-no-label # 输入漂移但标签证据不足,只应进入调查路径。
$LASTEXITCODE # 预期为 1,说明需要动作而非 Python 运行错误。预期 action 为 investigate,退出码为 1。输入漂移只是调查信号;标签覆盖不足时,脚本不会把它升级成“质量已下降”或“自动再训练”。
漂移伴随有标签的关键切片退化
python -B .\examples\promotion_gate.py observe --id window-quality-regression # 用有标签的关键切片退化 fixture 验证回滚优先级。预期 action 为 rollback_and_review_retraining。这里的顺序是先限制影响,再审查数据与标签是否适合产生新候选;名称中的 review_retraining 不代表自动上线。
技术故障
python -B .\examples\promotion_gate.py observe --id window-technical-failure # 单独模拟服务错误率/延迟故障,避免误归因为模型质量。错误率和 P95 延迟越过本地策略时,动作是 rollback_and_investigate。技术故障没有被错误解释成模型需要再训练。
Shadow 技术故障
python -B .\examples\promotion_gate.py observe --id window-shadow-technical-failure # 验证 shadow 阶段只能阻断扩量,不能冒充已回滚用户流量。预期动作为 block_rollout_and_investigate。Shadow 候选尚未承接用户决策,因此应阻断进入 Canary,而不是声称“已回滚用户流量”;若影子链路误接真实写操作,仍必须按事故处理副作用。
窗口用 sample_count、labeled_count 与 critical_labeled_count 表达分母。脚本由前两者计算标签覆盖率,同时要求绝对样本量、覆盖率和关键切片样本都过门;“80% 已标注”若只有几条样本,不能自动扩大。
一次查看所有教学场景
python -B .\examples\promotion_gate.py audit # 汇总全部离线 fixture,观察不同决策分支而不把它当单项发布门。audit 用于汇总样例,因此只要两个 JSON 契约有效就返回 0;其中仍会同时出现通过、阻断、调查和回滚结果。自动化系统不应只看 audit 的进程码,而应使用单候选或单窗口命令,或解析每条结构化决策。
运行测试
Push-Location .\examples # 进入源码与测试所在目录,简化模块发现。
$env:PYTHONDONTWRITEBYTECODE = "1" # 双重禁止字节码缓存,保持教学目录干净。
python -B -m unittest -q test_promotion_gate.py # 正常解释器下运行全部回归测试。
python -B -O -m unittest -q test_promotion_gate.py # 验证生产校验不依赖 -O 会移除的 bare assert。
python -B -W error -m unittest -q test_promotion_gate.py # 把警告提升为失败,捕获潜在兼容性问题。
Pop-Location # 离开 examples,恢复到项目目录。三种模式分别检查:
- 普通模式:52 个契约和行为测试;
-O:生产校验不依赖会被优化移除的普通assert;-W error:Python warning 被视为失败。
也可以在不生成 .pyc 的情况下做语法检查:
python -B -c "from pathlib import Path; [compile(p.read_text(encoding='utf-8'), str(p), 'exec') for p in map(Path, ['examples/promotion_gate.py', 'examples/test_promotion_gate.py'])]" # 只在内存编译两份 Python 文件,检查语法且不生成 .pyc。
Pop-Location # 恢复最初的项目根目录。从代码读懂控制边界
| 代码 | 工程含义 |
|---|---|
validate_candidates_fixture | manifest schema 与不可变血缘入口 |
evaluate_candidate | 候选和 Champion 在版本化策略下比较 |
validate_observations_fixture | 部署必须绑定已通过的候选门指纹,参考身份必须匹配固定制品 |
assess_observation | 阶段、样本分母、漂移、标签证据、质量与技术故障分开判断 |
evidence_fingerprint | 决策输入的稳定指纹,不是数字签名或授权 |
| CLI 退出码 | 0 继续/晋级,1 阻断或需动作,2 输入错误 |
evidence_fingerprint 只能检测同一组 JSON 证据是否变化,不能证明证据来源可信。真实系统还需要身份、不可变存储、签名或证明、访问控制和审计。
综合扩展任务
- 为两个命名关键切片分别设置策略,并避免把平均值当作唯一判据;
- 加入多次重复运行区间,而不是只比较单点指标;
- 为候选增加风险审批对象,绑定审核者、摘要、目标环境和有效期;
- 为 shadow 增加只读工具或模拟副作用不变量,再证明进入 Canary 前会阻断错误;
- 模拟部署别名在评测后被移动,验证固定摘要和候选门指纹仍能阻断错误制品;
- 把每条决策写入新建、不可覆盖的临时报告,并为重复执行设计幂等键;
- 为旧 schema 编写显式迁移器,而不是放宽校验静默接受。
掌握检查
- 能说明数据、标签、代码、环境、训练配置和制品摘要各自提供什么血缘。
- 能解释候选整体指标更高仍被阻断的原因。
- 能区分漂移、标签确认的质量退化和服务技术故障。
- 能说明为什么漂移不能直接触发自动再训练和上线。
- 能运行 52 个测试并解释
-O模式的意义。 - 能指出离线指纹、Registry 版本、审批和制品签名之间的差别。
- 能列出本项目尚未验证的真实平台能力。
项目边界
本项目没有验证真实 MLflow 3.14.0、Kubeflow、KServe、Kubernetes、云对象存储、容器、模型推理、线上流量或业务因果效果;也没有生成模型权重。固定参考值不是同期随机 control,不能把差异解释为发布的因果效果;更严格的并行 control 绑定见 LLMOps 离线发布门项目。接入真实平台时必须在独立环境锁定版本,以相同契约运行集成、权限、失败恢复和渐进发布测试。
参考资料
以下资料核对于 2026-07-21: