iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
AI Engineering

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

Day 24:評測體系 — LLM-as-a-Judge 與那個沒人算的 κ 值

  • 分享至 

  • xImage
  •  

今天是合流點。前十六天兵分兩路,從今天起的四天,兩條路的人都要看——因為評測、安全、LLMOps、治理,是兩個職務共同的責任。

而評測是其中最關鍵的:它是「做得出 demo」與「做得出產品」的分界線。

今天要解決的問題

一個很常見的窘境:

主管:「這個 AI 助理準確率多少?」
工程師:「呃……我們測過一些問題,大部分都答得不錯。」
主管:「大部分是多少?」
工程師:「……」

傳統軟體有測試,ML 有測試集,LLM 應用呢? 很多團隊的答案是「人工看幾個例子」——這在 demo 階段可行,在產品階段是災難:你無法回答準確率、無法知道改動有沒有讓事情變糟、無法在上線前擋下退化。

📊 職缺訊號

「評測、安全與品質」出現在 34.3% 的生成式 AI 職缺,成長率排名第二(+1.7%)。這個成長趨勢說得很清楚:市場正在從「會做」轉向「能證明做得好」。而對 MLOps 工程師而言,這是 Day 11 品質門檻的延伸——只是要擋的東西從 AUC 變成了一組更複雜的指標。


一、現象:LLM 應用為什麼難測

三個根本困難,每一個都讓傳統測試方法失效:

困難 傳統軟體 LLM 應用
非確定性 同樣輸入必得同樣輸出 同樣輸入可能得到不同表述
沒有唯一正解 assert 相等即可 「意思對但用詞不同」該算對還是錯?
失敗是漸進的 要嘛通過要嘛失敗 答案可能「七成正確」

所以 LLM 應用的評測不能只有一種方法,要分層:

image

圖 24-1:評測金字塔(示意架構)。設計原則與軟體測試金字塔相同——能在便宜的下層攔截的問題,不要留給昂貴的上層。

第 1 層最常被低估。 很多「AI 品質問題」其實是格式問題:JSON 解析失敗、缺少必要欄位、引用編號不合法(Day 20)、輸出超長。這些用 assert 就能抓,成本幾乎為零,卻能攔下相當比例的失敗。

二、原理:LLM 評審可信嗎?

第 3 層是 LLM 評測的核心工具,也是最多人用錯的地方。

用它的理由:只有它能判斷「語意上對不對」,而且便宜到能跑幾百題。
風險:它自己也是個 LLM,也會錯、也有偏誤。

所以有一個多數團隊跳過、但絕不該跳過的步驟:驗證你的評審。

LLM 評審與人工標註的一致性檢核

圖 24-2:LLM 評審的可信度檢核(示範性數據)。左圖是與人工黃金標準的混淆矩陣與 Cohen's κ;右圖是五種評判偏誤在緩解前後的幅度。

Cohen's κ(kappa)是什麼? 它衡量「兩個評分者的一致程度,扣掉隨機猜也會一致的部分」。判讀標準:

κ 值 判讀 該怎麼辦
< 0.4 一致性差 不能用,回去改 rubric
0.4–0.6 中等 只能用於粗略趨勢,不能當門檻
≥ 0.6 實質一致 可作為自動化門檻
≥ 0.8 高度一致 可大幅減少人工抽查

為什麼要扣掉隨機一致? 舉例:如果 90% 的答案都是「好」,那麼一個「永遠回答好」的評審也能達到 90% 一致率——但它毫無資訊量。κ 就是用來抓出這種假象的。

圖 24-2 左圖還有一個重要觀察:誤判集中在「可(3 分)」這一列。這是 LLM 評審的典型弱點——極端的好壞判得準,中間灰帶判不穩。知道這件事,你在設計 rubric 時就會避免使用過多的中間級距。

三、動手:建一個能用的評測體系

3.1 第 1 層:可斷言的檢查(先做這個)

"""eval/assertions.py —— 最便宜的一層,能攔下大量問題。"""
import json, re

def check_response(output: str, ctx: dict) -> list[str]:
    """回傳違規清單,空清單代表通過。"""
    fails = []

    # 格式:能不能解析
    try:
        data = json.loads(output)
    except json.JSONDecodeError:
        return ["輸出非合法 JSON"]      # 這條不過,後面都不用檢查了

    # 必要欄位
    for field in ("answer", "sources", "confidence"):
        if field not in data:
            fails.append(f"缺少必要欄位:{field}")

    # 引用合法性(Day 20)
    cited = {int(n) for n in re.findall(r"\[(\d+)\]", data.get("answer", ""))}
    if not cited.issubset(set(range(1, ctx["n_chunks"] + 1))):
        fails.append(f"引用了不存在的來源編號:{cited}")

    # 禁用內容:不該出現的東西
    for banned in ("身分證字號", "內部成本", "as an AI language model"):
        if banned in data.get("answer", ""):
            fails.append(f"輸出包含禁用內容:{banned}")

    # 長度上限(成本與體驗)
    if len(data.get("answer", "")) > 1200:
        fails.append("回答超過長度上限")

    return fails

3.2 第 3 層:LLM 評審與偏誤緩解

"""eval/judge.py —— 帶偏誤緩解的 LLM 評審。"""
JUDGE_RUBRIC = """你是嚴格的品質評審。依下列標準為「候選答案」評分。

評分標準(rubric):
5 分:完全正確、有依據、切題、格式正確
4 分:正確但有小瑕疵(例如語氣或格式)
3 分:部分正確,或遺漏重要資訊
2 分:有明顯錯誤或無依據的陳述
1 分:完全錯誤或答非所問

重要原則:
- 只依內容的正確性評分,**不要因為答案較長就給高分**
- 若答案說「知識庫中沒有資料」,而參考答案確實也無法從脈絡得出,給 5 分
- 先寫出一句評分理由,再給分數

參考答案:{reference}
脈絡:{context}
候選答案:{candidate}

回傳 JSON:{{"reason": "<一句話理由>", "score": <1-5>}}"""

async def judge_with_mitigation(reference, context, candidate_a, candidate_b):
    """比較兩個候選時,交換順序各評一次以抵銷位置偏誤。"""
    s1 = await judge(reference, context, candidate_a, candidate_b)
    s2 = await judge(reference, context, candidate_b, candidate_a)   # 交換
    return {"a": (s1["a"] + s2["a"]) / 2, "b": (s1["b"] + s2["b"]) / 2}

三個緩解措施(對應圖 24-2 右圖):

偏誤 緩解
位置偏誤 交換順序評兩次取平均
自我偏好(偏好自己家族模型的風格) 用不同家族的模型當評審
冗長偏誤 rubric 明寫「不要因為長就給高分」
格式偏誤 評分前先把格式正規化
分數群聚(全給 4 分) 減少級距、要求先寫理由再給分

3.3 驗證你的評審:算 κ

"""eval/validate_judge.py —— 這一步不能跳過。"""
from sklearn.metrics import cohen_kappa_score

# 抽 50–100 題,請人工標註(用同一份 rubric)
human = [5, 3, 4, 1, 5, 2, ...]      # 人工分數
llm   = [5, 4, 4, 1, 5, 2, ...]      # LLM 評審分數

kappa = cohen_kappa_score(human, llm, weights="quadratic")  # 有序評分用加權 kappa
print(f"Cohen's κ = {kappa:.2f}")

if kappa < 0.6:
    print("⚠️ 一致性不足,不可作為自動化門檻。建議:")
    print("  1. 檢查分歧最大的案例,通常 rubric 有模糊之處")
    print("  2. 減少評分級距(5 級改 3 級)")
    print("  3. 在 rubric 中加入具體的邊界案例說明")

⚠️ κ 要定期重算

常見錯誤是「一次對齊、終身信任」。當你換了模型版本、改了 rubric、或評測集的題型分布改變,一致性都可能悄悄下滑。每次改動 judge 設定後,抽 50 題重算一次,並把這個數字寫進評測報告——讓所有讀報告的人知道這些分數有多可信。

四、取捨:評測要投資到什麼程度

專案階段 評測投入 具體做法
PoC 驗證 極少 20 題手動看,確認方向對
上線前 中等(值得投資) 50–100 題評測集 + 第 1、2 層自動化 + 一次 κ 驗證
上線後 持續累積 每次事故變成一題;納入 CI 成為 gate
高風險領域(醫療、法律、金融) 高 加上人工複核比例與定期稽核(Day 27)

把評測納入 CI,就是 Day 11 品質門檻在生成式 AI 的對應物:

# .github/workflows/eval.yml(節錄)
- name: 執行評測集
  run: uv run python eval/run.py --dataset eval/golden_set.json

- name: 品質門檻
  run: |
    uv run python eval/gate.py \
      --min-faithfulness 0.85 \
      --min-format-pass 0.98 \
      --max-regression 0.03      # 不得比目前線上版本退步超過 3%

💡 評測集就是產品規格的可執行版本

當你寫下一題「使用者問 X,系統應該回答 Y」,你其實是在定義產品行為。而這件事不能只由工程師做——業務單位、客服主管才知道「正確答案」長什麼樣。

實務上最有效的做法:讓業務單位提供 20 題與標準答案。這個過程本身,往往比評測結果更有價值——因為它會逼出大家對「這個產品到底該做什麼」的分歧。


今日小結

  • LLM 應用難測的三個根本原因:非確定性、沒有唯一正解、失敗是漸進的。
  • 評測要分層:可斷言檢查 → 程式化指標 → LLM 評審 → 人工。能在便宜的下層攔截的,不要留給上層。第 1 層最常被低估,卻能攔下大量失敗。
  • LLM-as-a-Judge 本身也會錯。必須算 Cohen's κ 驗證它與人工的一致性(≥ 0.6 才能當自動化門檻),且要定期重算。
  • LLM 評審的典型弱點:極端好壞判得準、中間灰帶判不穩——設計 rubric 時避免過多中間級距。
  • 五種偏誤與緩解:位置(交換順序)、自我偏好(換模型家族)、冗長(rubric 明寫)、格式(先正規化)、分數群聚(減少級距、先寫理由)。
  • 把評測做成 CI gate,就是 Day 11 品質門檻的生成式 AI 版本。
  • 評測集是產品規格的可執行版本——它不該只由工程師定義。

延伸閱讀

  • 📘 教科書對應章節:第 18 章 評測、安全與品質
  • 📄 Zheng et al., Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena (2023)——位置偏誤、冗長偏誤的系統性研究出處
  • 📄 promptfoo 文件——把評測寫成 YAML 設定並納入 CI 的現成工具

上一篇
Day 23:微調 — 什麼時候該做、LoRA 的帳怎麼算
下一篇
Day 25:安全 — OWASP LLM Top 10 與提示注入的縱深防禦
系列文
RE: 從 4,343 筆職缺到 AI Engineer:MLOps × GenAI Engineering 雙主軸實戰 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言