iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
AI Engineering

從 4,343 筆職缺到 AI Engineer:MLOps × GenAI Engineering 雙主軸實戰系列 第 10

Day 10:實驗追蹤與模型註冊—MLflow 與 champion/challenger

  • 分享至 

  • xImage
  •  

昨天資料有了版本。今天處理另外兩根柱子:這次訓練用了什麼設定、跑出什麼結果、產出的模型在哪裡

這是 Day 08 診斷表第 3、5 題的內容,也是導入成本最低、痛感解除最快,投資報酬率最高的一天。

今天要解決的問題

三個熟悉的場景:

場景一:Excel 實驗紀錄。 有人在共用 Excel 上記「模型 A:lr=0.01,AUC=0.87」。兩週後有人問「那個 0.89 的是怎麼跑出來的」——沒人記得,因為那次忘了記。

場景二:模型檔案考古學。 資料夾裡躺著 model.pklmodel_v2.pklmodel_final.pklmodel_final_真的.pkl沒有人知道線上跑的是哪一個。

場景三:回滾要改程式碼。 新模型上線後效果不好要回滾,發現服務程式碼裡寫死了 joblib.load("model_v3.pkl"),要改程式碼、重建映像、重新部署——在事故當下,這三個步驟每一步都是風險。

📊 職缺訊號

「模型版本與實驗管理」在 MLOps 職缺中只佔 7.2%,是六項任務中最低的。但別誤讀這個數字——它低,是因為多數團隊還沒走到這一步(Day 08 的成熟度分布),不是因為不重要。在面試中,能講清楚 champion/challenger 機制的候選人,通常會被判定為「有實際上線經驗」。


一、現象:實驗追蹤要記什麼

一次訓練要記錄的東西,可以整理成四類:

MLflow 的四個元件與資料流

圖 10-1:實驗追蹤系統的元件與資料流(示意架構)。Tracking 記錄過程、Registry 管理產出、Artifacts 存放檔案,服務端只透過 Registry 取用模型。

類別 內容 為什麼要記
參數(params) 學習率、樹的數量、資料版本 tag、seed 重現的必要條件
指標(metrics) AUC、F1、loss 曲線、各切片的表現 比較與門檻判斷
產出(artifacts) 模型檔、混淆矩陣圖、特徵重要度、metrics.json 交付與稽核
來源(tags) Git commit、資料雜湊、執行者、環境 出事時的追溯線索

第四類最常被忽略,卻最重要。 半年後模型出問題,你要能回答「這個模型是誰、用哪個 commit、哪份資料、什麼時候訓練出來的」——這四個問題答不出來,就無法判斷責任與修復方向。

二、原理:Registry 讓模型與程式碼解耦

模型註冊表(Model Registry)解決的是場景三:回滾不該需要改程式碼。

image

圖 10-2:模型註冊表的別名機制(示意流程)。服務端只認 @champion 這個別名,晉升與回滾都是「移動別名」,不需要改程式碼或重新部署。

這個設計的價值在於把「哪個版本是現行版」的決策,從程式碼移到了註冊表。事故當下,回滾是一行指令,而不是一次部署。

三、動手:完整的實驗追蹤流程

3.1 啟動 MLflow 並記錄實驗

uv add mlflow scikit-learn
mlflow server --host 127.0.0.1 --port 5000    # UI 在 http://127.0.0.1:5000
"""train_with_mlflow.py —— 把 Day 06 的訓練腳本升級成可追溯的版本。"""
import json, subprocess, hashlib
from pathlib import Path

import mlflow, mlflow.sklearn
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score, f1_score
from sklearn.model_selection import train_test_split

mlflow.set_tracking_uri("http://127.0.0.1:5000")
mlflow.set_experiment("fraud-detection")

SEED = 42
params = {"n_estimators": 300, "max_depth": 12, "random_state": SEED}

df = pd.read_csv("data/train.csv")
X, y = df.drop(columns=["label"]), df["label"]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2,
                                          random_state=SEED, stratify=y)

with mlflow.start_run(run_name="rf-baseline") as run:
    # 1) 參數
    mlflow.log_params(params)

    # 2) 來源標籤——出事時的追溯線索,這幾行最容易被省略,也最不該省
    mlflow.set_tags({
        "git_commit": subprocess.check_output(
            ["git", "rev-parse", "--short", "HEAD"]).decode().strip(),
        "data_sha256": hashlib.sha256(
            Path("data/train.csv").read_bytes()).hexdigest()[:16],
        "data_version": "data-v2",          # 對應 Day 09 的 Git tag
    })

    model = RandomForestClassifier(**params).fit(X_tr, y_tr)

    # 3) 指標——除了整體,一定要記「切片」指標
    proba = model.predict_proba(X_te)[:, 1]
    mlflow.log_metrics({
        "auc": roc_auc_score(y_te, proba),
        "f1": f1_score(y_te, (proba > 0.5).astype(int)),
    })
    for ch in X_te["channel"].unique():          # 分通路看,避免整體好、局部爛
        m = X_te["channel"] == ch
        mlflow.log_metric(f"auc_{ch}", roc_auc_score(y_te[m], proba[m]))

    # 4) 模型——帶簽章(輸入輸出 schema),部署時可自動驗證
    mlflow.sklearn.log_model(
        model, name="model",
        signature=mlflow.models.infer_signature(X_te, proba),
        input_example=X_te.head(3),
    )
    print("run_id:", run.info.run_id)

💡 切片指標是資深工程師的標記

只看整體 AUC 會漏掉「整體 0.89、但 LINE 通路只有 0.62」這種問題。上線後被抱怨的往往就是那個弱勢切片。多寫三行 for 迴圈,省下三個月後的一場會議。

3.2 註冊與晉升

from mlflow import MlflowClient
client = MlflowClient()

# 通過品質門檻後才註冊(門檻邏輯見 Day 11)
mv = mlflow.register_model(f"runs:/{run_id}/model", "fraud-model")

# 新版本先當挑戰者
client.set_registered_model_alias("fraud-model", "challenger", mv.version)

# 金絲雀驗證通過後晉升為冠軍——這一行就是「上線」
client.set_registered_model_alias("fraud-model", "champion", mv.version)

3.3 服務端:只認別名

import mlflow.pyfunc

# 服務端永遠這樣寫,程式碼裡不出現版本號
model = mlflow.pyfunc.load_model("models:/fraud-model@champion")
predictions = model.predict(features_df)

回滾就是把別名指回舊版本,一行指令、不需重新部署:

mlflow models set-alias -m fraud-model --alias champion --version 6

四、取捨:工具選型與常見誤區

工具 適合 注意
MLflow 開源、自架、要完整的 Registry 需自己維運(DB+物件儲存);生態最完整
Weights & Biases 深度學習、重視視覺化與協作 SaaS 為主,資料出境需評估(Day 27)
雲端託管(SageMaker/Vertex/Azure ML) 已在該雲上、要少維運 綁定該雲,遷移成本高
TensorBoard 只需看訓練曲線 不是實驗管理,沒有 Registry

三個常見誤區:

  1. 只記指標,不記來源。 半年後無法追溯,等於沒記。
  2. 把 Registry 當檔案櫃用。 註冊了一堆版本卻沒有別名機制,服務端還是寫死版本號——那只是換個地方放檔案。
  3. 在 Registry 裡管提示詞(prompt)。 生成式 AI 團隊常犯。提示的版本管理需求不同(變更頻繁、要 A/B、要與評測集綁定),Day 26 會談專門的做法。

4.1 一個容易被忽略的價值:實驗紀錄是團隊的記憶

實驗追蹤的價值,多數人只看到「方便比較」。但它真正的複利在團隊記憶

具體場景:新人加入團隊,問「為什麼我們用 XGBoost 不用深度學習」。如果有完整的實驗紀錄,答案是打開 UI 給他看——半年前試過三種深度模型,指標沒有更好但訓練時間多五倍,紀錄都在。如果沒有紀錄,答案就變成「以前試過,好像不行」,於是新人半信半疑,三個月後又試了一次同樣的東西。

沒有實驗紀錄的團隊,會週期性地重複同樣的失敗。 這個成本不會出現在任何報表上,但它是真實存在的。

同樣的道理適用於「為什麼這個超參數是這個值」。有紀錄時,答案是「搜過 40 組,這組最好,證據在此」;沒紀錄時,答案是「一直都是這樣」——而後者正是技術債的標準語法。

4.2 從傳統 ML 到生成式 AI,這一層怎麼變

給主軸二讀者的補充:如果你不訓練模型,這一天還有用嗎?有,但要換個對應:

傳統 ML 的概念 生成式 AI 應用的對應物
超參數(學習率、樹深) 模型名稱、temperature、top_p、檢索的 top-k
訓練資料版本 檢索索引版本、切塊策略版本
模型權重 系統提示 + few-shot 範例 + 工具定義
測試集指標 評測集分數(faithfulness、答對率、格式合規率)
模型註冊表的 champion 目前線上採用的「提示+模型+索引」組合

你依然需要一份紀錄,回答「這個版本的組合,在評測集上跑出什麼分數」。 只是工具從 MLflow 換成了 Langfuse、promptfoo 或一份自己維護的表格。Day 24 與 Day 26 會完整處理這條線。

⚠️ 導入建議

如果你的團隊還在 Excel 階段,不要一次導入完整方案。第一週只做一件事:把 mlflow.autolog() 加進現有訓練腳本(一行),讓大家先感受到「所有實驗自動被記下來」的好處。等到有人開始主動查 UI,再談 Registry 與別名。工具導入的失敗,九成是因為一次要求太多。


今日小結

  • 實驗要記四類:參數、指標、產出、來源。第四類(Git commit、資料雜湊)最常被省略,卻是出事時唯一的追溯線索。
  • 切片指標(分通路、分地區、分金額級距)能抓出「整體好、局部爛」的問題,是資深與初階的分水嶺。
  • 模型註冊表的核心價值是解耦:服務端只認 @champion 別名,晉升與回滾都是移動別名,不需改程式碼、不需重新部署
  • 工具依團隊情境選;三個誤區是「只記指標」「把 Registry 當檔案櫃」「用它管提示詞」。
  • 導入從一行 autolog() 開始,別一次要求全套。

限制與注意事項

  • 推論服務快取與連線更新延遲:服務端雖然寫 models:/fraud-model@champion,但在分散式架構或高吞吐推論服務下,各 Pod/Worker 何時重新載入新權重、如何保證載入過程不中斷請求(Graceful Reload),本文未著墨相關冷啟動與快取失效問題。

  • 資料與環境漂移的不可重現性:僅記錄 Git Commit 與資料 SHA256,若底層 C 函式庫、CUDA 驅動或非固定隨機性的第三方套件有變動,單靠 MLflow 標籤仍可能無法 100% 精確重現數值,真實設計時請留意。

  • GenAI 評測維度與即時追蹤成本:將傳統 ML 指標直接對應到 GenAI 的 LLM-as-a-Judge 評測集,本文未考慮 LLM 評測本身的成本、非確定性以及動態真實流量下的 Trace 複雜度。

明天預告

有了資料版本與模型版本,明天把它們串成一條可以自動跑的管線,並加上這個系列最重要的一道關卡:品質門檻——讓不夠好的模型根本進不了生產環境。我會給一份可直接抄的 GitHub Actions workflow。

延伸閱讀


上一篇
Day 09:資料與特徵——DVC、資料驗證與訓練—服務偏斜
下一篇
Day 11:訓練管線與 CI/CD—品質門檻設定
系列文
從 4,343 筆職缺到 AI Engineer:MLOps × GenAI Engineering 雙主軸實戰11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言