CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
MLOps 入门/课时/综合练习
RawBlame
课时目录12 节

MLOps 入门

  1. 01MLOps 是什么
  2. 02数据工程基础
  3. 03版本控制与 DVC
  4. 04训练与实验跟踪
  5. 05MLflow 与血缘
  6. 06编排与调度
  7. 07CI/CD for ML
  8. 08容器化部署
  9. 09云原生 ML
  10. 10监控与可观测
  11. 11可解释 AI
  12. 12综合练习

综合练习

DVC→MLflow→Docker→Metrics 端到端。

40 分钟

综合练习

这一课你将能做到

  1. 把 DVC、MLflow、Prefect、Docker、K8s、Prometheus、Evidently、SHAP 串成一条端到端流水线并完整交付
  2. 用「题目难度评分模型」走一遍从原始日志到漂移监控的全流程(比超时预测更完整的回归场景)
  3. 按 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  # 能否一键起服务?

讲清楚要点

  1. 交付物是流水线,不是一次训练的产物:验收标准是「换个人、换台机器,clone 后三条命令复现全部结果」。做到这点,你已经超过多数把模型文件私藏在工位电脑上的项目。
  2. 接缝处的契约要显式:注册中心 URI 用环境变量传递;门禁阈值在 params.yaml;漂移判定读 drift.json 的固定字段。契约文档化在 docs/,比代码本身更长寿。
  3. 模型卡(Model Card)是最后一块拼图:用途、训练数据范围与时间窗、指标基线、已知失效模式、责任人与申诉入口。它把技术交付升级为业务可签约的交付。
  4. 演进路线而非一步到位:单机 compose 跑稳 → K8s 化 → 监控闭环 → CT 自动重训 → 平台化。每一步都保留回退开关,禁止「重写式升级」。
  5. 边缘概览:若要在客户端做离线提示(如 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 可复现
练习仓库密钥写死在代码里迁生产即泄漏事故从第一天就用环境变量
面试只罗列工具名显得只会搭积木讲清每个组件解决的接缝问题与取舍

卡点急救

  1. 依赖版本互相冲突:以 requirements.txt 冻结为准重装 .venv;MLflow/sklearn 升级前先跑一遍 dvc repro 验证。
  2. 端口 5000/8000 被占用:lsof -i:5000(Windows: netstat -ano | findstr :5000)找到进程杀掉,或服务统一改非默认端口并同步进配置。
  3. SQLite backend 并发写报 database is locked:多人共用 MLflow server 时换 PostgreSQL backend;单人练习降低并发触发即可。

面试常问

  • 讲一个你从 0 到 1 落地的 ML 项目。 按 STAR 展开(见上文模板),必须包含四个要素:量化的问题背景、有取舍的架构决策(如为什么先批后在线)、门禁与监控闭环、可复现性证据(一键重放命令)。忌讳:背工具清单、虚构数据规模。
  • 你的流水线最脆弱的环节是什么? 诚实答案通常是「特征口径的隐性变更」或「上游数据 schema 变更」——前者靠共享特征代码与回放比对,后者靠入口 schema 校验与漂移告警。能指出自己系统的软肋并给出缓解手段,是资深的标志。
  • 如果只有一周时间,你先做监控还是先做自动重训? 先监控。没有监控的重训是盲目自动化(可能自动上线坏模型),且监控数据(漂移、效果曲线)正是重训触发条件的来源。顺序永远是:可观测 → 门禁 → 自动化。

自测三问

  1. 毕业验收的「三条命令」分别验证什么?
  2. 模型卡应包含哪些字段?它解决什么沟通问题?
  3. 监控、门禁、自动重训三者的正确建设顺序与理由?

小结一句话

MLOps 的毕业标准不是「模型训出来了」,而是「任何人 clone 仓库后三条命令复现全部结果,且线上有监控、漂移有闭环、解释有档案」。

延伸

  • 本站 MLOps 路线图——回头对照知识全景,把已掌握的节点逐一标记。
  • Made With ML——毕业后延续工程化训练的开源实战课程。
  • 下一阶段进阶方向:特征商店(Feast)、LLM 应用运维(评测与监控同构复用)、多租户 GPU 平台化——本课程的方法论(可复现、门禁、闭环)全部适用。
加载本节练习…
← 上一课可解释 AI