Skip to content

필사 모드: MLOps 与模型生命周期管理:MLflow、DVC 与 LLMOps 完全指南

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

目录

  1. MLOps 概述与成熟度模型
  2. 实验追踪:MLflow 与 Weights and Biases
  3. 数据版本管理:DVC
  4. 特征存储
  5. 模型注册表
  6. ML 的 CI/CD
  7. 模型监控与漂移检测
  8. LLMOps
  9. 测验

MLOps 概述与成熟度模型

MLOps(Machine Learning Operations)是一套用于在生产环境中稳定运行 ML 系统的方法论、工具与文化的集合。它把 DevOps 的原则应用到 ML 工作流上,将模型从开发到部署、监控、再训练的整个生命周期自动化。

为什么需要 MLOps

有统计显示,95% 以上的 ML 项目都未能成功走到生产部署这一步。其原因大致如下:

  • 不可复现的实验:代码、数据、环境都没有做版本管理
  • 手动部署流程:速度慢,且容易出错
  • 缺乏监控:模型性能下降被发现得太晚
  • 团队孤岛:数据科学团队与工程团队之间存在脱节

MLOps 成熟度级别

Google 的 MLOps 成熟度模型将其划分为三个阶段。

Level 0:手动流程

所有流程都是手动的。数据科学家在 Jupyter Notebook 中做实验,再手动把结果部署出去。

特征说明
部署周期数月一次
自动化程度
可复现性
监控没有或靠手动

局限性:缺乏实验追踪、代码与数据版本不一致、部署出错、无法及时发现模型性能下降

Level 1:ML 流水线自动化

引入了 CT(Continuous Training,持续训练)。数据流水线与模型训练已经自动化,但 CI/CD 仍是手动的。

核心组成部分:

  • 自动化的数据校验流水线
  • 特征工程流水线
  • 模型训练流水线(Kubeflow Pipelines、Apache Airflow 等)
  • 自动化的模型性能评估
  • 引入特征存储
# Kubeflow Pipeline 示例 - Level 1 CT 流水线
import kfp
from kfp import dsl

@dsl.component
def data_validation_op(data_path: str) -> bool:
    import great_expectations as ge
    ds = ge.read_csv(data_path)
    results = ds.expect_column_values_to_not_be_null("target")
    return results["success"]

@dsl.component
def train_model_op(data_path: str, model_output: str):
    import mlflow
    import sklearn
    # 模型训练逻辑
    pass

@dsl.pipeline(name="CT Pipeline")
def ct_pipeline(data_path: str):
    validation = data_validation_op(data_path=data_path)
    with dsl.Condition(validation.output == True):
        train_model_op(data_path=data_path, model_output="/models/")

Level 2:CI/CD 流水线自动化

这是完全自动化的 MLOps 阶段。代码、数据、模型全部纳入版本管理,CI/CD/CT 完全自动化。

自动化触发条件:

  • 有新的训练数据到达(按计划或达到数据量阈值)
  • 检测到模型性能指标下降
  • 检测到数据漂移
  • 代码发生变更(新特征、算法改进)

Level 2 架构:

源代码变更或数据触发
CI 流水线(测试、构建)
CD 流水线(部署流水线)
CT 流水线(自动重训练)
模型评估 → 通过/不通过
注册进模型注册表
StagingProduction 晋升
监控与告警

实验追踪:MLflow 与 Weights and Biases

MLflow 完全指南

MLflow 是一个用于管理 ML 生命周期的开源平台,由 4 个核心组件构成。

MLflow Tracking

追踪实验的参数、指标与产出物(artifact)。

import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score
import numpy as np

# 配置 MLflow Tracking 服务器
mlflow.set_tracking_uri("http://mlflow-server:5000")
mlflow.set_experiment("fraud-detection-v2")

with mlflow.start_run(run_name="rf-baseline") as run:
    # 记录超参数
    params = {
        "n_estimators": 100,
        "max_depth": 10,
        "min_samples_split": 5,
        "random_state": 42
    }
    mlflow.log_params(params)

    # 训练模型
    model = RandomForestClassifier(**params)
    model.fit(X_train, y_train)

    # 记录指标
    y_pred = model.predict(X_test)
    metrics = {
        "accuracy": accuracy_score(y_test, y_pred),
        "f1_score": f1_score(y_test, y_pred, average="weighted"),
    }
    mlflow.log_metrics(metrics)

    # 模型自动记录(使用 sklearn autolog 时)
    # mlflow.sklearn.autolog()

    # 保存模型
    mlflow.sklearn.log_model(
        sk_model=model,
        artifact_path="model",
        registered_model_name="fraud-detection",
        input_example=X_test[:5],
        signature=mlflow.models.infer_signature(X_train, y_pred)
    )

    # 自定义产出物
    import matplotlib.pyplot as plt
    from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
    cm = confusion_matrix(y_test, y_pred)
    disp = ConfusionMatrixDisplay(confusion_matrix=cm)
    disp.plot()
    plt.savefig("confusion_matrix.png")
    mlflow.log_artifact("confusion_matrix.png")

    print(f"Run ID: {run.info.run_id}")
    print(f"Accuracy: {metrics['accuracy']:.4f}")

MLflow Autolog

按框架自动记录,把样板代码降到最少:

import mlflow

# 自动检测框架并记录
mlflow.autolog()

# PyTorch 专用 autolog
mlflow.pytorch.autolog(
    log_every_n_epoch=1,
    log_models=True,
    disable=False,
    exclusive=False,
    log_datasets=True
)

# XGBoost 专用 autolog
mlflow.xgboost.autolog(
    log_input_examples=True,
    log_model_signatures=True,
    log_models=True,
    log_datasets=True
)

MLflow Projects

打包可复现的 ML 项目:

# MLproject 文件
name: fraud-detection

conda_env: conda.yaml

entry_points:
  main:
    parameters:
      n_estimators: { type: int, default: 100 }
      max_depth: { type: int, default: 10 }
      data_path: { type: str, default: 'data/train.csv' }
    command: 'python train.py --n_estimators {n_estimators} --max_depth {max_depth} --data_path {data_path}'
  evaluate:
    parameters:
      model_uri: { type: str }
      test_data: { type: str }
    command: 'python evaluate.py --model_uri {model_uri} --test_data {test_data}'

Weights & Biases (W&B)

W&B 是一个提供实验追踪、可视化与超参数优化的 MLOps 平台。

import wandb
from wandb.integration.keras import WandbCallback

# 初始化 W&B
run = wandb.init(
    project="image-classification",
    config={
        "learning_rate": 0.001,
        "epochs": 50,
        "batch_size": 32,
        "architecture": "ResNet50"
    }
)

# 用 W&B Sweep 做超参数优化
sweep_config = {
    "method": "bayes",
    "metric": {"name": "val_accuracy", "goal": "maximize"},
    "parameters": {
        "learning_rate": {"min": 1e-5, "max": 1e-2},
        "batch_size": {"values": [16, 32, 64]},
        "dropout": {"min": 0.1, "max": 0.5}
    }
}
sweep_id = wandb.sweep(sweep_config, project="image-classification")
wandb.agent(sweep_id, function=train_fn, count=50)

数据版本管理:DVC

DVC(Data Version Control)是一款与 Git 配合、为大型数据集与 ML 流水线做版本管理的工具。

DVC 工作原理

DVC 不会把大文件直接存进 Git,而是只把 .dvc 元数据文件(指针)提交到 Git。实际的数据则存放在 S3、GCS、Azure Blob、SSH 等远程存储中。

# 初始化 DVC
git init
dvc init

# 配置远程存储(S3)
dvc remote add -d myremote s3://my-bucket/dvc-store
dvc remote modify myremote region us-east-1

# 添加数据
dvc add data/train.csv
git add data/train.csv.dvc .gitignore
git commit -m "Add training data v1"
dvc push

# 在其他环境中拉取数据
git pull
dvc pull

DVC Pipeline(dvc.yaml)

以声明式的方式定义可复现的 ML 流水线:

# dvc.yaml
stages:
  prepare:
    cmd: python src/prepare.py --input data/raw.csv --output data/processed/
    deps:
      - src/prepare.py
      - data/raw.csv
    outs:
      - data/processed/train.csv
      - data/processed/test.csv
    params:
      - prepare:
          - split_ratio
          - random_seed

  featurize:
    cmd: python src/featurize.py
    deps:
      - src/featurize.py
      - data/processed/train.csv
    outs:
      - data/features/train_features.pkl
    params:
      - featurize:
          - max_features
          - ngrams

  train:
    cmd: python src/train.py
    deps:
      - src/train.py
      - data/features/train_features.pkl
    outs:
      - models/model.pkl
    metrics:
      - reports/metrics.json:
          cache: false
    params:
      - train:
          - n_estimators
          - max_depth
          - random_seed

  evaluate:
    cmd: python src/evaluate.py
    deps:
      - src/evaluate.py
      - models/model.pkl
      - data/processed/test.csv
    metrics:
      - reports/eval_metrics.json:
          cache: false
    plots:
      - reports/plots/confusion_matrix.csv:
          cache: false
# params.yaml
prepare:
  split_ratio: 0.8
  random_seed: 42
featurize:
  max_features: 1000
  ngrams: 2
train:
  n_estimators: 100
  max_depth: 10
  random_seed: 42

DVC 实验管理

# 运行流水线
dvc repro

# 创建实验分支
dvc exp run --set-param train.n_estimators=200 --name exp-200-trees

# 比较实验
dvc exp show

# 输出指标表
dvc metrics show
dvc metrics diff

特征存储

特征存储(Feature Store)是用于集中存储、共享、服务 ML 特征的数据层。

为什么需要特征存储

  • 消除训练/服务偏差:保证训练与推理使用相同的特征转换逻辑
  • 特征复用:在团队之间共享特征,消除重复劳动
  • 低延迟服务:为在线预测提供实时特征查询
  • 特征一致性:维持批处理与实时流水线之间的一致性

在线存储 vs 离线存储

区分在线存储离线存储
目的实时推理服务模型训练
延迟数毫秒数秒到数分钟
存储介质Redis、DynamoDB、CassandraS3、BigQuery、Hive
数据量最新状态(当前值)全部历史
查询模式单条查询(基于 key)批量扫描

Feast 特征存储

# feature_repo/feature_store.yaml
project: fraud_detection
registry: data/registry.db
provider: local
online_store:
  type: redis
  connection_string: "localhost:6379"
offline_store:
  type: bigquery
  dataset: feast_dev
# feature_repo/features.py
from datetime import timedelta
from feast import Entity, Feature, FeatureView, FileSource, ValueType
from feast.types import Float32, Int64, String

# 定义实体
user = Entity(
    name="user_id",
    value_type=ValueType.INT64,
    description="用户 ID"
)

# 定义数据源
user_stats_source = FileSource(
    path="data/user_stats.parquet",
    timestamp_field="event_timestamp",
    created_timestamp_column="created"
)

# 定义特征视图
user_stats_fv = FeatureView(
    name="user_stats",
    entities=["user_id"],
    ttl=timedelta(days=7),
    features=[
        Feature(name="transaction_count_7d", dtype=Float32),
        Feature(name="avg_transaction_amount", dtype=Float32),
        Feature(name="days_since_last_login", dtype=Int64),
        Feature(name="account_age_days", dtype=Int64),
    ],
    online=True,
    source=user_stats_source,
    tags={"team": "fraud", "version": "v2"},
)
# 使用特征存储 - 训练
from feast import FeatureStore
import pandas as pd

store = FeatureStore(repo_path="feature_repo/")

# 获取训练数据(离线)
entity_df = pd.DataFrame({
    "user_id": [1001, 1002, 1003],
    "event_timestamp": pd.to_datetime(["2026-03-01", "2026-03-01", "2026-03-01"])
})

training_df = store.get_historical_features(
    entity_df=entity_df,
    features=[
        "user_stats:transaction_count_7d",
        "user_stats:avg_transaction_amount",
        "user_stats:days_since_last_login",
    ]
).to_df()

# 在线服务 - 实时特征查询
feature_vector = store.get_online_features(
    features=[
        "user_stats:transaction_count_7d",
        "user_stats:avg_transaction_amount",
    ],
    entity_rows=[{"user_id": 1001}]
).to_dict()

特征漂移检测

from evidently import ColumnMapping
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset

# 生成特征漂移报告
report = Report(metrics=[DataDriftPreset()])
report.run(
    reference_data=reference_features,
    current_data=current_features,
    column_mapping=ColumnMapping(target="label")
)
report.save_html("feature_drift_report.html")

# 查看漂移结果
results = report.as_dict()
drifted_features = [
    col for col, info in results["metrics"][0]["result"]["drift_by_columns"].items()
    if info["drift_detected"]
]
print(f"检测到漂移的特征: {drifted_features}")

模型注册表

MLflow Model Registry

MLflow Model Registry 是用于模型版本管理、阶段切换与团队协作的中央仓库。

import mlflow
from mlflow.tracking import MlflowClient

client = MlflowClient()

# 注册新模型
model_uri = f"runs:/{run_id}/model"
model_version = mlflow.register_model(
    model_uri=model_uri,
    name="fraud-detection"
)

# 添加模型说明
client.update_registered_model(
    name="fraud-detection",
    description="支付欺诈检测模型 - 基于 RandomForest"
)

client.update_model_version(
    name="fraud-detection",
    version=model_version.version,
    description=f"Accuracy: 0.956, F1: 0.943 on test set"
)

# 切换到 Staging
client.transition_model_version_stage(
    name="fraud-detection",
    version=model_version.version,
    stage="Staging",
    archive_existing_versions=False
)

# 加载并校验 Staging 模型
staging_model = mlflow.pyfunc.load_model(
    model_uri="models:/fraud-detection/Staging"
)
staging_preds = staging_model.predict(X_val)
staging_accuracy = accuracy_score(y_val, staging_preds)

# 校验通过后晋升到 Production
if staging_accuracy > 0.95:
    client.transition_model_version_stage(
        name="fraud-detection",
        version=model_version.version,
        stage="Production",
        archive_existing_versions=True  # 归档之前的 Production 版本
    )
    print(f"模型 v{model_version.version} 已晋升到 Production")

Hugging Face Hub 模型注册表

from huggingface_hub import HfApi, Repository
from transformers import AutoModelForSequenceClassification, AutoTokenizer

api = HfApi()

# 上传模型
api.upload_folder(
    folder_path="./fine-tuned-model",
    repo_id="myorg/sentiment-classifier-v2",
    repo_type="model",
)

# 更新模型卡片
api.upload_file(
    path_or_fileobj="README.md",
    path_in_repo="README.md",
    repo_id="myorg/sentiment-classifier-v2",
)

# 为特定版本打标签
api.create_tag(
    repo_id="myorg/sentiment-classifier-v2",
    tag="v2.1.0",
    tag_message="Improved accuracy on edge cases"
)

ML 的 CI/CD

GitHub Actions ML 流水线

# .github/workflows/ml-cicd.yml
name: ML CI/CD Pipeline

on:
  push:
    branches: [main, develop]
    paths:
      - 'src/**'
      - 'params.yaml'
      - 'dvc.yaml'
  schedule:
    - cron: '0 2 * * 1' # 每周一凌晨 2 点自动重训练

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run unit tests
        run: pytest tests/ -v --cov=src
      - name: Data validation
        run: python src/validate_data.py

  train-and-evaluate:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Configure DVC remote
        run: |
          dvc remote modify myremote access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
          dvc remote modify myremote secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      - name: Pull data
        run: dvc pull
      - name: Run DVC pipeline
        run: dvc repro
      - name: Log metrics to MLflow
        run: python src/log_results.py
        env:
          MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }}
      - name: Check model performance gate
        run: |
          python src/check_performance_gate.py \
            --min-accuracy 0.95 \
            --min-f1 0.93
      - name: Push results
        run: |
          dvc push
          git add reports/metrics.json dvc.lock
          git commit -m "chore: update metrics [skip ci]"
          git push

  deploy-staging:
    needs: train-and-evaluate
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Promote model to Staging
        run: python src/promote_model.py --stage Staging
      - name: Run integration tests
        run: pytest tests/integration/ -v
      - name: Deploy to staging endpoint
        run: kubectl apply -f k8s/staging/

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Promote model to Production
        run: python src/promote_model.py --stage Production
      - name: Blue/Green deployment
        run: ./scripts/blue_green_deploy.sh
      - name: Smoke tests
        run: pytest tests/smoke/ -v

自动重训练触发器

# src/check_retrain_trigger.py
import mlflow
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset

def should_retrain(
    current_data,
    reference_data,
    performance_threshold=0.92,
    drift_threshold=0.3
) -> tuple[bool, str]:
    """判断是否需要重训练"""

    # 1. 基于性能的触发条件
    current_metrics = get_current_metrics()
    if current_metrics["accuracy"] < performance_threshold:
        return True, f"性能下降: accuracy={current_metrics['accuracy']:.3f}"

    # 2. 数据漂移触发条件
    report = Report(metrics=[DataDriftPreset()])
    report.run(reference_data=reference_data, current_data=current_data)
    results = report.as_dict()
    drift_share = results["metrics"][0]["result"]["share_of_drifted_columns"]

    if drift_share > drift_threshold:
        return True, f"数据漂移: 检测到 {drift_share:.1%} 的特征发生漂移"

    return False, "无需重训练"

def get_current_metrics():
    client = mlflow.tracking.MlflowClient()
    prod_model = client.get_latest_versions("fraud-detection", stages=["Production"])[0]
    run = client.get_run(prod_model.run_id)
    return {
        "accuracy": float(run.data.metrics.get("accuracy", 0)),
        "f1_score": float(run.data.metrics.get("f1_score", 0))
    }

模型监控与漂移检测

数据漂移 vs 概念漂移

数据漂移(Data Drift):输入特征的分布发生变化。P(X) 变化,但 P(Y|X) 保持不变。例如:用户年龄分布变化、交易金额分布变化。

概念漂移(Concept Drift):输入与输出之间的关系发生变化。P(Y|X) 变化。例如:欺诈模式变化、用户偏好变化。

Evidently 漂移监控

import pandas as pd
from evidently.report import Report
from evidently.test_suite import TestSuite
from evidently import ColumnMapping
from evidently.metric_preset import (
    DataDriftPreset,
    DataQualityPreset,
    TargetDriftPreset,
    ClassificationPreset
)
from evidently.tests import (
    TestNumberOfDriftedColumns,
    TestShareOfDriftedColumns,
    TestColumnDrift
)

# 配置列映射
column_mapping = ColumnMapping(
    target="fraud_label",
    prediction="fraud_score",
    numerical_features=["amount", "transaction_count_7d", "avg_amount"],
    categorical_features=["merchant_category", "payment_method"]
)

# 综合漂移报告
report = Report(metrics=[
    DataDriftPreset(),
    DataQualityPreset(),
    TargetDriftPreset(),
    ClassificationPreset()
])
report.run(
    reference_data=reference_df,
    current_data=production_df,
    column_mapping=column_mapping
)
report.save_html("monitoring/report.html")

# 告警测试套件
test_suite = TestSuite(tests=[
    TestNumberOfDriftedColumns(lt=3),
    TestShareOfDriftedColumns(lt=0.3),
    TestColumnDrift(column_name="amount"),
    TestColumnDrift(column_name="transaction_count_7d"),
])
test_suite.run(
    reference_data=reference_df,
    current_data=production_df
)

# 测试失败时发送告警
results = test_suite.as_dict()
failed_tests = [t for t in results["tests"] if t["status"] == "FAIL"]
if failed_tests:
    send_alert(f"监控告警: {len(failed_tests)} 个测试失败")

Prometheus + Grafana 指标监控

# src/monitoring/metrics.py
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time

# 定义指标
prediction_counter = Counter(
    "model_predictions_total",
    "预测总数",
    ["model_version", "result"]
)
prediction_latency = Histogram(
    "model_prediction_latency_seconds",
    "预测延迟",
    buckets=[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0]
)
model_accuracy = Gauge(
    "model_accuracy_current",
    "当前模型准确率"
)
drift_score = Gauge(
    "feature_drift_score",
    "特征漂移分数",
    ["feature_name"]
)

# 在服务代码中更新指标
def predict_with_monitoring(features, model_version="v2.1"):
    start_time = time.time()
    prediction = model.predict(features)
    latency = time.time() - start_time

    prediction_latency.observe(latency)
    prediction_counter.labels(
        model_version=model_version,
        result="fraud" if prediction[0] == 1 else "normal"
    ).inc()

    return prediction

LLMOps

LLMOps 是面向大语言模型的开发、部署与运维,是 MLOps 的一种扩展。

LLM 流水线的特殊挑战

  • 非确定性输出:相同输入产生不同输出 → 评估变得复杂
  • 提示词敏感性:微小的改动会引发很大的性能差异
  • 高成本的 Fine-tuning:需要大量 GPU 资源
  • 幻觉(Hallucination):生成与事实不符的信息
  • 上下文长度管理:处理长上下文

使用 LangSmith 进行 LLM 追踪

from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langsmith import Client
import os

# LangSmith 配置
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "production-chatbot"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-api-key"

# 定义 LangChain 链(自动记录到 LangSmith 的追踪中)
llm = ChatOpenAI(model="gpt-4o", temperature=0.1)
prompt = ChatPromptTemplate.from_template(
    "你是一名友善的客户服务代表。\n\n问题: {question}\n\n回答:"
)
chain = prompt | llm

# 执行 - 自动追踪
response = chain.invoke({"question": "退款政策是怎样的?"})

# 用 LangSmith 客户端做评估
langsmith_client = Client()

# 创建数据集
dataset = langsmith_client.create_dataset(
    dataset_name="customer-service-eval",
    description="客户服务聊天机器人评估数据集"
)

# 添加评估样例
langsmith_client.create_examples(
    inputs=[{"question": "请告诉我退款政策"}],
    outputs=[{"answer": "购买后 30 天内可以退款。"}],
    dataset_id=dataset.id
)

# 执行自动评估
from langsmith.evaluation import evaluate, LangChainStringEvaluator

evaluators = [
    LangChainStringEvaluator("cot_qa"),
    LangChainStringEvaluator("labeled_criteria", config={
        "criteria": "correctness"
    })
]
results = evaluate(
    lambda x: chain.invoke(x),
    data=dataset.name,
    evaluators=evaluators,
    experiment_prefix="gpt4o-baseline"
)

提示词版本管理

# prompt_registry.py
import mlflow
from dataclasses import dataclass
from typing import Optional

@dataclass
class PromptVersion:
    template: str
    version: str
    description: str
    metrics: Optional[dict] = None

class PromptRegistry:
    def __init__(self, mlflow_uri: str):
        mlflow.set_tracking_uri(mlflow_uri)
        self.experiment_name = "prompt-versions"
        mlflow.set_experiment(self.experiment_name)

    def register_prompt(self, prompt: PromptVersion) -> str:
        with mlflow.start_run(run_name=f"prompt-{prompt.version}") as run:
            mlflow.log_param("version", prompt.version)
            mlflow.log_param("description", prompt.description)
            mlflow.log_text(prompt.template, "prompt_template.txt")
            if prompt.metrics:
                mlflow.log_metrics(prompt.metrics)
            return run.info.run_id

    def get_prompt(self, version: str) -> str:
        client = mlflow.tracking.MlflowClient()
        runs = client.search_runs(
            experiment_ids=[mlflow.get_experiment_by_name(self.experiment_name).experiment_id],
            filter_string=f"params.version = '{version}'"
        )
        if not runs:
            raise ValueError(f"未找到提示词版本 {version}")
        artifact_uri = runs[0].info.artifact_uri
        return mlflow.artifacts.load_text(f"{artifact_uri}/prompt_template.txt")

# 使用示例
registry = PromptRegistry("http://mlflow-server:5000")
registry.register_prompt(PromptVersion(
    template="你是一名 {role}。{context}\n\n问题: {question}\n回答:",
    version="v1.2.0",
    description="加入上下文的提示词改进版",
    metrics={"accuracy": 0.87, "hallucination_rate": 0.03}
))

LLM 微调流水线

# fine_tuning_pipeline.py
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    TrainingArguments,
    Trainer
)
from peft import LoraConfig, get_peft_model, TaskType
import mlflow

def fine_tune_with_lora(
    base_model: str,
    dataset_path: str,
    output_dir: str,
    lora_r: int = 16,
    lora_alpha: int = 32
):
    mlflow.set_experiment("llm-fine-tuning")

    with mlflow.start_run():
        # LoRA 配置
        lora_config = LoraConfig(
            task_type=TaskType.CAUSAL_LM,
            r=lora_r,
            lora_alpha=lora_alpha,
            target_modules=["q_proj", "v_proj"],
            lora_dropout=0.05,
            bias="none"
        )
        mlflow.log_params({
            "base_model": base_model,
            "lora_r": lora_r,
            "lora_alpha": lora_alpha
        })

        # 准备模型
        model = AutoModelForCausalLM.from_pretrained(base_model)
        model = get_peft_model(model, lora_config)
        model.print_trainable_parameters()

        # 训练配置
        training_args = TrainingArguments(
            output_dir=output_dir,
            num_train_epochs=3,
            per_device_train_batch_size=4,
            gradient_accumulation_steps=4,
            learning_rate=2e-4,
            fp16=True,
            report_to="mlflow"
        )

        trainer = Trainer(
            model=model,
            args=training_args,
            train_dataset=train_dataset,
        )
        trainer.train()

        # 保存并注册模型
        model.save_pretrained(output_dir)
        mlflow.transformers.log_model(
            transformers_model={"model": model, "tokenizer": tokenizer},
            artifact_path="fine-tuned-model",
            registered_model_name="customer-service-llm"
        )

测验

Q1. 请说明 MLOps Level 2 中 CT(Continuous Training)自动化的 4 种触发条件。

答案:数据触发、性能触发、漂移触发、计划触发

说明:

  1. 数据触发:当新的训练数据达到特定阈值(例如 10 万条)、或新的数据批次流入流水线时,自动重训练就会启动。
  2. 性能触发:当生产模型的准确率、F1 分数等指标跌破预先定义的阈值(例如 accuracy < 0.92)时触发。
  3. 漂移触发:当 Evidently 等工具检测到的数据漂移比例超过阈值(例如 30% 以上的特征出现漂移)时触发。
  4. 计划触发:根据业务需求做周期性重训练(例如每周一凌晨 2 点),以维持数据的新鲜度。
Q2. 请说明为什么特征存储要把在线存储和离线存储分开。

答案:是为了分别针对训练与推理各自不同的访问模式和性能要求做优化。

说明:

  • 离线存储(S3、BigQuery)用于模型训练。需要对数百万条历史数据做批量扫描,因此大批量处理能力和成本效率更重要,可以容忍较高的延迟(数秒到数分钟)。
  • 在线存储(Redis、DynamoDB)用于实时推理。需要在数毫秒内查到某个特定实体(用户 ID、商品 ID)的最新特征,因此针对低延迟的单条查询做了优化。
  • 如果不把两者分开,训练时的大批量扫描查询会干扰实时推理查询;反过来,为了满足实时性要求,训练成本又会大幅飙升。
Q3. 请说明数据漂移与概念漂移的差异,以及各自的检测方式。

答案:数据漂移是 P(X) 的变化,概念漂移是 P(Y|X) 的变化。

说明:

  • 数据漂移:输入特征的统计分布发生变化。可以用 Kolmogorov-Smirnov 检验、Population Stability Index(PSI)、JS Divergence 等方法检测,Evidently 的 DataDriftPreset 就是典型代表,即使没有标签也能检测。
  • 概念漂移:相同输入对应的正确输出发生了变化。例如在欺诈检测中,一旦出现新的欺诈模式,原有规则就会失效。这需要实际的标签,通过模型性能(accuracy、F1)的下降来检测。如果标签滞后到达,可以借助代理指标(proxy metric)。
Q4. 请说明 DVC 如何借助 Git 管理大型 ML 数据。

答案:把指针(元数据)文件存进 Git,实际数据则存放在远程存储中。

说明: DVC 不会把大文件(数据集、模型)直接存进 Git,而是生成扩展名为 .dvc 的元数据文件,由 Git 来追踪。这个文件里保存着实际数据的 MD5 哈希、大小、路径等信息。实际数据会通过 dvc push 上传到 S3、GCS、Azure Blob 等远程存储。在其他环境中,可以用 dvc pull 下载到完全相同版本的数据。Git 提交与 DVC 数据版本是 1:1 对应的,由此保证了实验的可复现性。

Q5. 请说明 MLflow Model Registry 中,从 Staging 晋升到 Production 之前需要校验的项目。

答案:性能校验、公平性校验、集成测试、性能(延迟)测试、数据 schema 兼容性

说明:

  1. 性能校验:在留出测试集或近期生产数据上,确认准确率、F1、AUC 等指标与现有 Production 模型相比持平或有所提升。
  2. 公平性校验:按切片检查特定人群、年龄段等维度上是否存在性能偏差。
  3. 集成测试:在实际服务环境(API、特征存储连接)中确认端到端预测能够正常工作。
  4. 性能(延迟)测试:通过负载测试确认平均响应时间及 P99 延迟是否满足 SLA。
  5. Schema 兼容性:确认输入特征 schema、输出格式是否与当前服务基础设施兼容。

현재 단락 (1/711)

1. [MLOps 概述与成熟度模型](#mlops-概述与成熟度模型)

작성 글자: 0원문 글자: 19,925작성 단락: 0/711