综合练习
这一课你将能做到
- 把 DVC、MLflow、Prefect、Docker、K8s、Prometheus、Evidently、SHAP 串成一条端到端流水线并完整交付
- 用「题目难度评分模型」走一遍从原始日志到漂移监控的全流程(比超时预测更完整的回归场景)
- 按 12 项毕业清单自查每个环节的可复现性与可运维性
为什么要学
前 11 课你分别摸过了每一块砖:数据管道、版本控制、实验跟踪、模型注册、编排调度、CI/CD、容器、云形态、监控、可解释性。但砖和房子之间隔着一次真实的施工——组件之间的接缝(注册中心地址传给容器、监控触发重训、解释报告进工单)才是 MLOps 工程师的真功夫。
本课是毕业设计:交付一个难度评分模型的完整流水线。选它而不是超时预测,因为它是回归任务 + 批量推理 + 全站落库,恰好把没覆盖到的组合补齐。人话:上一条流水线,你就有了面试里最值钱的素材——「我从 0 到 1 做过完整的 ML 交付」。
先建立图像
最终仓库形态:
mlops-lab/
├── data/ data/*.dvc # DVC 接管的数据集
├── src/ # make/clean/features/train/batch_score/
│ # serve/promote/drift_report/explain_*
├── flows/retrain.py # Prefect 每日编排
├── dvc.yaml params.yaml # 数据管道与参数
├── Dockerfile docker-compose.yml
├── k8s/timeout-api.yaml
├── .github/workflows/ml-ci.yml
└── reports/ # drift.html / shap_*.png(CI 产出物)
交付链路(一图总览全部 11 课):
判题日志 → dvc repro(DVC) → 训练(MLflow Tracking) → 门禁+注册(Registry)
→ 镜像(Docker) → 部署(compose/K8s) → 三层监控(Prometheus+Evidently)
→ 漂移/效果触发 → 编排重训(Prefect) → 解释报告(SHAP) → 持续闭环
跟着做
步骤 1:数据管道定稿(第 2/3 课组件)
dvc.yaml 保持第 3 课的三段式(make_data → clean → features),并补上训练段:
# dvc.yaml(新增 train 段)
stages:
# ...前三个 stage 同第 3 课...
train_difficulty:
cmd: python src/train_difficulty.py
deps:
- src/train_difficulty.py
- data/processed/problem_daily.parquet
params:
- train.random_state
outs:
- models/difficulty-v1.joblib
- metrics.json
metrics:
- metrics.json:
cache: false
# params.yaml(最终版)
features: { tle_window: 7 }
train: { random_state: 42, min_auc: 0.8, min_mae: 1.2 }
步骤 2:难度评分模型的训练与注册(第 4/5 课组件)
# src/train_difficulty.py
import yaml, json, mlflow
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split
from mlflow.models import infer_signature
mlflow.set_tracking_uri("http://127.0.0.1:5000")
p = yaml.safe_load(open("params.yaml", encoding="utf-8"))
df = pd.read_parquet("data/processed/problem_daily.parquet")
X = df[["tle_rate_7d", "avg_time", "submits"]]
y = df.groupby("problem_id")["tle_rate_7d"].transform(
lambda s: pd.cut(s.rank(pct=True), bins=5, labels=False) + 1)[:len(df)]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=p["train"]["random_state"])
with mlflow.start_run() as run:
mlflow.log_params({k: str(v) for k, v in p["train"].items()})
model = RandomForestRegressor(n_estimators=200, random_state=42)
model.fit(X_tr, y_tr)
mae = mean_absolute_error(y_te, model.predict(X_te))
json.dump({"mae": mae}, open("metrics.json", "w"))
mlflow.log_metric("mae", mae)
mlflow.sklearn.log_model(model, name="model",
signature=infer_signature(X_tr.head(5)),
input_example=X_tr.head(5))
mlflow.register_model(f"runs:/{run.info.run_id}/model", "difficulty_scorer")
mlflow server --backend-store-uri sqlite:///mlflow.db \
--artifacts-destination ./mlartifacts --port 5000 # 终端 1
export MLFLOW_TRACKING_URI=http://127.0.0.1:5000
dvc repro # 全管道一键重放
python src/promote.py stage $(python -c "import json;print(json.load(open('metrics.json')).get('version',1))") 2>/dev/null || true
python src/promote.py release 1 # 过门禁晋升 champion
步骤 3:容器化与部署(第 7/8 课组件)
docker build -t difficulty-api:v1 .
docker compose up -d --build # api + mlflow 本地栈
curl -X POST "http://127.0.0.1:8000/score?problem_id=1005"
# 生产:kubectl apply -f k8s/ && kubectl get hpa
服务端沿用第 5 课模式:启动时 load_model("models:/difficulty_scorer@champion"),晋升即发布,回滚即指针。
步骤 4:接入监控闭环(第 6/10 课组件)
# 每日流水线(Prefect 已部署):在 flows/retrain.py 的 gate 任务里追加两级门禁
# ① 数据门禁:python src/validate_data.py
# ② 漂移门禁:python src/drift_report.py → drift.json 中 drifted 非空则告警
# 服务侧:/metrics 已暴露 QPS/p99/预测分布,Grafana 面板建好后截图存进仓库 docs/
步骤 5:解释报告入档(第 11 课组件)
python src/explain_shap.py # reports/ 下产出 beeswarm 与 waterfall
# 把「难度分主要依据:7 日 TLE 率(贡献最大)、平均耗时、提交量」写进 docs/MODEL_CARD.md
# 模型卡:用途、数据范围、指标、已知局限(如新题型分布外)、申诉渠道
步骤 6:端到端验收
git clone <你的仓库> /tmp/verify && cd /tmp/verify
pip install -r requirements.txt && dvc pull && dvc repro # 陌生人能否一键复现?
python -m pytest --collect-only 2>/dev/null || true # 有测试则跑(可选)
docker compose up -d --build && curl localhost:8000/health # 能否一键起服务?
讲清楚要点
- 交付物是流水线,不是一次训练的产物:验收标准是「换个人、换台机器,clone 后三条命令复现全部结果」。做到这点,你已经超过多数把模型文件私藏在工位电脑上的项目。
- 接缝处的契约要显式:注册中心 URI 用环境变量传递;门禁阈值在 params.yaml;漂移判定读 drift.json 的固定字段。契约文档化在 docs/,比代码本身更长寿。
- 模型卡(Model Card)是最后一块拼图:用途、训练数据范围与时间窗、指标基线、已知失效模式、责任人与申诉入口。它把技术交付升级为业务可签约的交付。
- 演进路线而非一步到位:单机 compose 跑稳 → K8s 化 → 监控闭环 → CT 自动重训 → 平台化。每一步都保留回退开关,禁止「重写式升级」。
- 边缘概览:若要在客户端做离线提示(如 IDE 内超时预警),路径是把模型转 TFLite/ONNX 跑在端侧,配套课题是量化压缩与端云一致性校验——知道边界在哪即可,不必现在深入。
你可能会懵的地方
- 没有真实判题数据,这个毕业设计还有意义吗? 有。模拟数据的管道结构与真实完全同构,换数据源只动 make_dataset.py。面试讲项目时明确说「数据是模拟的,但管道是生产形态」,远比编造数据经历诚实且加分。
- 多个模型该拆成多个服务还是合进一个? 默认单体多路由(一个 FastAPI 挂 /predict /score 多个端点),共享鉴权、限流、监控基建;只有当负载特征差异大(批量重算 vs 毫秒在线)或团队边界需要独立发布时才拆。拆分是运维成本,不是荣誉。
- 练习仓库能直接进化成生产仓库吗? 路线是「继承而非重写」:补真实数据源、接入公司 SSO/密钥管理、K8s 迁移、审计与合规项。练习期养成的所有纪律(seed、tag、门禁、留痕)在生产期全部直接复用。
- 面试里怎么讲这条流水线? STAR 框架:S「判题站有 X 次提交/日,超时误判引发申诉」→ T「交付可复现的预测与评分流水线」→ A「按数据/训练/发布/监控四层实施,关键决策是XX」→ R「量化结果(离线指标 + 工单量下降)+ 已知局限」。重点讲决策与取舍,不是报工具名。
- 下一步深入什么方向? 按兴趣三选一:特征侧(Feast/实时特征一致性)、平台侧(Kubeflow/Argo、多租户 GPU 调度)、前沿侧(LLM 应用的评测与监控,方法论与本课程同构)。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 跟着命令复制粘贴不留仓库 | 练完即忘,无法验收 | 全程 Git 提交,每课一个 commit |
| 跳过监控「先上线再说」 | 第一天就在裸奔 | 监控与上线同一天交付 |
| 手动训练一次就把产物当最终交付 | 流水线形同虚设 | 验收标准 = dvc repro 可复现 |
| 练习仓库密钥写死在代码里 | 迁生产即泄漏事故 | 从第一天就用环境变量 |
| 面试只罗列工具名 | 显得只会搭积木 | 讲清每个组件解决的接缝问题与取舍 |
卡点急救
- 依赖版本互相冲突:以 requirements.txt 冻结为准重装 .venv;MLflow/sklearn 升级前先跑一遍 dvc repro 验证。
- 端口 5000/8000 被占用:
lsof -i:5000(Windows:netstat -ano | findstr :5000)找到进程杀掉,或服务统一改非默认端口并同步进配置。 - SQLite backend 并发写报 database is locked:多人共用 MLflow server 时换 PostgreSQL backend;单人练习降低并发触发即可。
面试常问
- 讲一个你从 0 到 1 落地的 ML 项目。 按 STAR 展开(见上文模板),必须包含四个要素:量化的问题背景、有取舍的架构决策(如为什么先批后在线)、门禁与监控闭环、可复现性证据(一键重放命令)。忌讳:背工具清单、虚构数据规模。
- 你的流水线最脆弱的环节是什么? 诚实答案通常是「特征口径的隐性变更」或「上游数据 schema 变更」——前者靠共享特征代码与回放比对,后者靠入口 schema 校验与漂移告警。能指出自己系统的软肋并给出缓解手段,是资深的标志。
- 如果只有一周时间,你先做监控还是先做自动重训? 先监控。没有监控的重训是盲目自动化(可能自动上线坏模型),且监控数据(漂移、效果曲线)正是重训触发条件的来源。顺序永远是:可观测 → 门禁 → 自动化。
自测三问
- 毕业验收的「三条命令」分别验证什么?
- 模型卡应包含哪些字段?它解决什么沟通问题?
- 监控、门禁、自动重训三者的正确建设顺序与理由?
小结一句话
MLOps 的毕业标准不是「模型训出来了」,而是「任何人 clone 仓库后三条命令复现全部结果,且线上有监控、漂移有闭环、解释有档案」。
延伸
- 本站 MLOps 路线图——回头对照知识全景,把已掌握的节点逐一标记。
- Made With ML——毕业后延续工程化训练的开源实战课程。
- 下一阶段进阶方向:特征商店(Feast)、LLM 应用运维(评测与监控同构复用)、多租户 GPU 平台化——本课程的方法论(可复现、门禁、闭环)全部适用。