昨天談脈絡工程(context engineering),學會把對的資訊塞進有限的上下文視窗。但這裡藏著一個要命的問題:你改了 prompt、換了檢索策略、調了記憶摘要,你怎麼知道系統真的變好、而不是這裡好了那裡壞了?靠自己手動點幾個例子看順不順眼,是自我安慰。答案是評估(evals):把「好不好」變成可量測、可重跑、可比較的數字。今天講清楚為什麼傳統測試不夠、評估分哪些層次、有哪些方法,以及當紅的 LLM-as-judge(用一個模型評分另一個模型的輸出)怎麼用才不會被它的偏誤騙了。

📖 學

傳統軟體的單元測試(unit test)建立在一個假設上:同樣的輸入,永遠得到同樣的輸出,而且對錯是二元的。add(2, 3) 就該回 5,不多不少。LLM 世界這兩個假設全破。第一,輸出是非確定性的(non-deterministic),同一個 prompt 跑兩次可能給出措辭不同的答案,即使把 temperature 設成 0,底層推論的浮點運算與服務端批次處理仍可能讓結果飄移。第二,任務多半是開放式的(open-ended),「幫我摘要這篇文章」沒有唯一正解,一個摘要可以又對又不夠精煉,好壞是連續光譜而非通過/失敗。所以你不能寫 assert output == expected,你需要的是一套能容忍變異、能給程度分數的評估機制。

評估要分層次來想,不同層次抓不同的病。元件層(component-level)評估針對系統的某一段零件,對 RAG 來說最關鍵的就是檢索命中率:給定一個問題,正確的文件段落有沒有被撿回來?常用指標是 Recall@k(前 k 個結果裡涵蓋了多少該找到的段落)、Precision@k(撿回來的東西裡有多少真的相關)、MRR(Mean Reciprocal Rank,第一個正確結果排在多前面)以及 nDCG(排序品質的加權分數)。這層的好處是便宜、快、責任歸屬清楚——如果檢索 recall 只有 40%,那生成端再強也是巧婦難為無米之炊,你該去修檢索而不是換模型。任務層(task-level / end-to-end)評估則看整條管線跑完的最終產出,例如 RAG 的答案「忠實度」(faithfulness,答案有沒有超出檢索內容去瞎編)與「答案相關性」(answer relevance)。兩層要一起看:元件層告訴你病灶在哪,任務層告訴你使用者實際感受到的結果。

還有一條正交的軸:離線(offline)對線上(online)。離線評估是在固定的評估資料集上跑,像是回歸測試,適合在每次改動前後比對、進 CI(持續整合)。線上評估則是在真實流量上量測,收集使用者的隱性訊號(有沒有重問、有沒有複製答案、對話輪數)與抽樣的人工或模型評分。離線幫你在上線前擋掉退步,線上幫你抓到那些你評估集根本沒想到的真實案例——兩者互補,離線集的內容常常就是從線上撈出來的失敗案例反哺而來的。

具體怎麼評分,由淺到深有三種方法。最硬的是程式化斷言(programmatic assertions / code-based grading):輸出必須是合法 JSON、必須包含某個關鍵字、數字必須落在範圍內、不能出現禁詞。這類斷言確定、免費、零偏誤,能抓多少就用多少,是評估的第一道防線。其次是參考答案比對(reference-based),你有標準答案(ground truth),用字串完全比對、或用嵌入向量的語意相似度、或針對抽取型任務算 F1。問題是開放式任務往往沒有單一標準答案,硬比對會冤枉掉「換句話說但一樣好」的回答。於是有了第三種:LLM-as-judge,用一個(通常較強的)模型當裁判,依你給的準則替另一個模型的輸出打分或做比較。它的殺傷力在於能處理前兩種方法搞不定的模糊判斷——「這個回答的語氣專不專業」「有沒有正面回應使用者的真正問題」——而且比人工便宜太多、可以規模化跑上萬筆。

但 LLM-as-judge 不是免費午餐,它有一組已被大量研究記錄的系統性偏誤,不理解就會被它騙。位置偏誤(position bias):做兩兩比較時,裁判會偏好排在特定位置(前面或後面)的答案,光是把兩個回答的呈現順序對調,在程式碼評判這類任務上準確率就可能擺盪超過 10%。冗長偏誤(verbosity bias):裁判傾向給比較長、比較「像模像樣」的答案更高分,即使實質內容沒有更好——研究顯示模型裁判的評分與回答長度的相關係數可高達 0.87,遠高於人類評審的 0.44。自我偏好(self-preference bias):模型會偏愛自己或同家族模型生成的輸出,在某些基準上這個偏差幅度從 -38% 到 +90% 不等,而且越強的模型自我偏好往往越明顯——這代表你不該用 GPT 去評 GPT 自己的輸出還沾沾自喜。

校準(calibration)這些偏誤有幾套成熟做法。給明確的評分準則(rubric):不要只丟「請打 1 到 5 分」,要寫清楚每個分數對應什麼具體行為,例如「5 分=完全依據提供的脈絡作答且無捏造;3 分=大致正確但有一處無關脈絡的補充;1 分=出現與脈絡矛盾的內容」,準則越具體,裁判越穩定、也越接近人類判斷。用兩兩比較(pairwise)取代絕對打分:模型判斷「A 和 B 誰比較好」比判斷「A 值幾分」可靠得多;而為了消除位置偏誤,把 A/B 順序對調各跑一次,兩次結論一致才算數,不一致就記為平手。最後也最重要:和人工標註對齊(alignment with human labels)。抽一批樣本讓人工評審打分,再看你的 LLM 裁判和人類的一致率(agreement,常用 Cohen’s kappa 之類的指標),把裁判當成一個要被驗證的量測儀器——如果它和人類只有六成一致,那它給的分數就別太當真,要嘛改 rubric、要嘛換裁判模型。

評估資料集(eval dataset)怎麼建,決定了整套評估的天花板。起手式不必貪多,20 到 50 個精心挑選的案例就能開始發揮作用,重點在覆蓋面:典型案例、邊界案例(空輸入、超長輸入、多語言)、已知會出錯的案例、以及對抗性案例(想騙過系統的輸入)。最寶貴的來源是線上真實失敗案例——把使用者踩到的雷做成固定測項,它就再也不會偷偷回來咬你。每個案例存下輸入、預期行為或參考答案、以及評分方式,版本控管起來像對待程式碼一樣對待它。接著把離線評估接進 CI:每次改 prompt、換模型、動檢索,自動在整個評估集上重跑,設定門檻(例如忠實度不得低於上一版、關鍵斷言必須全過),退步就擋下這次合併(merge)。這就是把「我覺得變好了」升級成「數字證明沒變壞」的迴歸測試(regression test)。

把這一切接回前幾天的主線,你會看到一個閉環。脈絡工程負責把對的資訊放進視窗;可觀測性(observability)負責記錄每一次執行的軌跡(trace)、檢索了什麼、模型看到什麼;而評估則消費這些軌跡,把它們變成分數與趨勢。三者缺一不可:沒有可觀測性,你連評估要看哪裡都不知道;沒有評估,你的脈絡工程只是憑感覺調參。真正成熟的 AI 系統開發,是「觀測→評估→改動→再觀測」的持續循環,而 evals 就是這個飛輪的儀表板。

🧠 記

  • 傳統單元測試假設輸出確定且對錯二元;LLM 輸出非確定性(non-deterministic)又開放式(open-ended),所以要用能容忍變異、給程度分數的評估取代 assert equal
  • 評估分層:元件層看 RAG 檢索命中率(Recall@k、Precision@k、MRR、nDCG),任務層看 end-to-end 產出(忠實度 faithfulness、答案相關性);另有離線(進 CI 的回歸測試)對線上(真實流量訊號)兩軸。
  • 評分方法由硬到軟:程式化斷言(零偏誤,能用就用)→ 參考答案比對(語意相似度/F1)→ LLM-as-judge(處理模糊判斷、可規模化)。
  • LLM-as-judge 三大偏誤:位置偏誤(position bias,順序影響結果)、冗長偏誤(verbosity bias,偏愛長答案)、自我偏好(self-preference bias,偏愛自家模型輸出)。
  • 校準做法:寫具體 rubric、用 pairwise 比較並對調順序、和人工標註對齊(算 agreement/kappa),把裁判當成要驗證的量測儀器。
  • 評估資料集 20–50 例起步即可,覆蓋典型/邊界/失敗/對抗案例;把線上失敗案例反哺成固定測項,並把整個評估集接進 CI 做迴歸門檻。

✍️ 實踐

今天挑一個你自己在用的 prompt 或小 agent(例如「幫我把技術文章摘成三點」的助手),為它寫一份 5 題的 eval 集,今天做得完。步驟:第一,開一個表格或 YAML 檔,每列記三欄——輸入預期行為評分方式。第二,湊出 5 個案例:2 個典型輸入、1 個邊界(超長或空白輸入)、1 個已知踩過的雷、1 個對抗性輸入(例如夾帶「忽略前面指令」的注入嘗試)。第三,為每題選評分方式:能用程式化斷言的先用(「輸出必須正好三點」「不得超過 120 字」),模糊的用一段 LLM-as-judge 的 rubric,把 1 分和 5 分各對應什麼行為寫死。第四,實際跑一遍現況拿到基準分數,存檔。之後每次你改動這個 prompt,重跑這 5 題比對——你就有了自己的迴歸測試。進階一點:把同一個回答的 A/B 順序對調,餵給你的 judge 兩次,親眼看看位置偏誤有沒有讓它改變主意。

🔗 延伸學習

💬 問 AI

我有一個 [描述你的 prompt 或 agent 用途] 的 LLM 應用。請幫我:
1. 設計一份 8 題的評估集,涵蓋典型、邊界、已知失敗與對抗性案例,每題給「輸入 / 預期行為 / 建議評分方式(程式化斷言或 LLM-as-judge rubric)」。
2. 為需要 LLM-as-judge 的題目,各寫一段 1–5 分的具體 rubric,並說明如何用 pairwise 比較與對調順序來降低位置偏誤。
3. 給我一個把這份評估集接進 CI 的最小做法(用什麼門檻擋退步),以及如何用線上失敗案例持續擴充這份集合。