【MLflow LLMs & Agents 實戰】#02 用 LLM-as-a-Judge 評估你的模型輸出

測驗:用 LLM-as-a-Judge 評估你的模型輸出

共 5 題,點選答案後會立即顯示結果

1. 文章指出,為什麼 LLM 的輸出「難以用傳統 metric(如 exact match、BLEU)評估」?

  • A. 因為 LLM 的輸出太長,無法計算
  • B. 因為同一個問題的好答案有無限多種,字串比對會把好答案判成錯
  • C. 因為傳統 metric 只能用在圖片上
  • D. 因為 LLM 不會輸出文字,只會輸出向量

2. 在評估資料集中,一筆資料的 inputsexpectations 分別代表什麼?

  • A. inputs 是評審模型名稱;expectations 是分數門檻
  • B. inputs 是標準答案;expectations 是題目
  • C. inputs 是餵給 app 的輸入(題目/context);expectations 是你對這題的期望(標準答案等)
  • D. 兩者都是評審打完分後才產生的結果

3. 關於內建 scorer 需不需要「標準答案(expected_response)」,下列何者正確?

  • A. Correctness 需要標準答案;RelevanceToQuery 不需要
  • B. 所有 scorer 都一定要標準答案才能跑
  • C. 所有 scorer 都不需要標準答案
  • D. RelevanceToQuery 需要標準答案;Correctness 不需要

4. 在 make_judge 建立自訂 judge 時,判準(rubric)具體是寫在哪個部分?

judge = make_judge( name=”conciseness”, instructions=”…{{ inputs }}…{{ outputs }}…pass/fail…”, model=”openai:/gpt-4o”, )
  • A. 寫在 name 這個名字裡
  • B. 寫在 model 參數裡
  • C. 寫在 instructions 這段文字裡,佔位符會被每題的 inputs/outputs 代換
  • D. MLflow 自動產生,開發者不能修改

5. 文章說要用評估來「比較不同 prompt 或模型版本」,關鍵前提是什麼?

  • A. 每個版本要用不同的評估集,才公平
  • B. 只要有一個版本跑過 evaluate 就能比較
  • C. 要把標準答案放進 inputs 讓分數更高
  • D. 兩次評估要用同一份 data 和同一組 scorers,只換 predict_fn,分數才可比

系列第 2 篇,共 4 篇|難度:L3-熟練
前置:已讀 #01(Tracing 入門),了解 trace 概念;有基本 Python 與 LLM API 經驗

一句話說明

LLM 的輸出沒有標準答案,所以我們請「另一個 LLM 當評審」來打分,MLflow 把這整套包成 mlflow.genai.evaluate


為什麼 LLM 輸出不能用傳統 metric

傳統 ML 評估很單純:分類問題比對 label 算 accuracy,回歸問題算 RMSE。有標準答案,一個 == 就分勝負。

LLM 不是這樣。你問「幫我把這封信寫得更客氣」,正確答案有無限多種。用字串比對(exact match)會把 99% 的好答案判成錯;用 BLEU、ROUGE 這種比對「字重疊」的指標,也只是在測「跟參考答案用字像不像」,測不出「這句話到底通不通、有沒有唬爛」。

所以現在的主流做法是 LLM-as-a-Judge:拿一個 LLM 當評審,給它「題目、AI 的回答、(可選的)標準答案」,請它照一份判準(rubric)打分或給 pass/fail。MLflow 的 GenAI 評估就是把這件事標準化。

作為 Vibe Coder,你的任務不是從零實作評審邏輯——那是 mlflow.genai 幫你做的。你的任務是看懂 AI 幫你寫的評估腳本在評什麼、判準嚴不嚴、結果能不能信。這篇就是教你讀這種 code。

✅ 必看懂(這篇的核心):
- 評估資料集長什麼樣(inputs / expectations)
- mlflow.genai.evaluate(...) 三個關鍵參數
- 內建 scorer(Correctness / RelevanceToQuery / Guidelines…)
- 自訂 judge(make_judge)的判準寫在哪

📌 知道就好(遇到再查):
- 把既有 trace 撈出來當評估資料
- 在 MLflow UI 比較兩個 run

🕰️ 認得就好(舊寫法,維護舊專案會看到):
- mlflow.evaluate(model_type="question-answering")(舊版評估入口)
Code language: JavaScript (javascript)

30 秒範例:一個最小的評估

uv add mlflow openai
import mlflow
from mlflow.genai.scorers import Correctness

# 1. 評估資料:一筆一筆的「題目 + 期望」
data = [
    {
        "inputs": {"question": "MLflow 的 tracking server 預設 port 是幾號?"},
        "expectations": {"expected_response": "5000"},
    },
]

# 2. 被評估的東西:一個吃 inputs、吐回答的函式
def my_app(question: str) -> str:
    return call_my_llm(question)   # 你的 LLM 應用

# 3. 跑評估
results = mlflow.genai.evaluate(
    data=data,
    predict_fn=my_app,
    scorers=[Correctness()],       # 用內建的「正確性」評審
)
Code language: PHP (php)

這段代碼做了什麼

  1. data:準備一份評估集,每筆有 inputs(餵給你 app 的題目)和 expectations(你期望它答成怎樣)
  2. predict_fn:指向你要被打分的應用,MLflow 會把每筆 inputs 餵進去拿回答
  3. scorers:指定評審。Correctness() 是內建的 LLM judge,會拿「回答」對「expected_response」判對錯
  4. 跑完,結果進 MLflow,可以在 UI 看每一題的分數和評審理由

核心概念翻譯

你會看到 意思
inputs 餵給你 app 的輸入(題目、context…),一個 dict
expectations 你對這題的期望(標準答案、該遵守的規則),評審會參考
predict_fn 被評估的應用函式,吃 inputs 吐 outputs
scorers=[...] 一串評審。可以混用內建 scorer 和自訂 judge
Correctness() 內建 LLM judge:回答對不對(比對 expected_response)
RelevanceToQuery() 內建:回答有沒有切題(不需要標準答案)
RetrievalGroundedness() 內建:回答有沒有「根據 context」而不是自己瞎編(測 RAG 幻覺)
Guidelines(...) 內建:你用白話寫一條規則,judge 判有沒有遵守
make_judge(...) 自己造一個 judge,判準(rubric)你自己寫

一個關鍵直覺:有些 scorer 需要 expectations(標準答案),有些不需要

  • Correctness 要標準答案(拿回答比對 expected_response)
  • RelevanceToQueryRetrievalGroundedness 不用標準答案(只看題目、回答、context 之間合不合理)

這很重要,因為準備標準答案很貴。看到一份評估腳本只用了「不需標準答案」的 scorer,你就知道它省了人工標註,但也就評不了「答案正不正確」這件事。


評估資料集:一筆資料長怎樣

這是整個評估的地基,一定要看懂。最完整的一筆長這樣:

{
    "inputs": {                              # 餵給 app 的輸入
        "question": "退貨要幾天內?",
        "context": "本店退貨政策為 7 天內…",   # RAG 場景會有檢索到的資料
    },
    "expectations": {                        # 你的期望(評審參考用)
        "expected_response": "7 天內可退貨",  # 標準答案
        "expected_facts": ["7 天"],          # 必須提到的事實點
    },
}
Code language: PHP (php)

逐欄翻譯

"inputs"                # 這題要問 app 什麼(會被餵進 predict_fn)
  "question"            # 使用者的問題
  "context"            # 檢索到的參考資料(RAG 才有)
"expectations"          # 這題「答對」長什麼樣
  "expected_response"   # 完整的理想答案
  "expected_facts"      # 只要答案包含這些關鍵事實就算對(比逐字比對寬鬆)
Code language: PHP (php)

你不用每個欄位都填。最省的版本只有 inputs(配不需標準答案的 scorer);要評正確性才需要 expectations

把 trace 轉成評估資料(承接 #01)

#01 教你的 trace,其實就是現成的評估素材——裡面已經有真實使用者問了什麼、你的 app 回了什麼。MLflow 可以把 trace 撈出來直接當 data

# 把過去記錄下來的 trace 撈出來當評估集
traces = mlflow.search_traces(
    experiment_ids=["123"],
    max_results=50,
)

results = mlflow.genai.evaluate(
    data=traces,          # 直接餵 trace,不用手寫 inputs
    scorers=[RelevanceToQuery()],
)
Code language: PHP (php)

這在幹嘛:不用自己手刻評估集,直接拿線上真實流量來評。MLflow 認得 trace 格式,會自動抽出 inputs / outputs。這也是為什麼 #01 要你先學會 tracing——沒有 trace 就沒有真實評估資料。


內建 scorers:AI 最常用這幾個

看評估腳本時,先看它 import 了哪些 scorer,就大概知道它在評什麼。

用法 1:Guidelines —— 用白話寫規則

這是最好懂、也最常被 AI 拿來用的一種。你用自然語言寫一條規則,judge 幫你判有沒有遵守:

from mlflow.genai.scorers import Guidelines

tone = Guidelines(
    name="polite_tone",
    guidelines="回答必須保持禮貌、專業,不能出現情緒性或責備使用者的字眼。",
)

results = mlflow.genai.evaluate(
    data=data,
    predict_fn=my_app,
    scorers=[tone],
)
Code language: JavaScript (javascript)

翻譯:「請一個 LLM 讀每個回答,判斷它有沒有做到『禮貌專業』這條規則,給 pass 或 fail 加理由。」不需要標準答案,因為判的是「風格有沒有守規矩」。

用法 2:多個 scorer 一起評

真實腳本通常一次掛好幾個評審,從不同角度打分:

from mlflow.genai.scorers import (
    Correctness, RelevanceToQuery, RetrievalGroundedness,
)

results = mlflow.genai.evaluate(
    data=data,
    predict_fn=rag_app,
    scorers=[
        Correctness(),            # 答對嗎(要 expected_response)
        RelevanceToQuery(),       # 切題嗎
        RetrievalGroundedness(),  # 有沒有根據檢索資料、還是在幻覺
    ],
)
Code language: PHP (php)

翻譯:這是典型的 RAG 評估組合——同時測「正確、切題、不亂編」。結果表格每個 scorer 一欄,你能看出「答對但離題」或「切題但在唬爛」這種細節。


自訂 judge:判準(rubric)自己寫

內建 scorer 不夠用時,AI 會幫你用 make_judge 造一個。這是評估腳本裡最需要盯緊的部分,因為判準的鬆緊全在這段文字裡

from mlflow.genai.judges import make_judge

conciseness = make_judge(
    name="conciseness",
    instructions=(
        "評估這個回答是否簡潔。\n"
        "問題:{{ inputs }}\n"
        "回答:{{ outputs }}\n"
        "如果回答直接、沒有廢話、沒有重複,評為 'pass';\n"
        "如果冗長、繞圈子、重複同樣的意思,評為 'fail'。"
    ),
    model="openai:/gpt-4o",       # 用哪個模型當評審
)
Code language: PHP (php)

逐段翻譯

name="conciseness"        # 這個評審的名字(會變成結果表格的欄名)
instructions="..."        # 判準本體:告訴評審 LLM 怎麼打分
  "{{ inputs }}"          # 佔位符,跑的時候換成該題的輸入
  "{{ outputs }}"         # 佔位符,換成 app 的回答
  "評為 'pass' / 'fail'"  # 明確的輸出格式(judge 要回這個)
model="openai:/gpt-4o"    # 指定當評審的模型(越強的模型判得越準,但越貴)
Code language: PHP (php)

這在幹嘛:你在 instructions 裡寫清楚「什麼算好、什麼算壞」,{{ inputs }} / {{ outputs }} 這些佔位符會在每一題被自動代換。這就是你的 rubric——judge 好不好用,全看這段寫得夠不夠具體。

判準設計的重點:越具體越可靠。「評估回答品質」這種模糊指令會讓 judge 亂給分;「有沒有提到退貨天數、語氣禮不禮貌」這種可檢查的條件才穩定。


讀懂評估結果

跑完 evaluate 會回一個結果物件,也會寫進 MLflow。你會看到類似這樣的表格(每列一題,每個 scorer 一欄):

question              | correctness | relevance | conciseness
----------------------|-------------|-----------|------------
退貨要幾天?           | pass        | pass      | fail
運費怎麼算?           | fail        | pass      | pass

怎麼讀:橫著看單題(這題哪個面向掛了),直著看趨勢(哪個 scorer 整體偏低)。上面第一列「答對、切題,但太囉嗦」;第二列「切題、簡潔,但答錯」。

在 UI 比較不同 prompt / 模型版本

評估最大的價值是比較。你改了 prompt 或換了模型,各跑一次 evaluate,就是兩個 MLflow run,在 UI 並排看哪個分數高:

# 版本 A
with mlflow.start_run(run_name="prompt-v1"):
    mlflow.genai.evaluate(data=data, predict_fn=app_v1, scorers=scorers)

# 版本 B
with mlflow.start_run(run_name="prompt-v2"):
    mlflow.genai.evaluate(data=data, predict_fn=app_v2, scorers=scorers)
Code language: PHP (php)

這在幹嘛:兩次評估用同一份 data 和同一組 scorers,只換 predict_fn。這樣兩個 run 的分數才可比——你才能理直氣壯說「v2 的 correctness 從 70% 升到 85%」。到 MLflow UI 勾選兩個 run 就能並排比較。


🚩 紅旗:評估腳本最容易出的問題

評估這種東西最陰險的地方是——它永遠會給你一個數字,但數字不一定有意義。以下幾個是 AI 幫你寫評估時最常見的坑。

🚩 紅旗 1:judge prompt 過於寬鬆

quality = make_judge(
    name="quality",
    instructions="判斷這個回答好不好。{{ outputs }}",   # 🚩 判準太模糊
    model="openai:/gpt-4o",
)
Code language: PHP (php)

為什麼危險:「好不好」沒有可檢查的標準,judge 只能憑感覺,結果幾乎全 pass,你會誤以為模型很棒。這種評估等於沒評。

跟 AI 這樣說:「把這個 judge 的 instructions 改具體,列出明確可檢查的條件(例如要包含哪些資訊、語氣要求、長度限制),並要求它輸出 pass/fail 加理由。」

🚩 紅旗 2:資料洩漏(標準答案混進輸入)

data = [{
    "inputs": {
        "question": "退貨幾天?",
        "answer": "7 天",          # 🚩 標準答案被放進 inputs 餵給 app 了
    },
    "expectations": {"expected_response": "7 天"},
}]
Code language: PHP (php)

為什麼危險inputs 是會餵進你 app 的東西。把答案夾在 inputs 裡,等於考試把答案印在考卷上——app 直接抄,評估分數虛高,上線就現形。標準答案只該放在 expectations

跟 AI 這樣說:「檢查我的評估集,標準答案應該只出現在 expectations,不能出現在 inputs 裡。」

🚩 紅旗 3:用被評估的同一個模型當評審

judge = make_judge(name="x", instructions="...", model="openai:/gpt-4o")
# 而 my_app 內部也是用 gpt-4o 生成回答   🚩 球員兼裁判
Code language: PHP (php)

為什麼危險:同一個模型有共同盲點,它看不出自己的錯,還可能偏好「跟自己風格像」的答案(self-preference bias),分數會系統性偏高。

跟 AI 這樣說:「評審模型和被評估的模型不要用同一個,換一個獨立的(最好是更強的)模型當 judge。」

🚩 紅旗 4:只信 judge,完全沒有人工抽查

為什麼危險:LLM judge 本身也會出錯、也會有偏好。如果你從沒人工看過 judge 的判斷對不對,你等於用一個沒被驗證過的尺在量東西。

跟 AI 這樣說:「幫我抽 10 筆 judge 判 pass 和 fail 的結果列出來,我要人工核對 judge 判得對不對。」(正式做法是先讓 judge 和人類標註對齊,再放心大規模用。)


Vibe Coder 驗收檢查點

拿到一份 AI 寫的評估腳本,照這個清單過一遍:

  • [ ] 打開評估集,確認 標準答案只在 expectations、沒混進 inputs(防資料洩漏)
  • [ ] 找到每個 make_judgeinstructions,讀一遍——判準是具體可檢查的,還是「好不好」這種模糊詞?
  • [ ] 確認 judge 的 model 和被評估的 model 不是同一個
  • [ ] 跑一次評估,到 MLflow UI 打開結果表格,手動看 3-5 題 judge 的評分理由,判斷它判得合不合理
  • [ ] 要比較版本時,確認兩個 run 用了同一份 data 和同一組 scorers(否則分數不可比)
  • [ ] 問 AI:「這份評估有沒有需要標準答案的 scorer?我的評估集有準備 expectations 嗎?」

看不懂就這樣問 AI

「用白話一段一段解釋這份 MLflow 評估腳本在評什麼:它用了哪些 scorer、每個 scorer 需不需要標準答案、判準寫在哪。我要能對別人講清楚。」

「這個 make_judge 的 instructions 判準夠具體嗎?會不會太寬鬆導致什麼答案都 pass?幫我列出可以改進的地方。」

「幫我檢查這份評估集有沒有資料洩漏——標準答案有沒有不小心出現在會餵給 app 的 inputs 裡?」


小結

  • LLM 輸出沒有唯一正解,所以用 LLM-as-a-Judge 打分,MLflow 用 mlflow.genai.evaluate 把它標準化
  • 評估集的地基是 inputs(餵給 app)+ expectations(你的期望);標準答案只放 expectations
  • 內建 scorer(Correctness / RelevanceToQuery / RetrievalGroundedness / Guidelines)能快速上手,其中有些需要標準答案、有些不用
  • 自訂 judge 用 make_judge,判準(rubric)就是那段 instructions,越具體越可靠
  • 讀結果表格要橫看單題、直看趨勢;比較版本要固定 data 和 scorers
  • 四大紅旗:judge 太寬鬆、資料洩漏、球員兼裁判、完全不做人工抽查

下一篇(#03)我們會把評估接進實際的迭代流程,看怎麼用評估結果驅動 prompt 優化。

進階測驗:用 LLM-as-a-Judge 評估你的模型輸出

測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。

1. 你要評估一個 RAG 客服機器人,重點是「答案有沒有根據檢索到的 context、還是在幻覺」,但你手上沒有人工標好的標準答案。你該選哪個 scorer? 情境題

  • A. Correctness(),因為它最全面
  • B. RetrievalGroundedness(),它測回答有沒有根據 context、不需要標準答案
  • C. 只能先花時間人工標好 expected_response,否則無法評估
  • D. 用 exact match 比對就好

2. 你想比較 prompt v1 與 v2 哪個比較好,正確的做法是? 情境題

  • A. v1 用 correctness、v2 用 relevance,看哪個分數高
  • B. 兩個版本各自準備最能凸顯自己優點的評估集
  • C. 用同一份 data 和同一組 scorers,各自 start_run 跑一次,只換 predict_fn,再到 UI 並排比較
  • D. 只跑 v2,因為它是新的,一定比較好

3. 你被指派評估一個「把使用者輸入的問題改寫得更客氣」的 app,重點是語氣。你想用最省事、不需標準答案的方式評「有沒有保持禮貌專業」。最合適的做法? 情境題

  • A. 用 Guidelines(name=..., guidelines="回答必須禮貌專業…"),用白話寫一條規則讓 judge 判
  • B. 用 Correctness() 配一份逐字標好的標準答案
  • C. 用字串長度判斷,越長越禮貌
  • D. 無法用 MLflow 評估風格,只能純人工

4. 同事的評估集這樣寫,且評估分數異常地高,上線後卻表現很差。問題最可能出在哪? 錯誤診斷

data = [{ “inputs”: { “question”: “退貨幾天內?”, “answer”: “7 天”, }, “expectations”: {“expected_response”: “7 天”}, }]
  • A. expectations 不該有 expected_response
  • B. 資料洩漏:標準答案 “answer” 被放進 inputs 餵給 app,等於考卷印答案,分數虛高
  • C. inputs 不能有 question 欄位
  • D. 缺少 scorers 參數(此段本來就沒有)

5. 一份自訂 judge 幾乎所有回答都判 pass,團隊卻覺得模型明明常出錯。看到下面的 judge 定義,最該優先修正什麼? 錯誤診斷

quality = make_judge( name=”quality”, instructions=”判斷這個回答好不好。{{ outputs }}”, model=”openai:/gpt-4o”, )
  • A. 把 model 換成更便宜的模型
  • B. 把 name 改得更長更描述性
  • C. instructions 判準太寬鬆(「好不好」無可檢查標準),改成列出明確可檢查的條件並要求 pass/fail 加理由
  • D. 移除 {{ outputs }} 佔位符

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *