跳至主要內容

    LLM Eval 怎麼做才不會被騙?跑越多組,第一名越可能只是運氣(2026 實驗設計懶人包)

    跑實驗前先定好五格 Eval 設計卡並鎖定保留集,才能擋住挑最高分帶來的運氣膨脹

    sunny 桑尼· · 20 MIN READ · 113 次瀏覽

    LLM Eval 怎麼做才不會被騙?跑越多組,第一名越可能只是運氣(2026 實驗設計懶人包)
    本文目錄

    一個下午跑完六十組實驗,排行榜第一名就是最好的嗎?這篇用三個自己就能跑的模擬,帶你量出挑最高分到底會騙你多少!

    三個模型、五套 Prompt、四種資料清洗方式,排列起來是六十組實驗。交給自動化流程,一個下午就跑完,排行榜第一名會自己浮出來。

    問題從這裡開始:跑實驗變容易之後,誰來決定哪個結果值得相信?

    這篇先回答一個更具體的問題:從六十組裡挑出來的第一名,分數裡有多少是運氣。答案可以用幾十行 numpy 算出來,結果比多數人以為的大。

    要擋住運氣,靠的是一張在跑實驗之前就寫好的表,這篇叫它「Eval 設計卡」。Eval 是 evaluation 的簡稱,指用一批題目替模型或 AI 系統打分數。設計卡有五格:這次要推翻哪一句話、用哪些題目、怎麼評分、什麼時候停、結果怎麼報告。

    Eval 設計卡的五格必須在看到分數前定下來,保留集留到最後才打開,才能擋住「看了答案才出題」的決策偏差(Sunny DataScience 整理)。

    每一格都先於結果寫下。它不保證每次決策都對,但能擋住最常見的錯:看了答案才出題。下面先從第一格講起,再用模擬實驗量出其他幾格各擋住了多少誤差。

    快速回答 LLM Eval(用一批題目替模型或 AI 系統打分數)跑得越多組,第一名裡的運氣越多。在一組模擬裡,假設 60 組設定的真實準確率都是 70%,在同一批 200 題上挑出的第一名平均 77.3%,換 500 題新題目重測回到 70.0%。擋住運氣的方法,是跑之前寫好 Eval 設計卡:要推翻的假設、題目、評分、停止規則、報告五格,都在看到分數之前定下來,鎖起來的保留集留到最後才打開。

    先寫下能被數據否定的具體假設,並在看到結果前鎖定比較條件與品質底線

    假設一個團隊要改善文件問答。設計卡的第一格不要寫「新版比較好」,要寫一句可以被數據否定的話,例如:「對需要跨兩段文件整合的問題,新版能提高答案有來源支持的比例,且不增加沒有來源的斷言。」這句話同時寫下兩件事:要改善的對象,和不能犧牲的品質。

    接著固定比較條件:同一批問題、同一份文件版本、同一套評分規則,只改這次要研究的因素。模型、Prompt、檢索和資料清洗一起變,分數上升也說不清是誰的功勞。想看因素之間的交互作用,可以做實驗設計,但要先決定哪些組合值得測、資源允許測到哪裡,不能事後把偶然的發現都當成原本的假設。

    設計卡也要記錄「不改善什麼」。新版讓普通問題答得更快,卻讓資料不足時的拒答變少,團隊願不願意接受?這取決於產品風險,要在看到結果之前寫下來。同一個總分,對內部輔助工具和對外自動回答的客服,代表的決策可能完全不同。

    三個模擬量出運氣成分:60 組挑最高分虛增 7.3%,反覆偷看 p 值讓假陽性飆至 27.4%

    有了假設,接下來的三格(題目、停止規則、報告)各自在擋一種統計上的錯。我寫了三個模擬,把這三種錯各自量出來。程式只用 numpy,下面依序貼進同一個檔案就能跑,一般筆電幾秒鐘跑完。

    想驗證的三件事

    1. 挑最高分會膨脹:候選組數越多,開發集上的第一名分數越高,就算每一組其實一樣好;換到沒看過的新題目,分數會掉回原形。
    2. 偷看會讓假陽性變多:每多幾題就看一次 p 值、顯著就停,宣稱「有差」的機率會遠高於表面上的 5%。
    3. 配對比較比較準:兩個模型答同一批題目時,用每一題的差異來算,標準誤會比把兩邊當成獨立樣本小,同樣的題數更容易看出真的差距。

    跑出來的結果如果和這三點不同,上面的說法就要改。

    前提假設

    模擬的好處是答案已知:我知道每一組設定真正的準確率,才量得出偏差有多大。代價是所有設定都是我給的,所以先攤開:

    實驗設定重跑次數

    (1) 挑最高分
    設定
    1 到 200 組設定,真實準確率全都是 70%;開發集 200 題;第一名再拿 500 題新題目重測
    重跑次數
    每種組數 2,000 次
    (2) 偷看 p 值
    設定
    A/A 測試:兩個完全相同的 Prompt,真實答對率都是 70%;每組每多 50 題看一次 p 值,p < 0.05 就停,最多 1,000 題
    重跑次數
    2,000 次
    (3) 配對比較
    設定
    兩個模型答同一批 200 題,題目難易差很多;B 真的比 A 好,平均高約 6.6 個百分點
    重跑次數
    2,000 次

    另外兩個前提:實驗 (1) 假設每一組設定答對與否彼此獨立;p 值用常態近似的雙尾檢定,這是比較兩個比例最常見的做法。

    思路與程式碼

    先放共用的設定:亂數種子固定為 16,所以你跑出來的數字會和文中一樣。p_value 把 z 分數換成雙尾 p 值。

    import numpy as np
    from math import erf, sqrt
    
    rng = np.random.default_rng(16)
    REPS = 2000          # repeat every setting 2,000 times
    TRUE_ACC = 0.70      # every configuration is truly 70% accurate
    
    
    def p_value(z: float) -> float:
        """Two-sided p-value under the normal approximation."""
        return 1 - erf(abs(z) / sqrt(2))
    

    實驗 (1) 模擬「k 組設定一起跑、挑開發集最高分」。每一組在 200 題上的答對題數,是一個二項分布的抽樣;max(axis=1) 就是排行榜第一名。最後再抽一份 500 題的新題目,代表第一名拿到保留集重測:因為每一組真實都是 70%,第一名換到新題目,就是另一次 70% 的抽樣。

    N_DEV, N_HOLDOUT = 200, 500
    for k in (1, 5, 10, 20, 60, 200):
        dev = rng.binomial(N_DEV, TRUE_ACC, size=(REPS, k)) / N_DEV
        best = dev.max(axis=1)
        print(f"(1) {k:>3} candidates: best on dev {best.mean():.1%}, reaches 75% in {(best >= 0.75).mean():.0%} of runs")
    holdout = rng.binomial(N_HOLDOUT, TRUE_ACC, size=REPS) / N_HOLDOUT
    print(f"    the winner on a fresh holdout: {holdout.mean():.1%}")
    

    實驗 (2) 是 A/A 測試:兩邊完全一樣,任何「顯著差異」都是假陽性。每多 50 題就做一次兩比例檢定,第一次 p < 0.05 就停下來宣布有差;同時記下「只在 1,000 題時看一次」的結果當對照。

    STEP, MAX_N = 50, 1000
    peek_hits = fixed_hits = 0
    for _ in range(REPS):
        a = rng.random(MAX_N) < TRUE_ACC
        b = rng.random(MAX_N) < TRUE_ACC
        for n in range(STEP, MAX_N + 1, STEP):
            pa, pb = a[:n].mean(), b[:n].mean()
            pool = (pa + pb) / 2
            if p_value((pa - pb) / sqrt(2 * pool * (1 - pool) / n)) < 0.05:
                peek_hits += 1
                break
        pa, pb = a.mean(), b.mean()
        pool = (pa + pb) / 2
        fixed_hits += p_value((pa - pb) / sqrt(2 * pool * (1 - pool) / MAX_N)) < 0.05
    print(f"(2) false positives: peek every {STEP} -> {peek_hits / REPS:.1%}, look once at {MAX_N} -> {fixed_hits / REPS:.1%}")
    

    實驗 (3) 讓題目有難有易:每一題有一個難度值,兩個模型答對的機率都隨難度變化,B 在每一題都比 A 好一點。不配對的標準誤把兩邊當成兩群獨立的人來算;配對的標準誤先算每一題的「B 減 A」,再看這 200 個差值的波動。

    N_Q = 200
    se_unpaired, se_paired, gaps = [], [], []
    win_unpaired = win_paired = 0
    for _ in range(REPS):
        difficulty = rng.normal(0, 2.0, N_Q)
        a = rng.random(N_Q) < 1 / (1 + np.exp(-(1.0 + difficulty)))   # model A
        b = rng.random(N_Q) < 1 / (1 + np.exp(-(1.5 + difficulty)))   # model B, truly a bit better
        diff = b.astype(float) - a
        su = sqrt(a.mean() * (1 - a.mean()) / N_Q + b.mean() * (1 - b.mean()) / N_Q)
        sp = diff.std(ddof=1) / sqrt(N_Q)
        gaps.append(diff.mean())
        se_unpaired.append(su)
        se_paired.append(sp)
        win_unpaired += diff.mean() / su > 1.96
        win_paired += diff.mean() / sp > 1.96
    print(f"(3) average gap {np.mean(gaps):.1%}; SE unpaired {np.mean(se_unpaired):.2%}, paired {np.mean(se_paired):.2%}")
    print(f"    B shown better at 95%: unpaired {win_unpaired / REPS:.0%}, paired {win_paired / REPS:.0%}")
    

    結果

    先看實驗 (1)。把每種候選組數的第一名分數畫出來:

    候選設定越多,開發集第一名虛增越高:60 組設定在開發集上第一名平均達 77.3%,但換到 500 題保留集重測即回跌至真實的 70.0%(資料來源:Sunny DataScience 模擬實驗,每種組數重跑 2,000 次)。

    只有 1 組時,開發集分數平均 69.9%,就是真實水準。候選變成 60 組,第一名平均 77.3%,而且 2,000 次模擬裡有 99% 的第一名超過 75%。這 7 個百分點全部是運氣:第一名拿到 500 題新題目重測,平均 70.0%。

    這個數字可以手算出來。200 題、答對率 70% 的分數,本身就有約 3.2 個百分點的標準誤(√(0.7 × 0.3 ÷ 200))。60 個獨立抽樣裡的最大值,平均落在中心之上約 2.3 個標準誤,70 + 2.3 × 3.2 ≈ 77.4,和模擬的 77.3% 幾乎一樣。候選越多,最大值離中心越遠,這就是挑最高分的膨脹。

    實驗 (2):每 50 題偷看一次、顯著就停,A/A 測試有 27.4% 會宣布「兩個 Prompt 有差」;只在 1,000 題看一次,是 5.9%,接近名目上的 5%。每偷看一次,就多一次被雜訊騙到的機會;20 次查看彼此相關,所以沒有膨脹到 64%(1 − 0.95²⁰),但也從 5% 變成了五倍多。

    實驗 (3):B 平均比 A 高 6.6 個百分點。不配對的標準誤是 4.63 個百分點,配對的是 3.67,小了約兩成。換成判斷力:在 95% 的水準下,不配對只有 25% 的模擬看得出 B 比較好,配對有 44%。原因是題目難易這份波動兩邊共享,相減之後就消掉了。但要注意,就算配對,200 題也只有不到一半的機會看出 6.6 個百分點的差距:題數該多少,要在跑之前算。

    回到想驗證的三件事,三件都成立:

    想驗證的事結果成立嗎

    挑最高分會膨脹
    結果
    60 組的第一名:開發集平均 77.3%,保留集 70.0%
    成立嗎
    成立
    偷看會讓假陽性變多
    結果
    每 50 題看一次 27.4%,只看一次 5.9%
    成立嗎
    成立
    配對比較比較準
    結果
    標準誤 4.63 → 3.67 個百分點;看出差距的機率 25% → 44%
    成立嗎
    成立

    這是模擬,數字只在這組設定下成立。可以帶走的是三個方向,和量它們的方法。你可以把題數改成 1,000、把候選組數改成 6,看膨脹縮小多少。

    OpenAI 停用 SWE-bench Verified:被反覆使用兩年的保留集,59.4% 難題有錯且已遭訓練污染

    公開的 benchmark,本質上是整個產業共用的保留集。實驗 (1) 講的事,在 2026 年 2 月發生在最有名的那一份上。

    SWE-bench Verified 是 OpenAI 在 2024 年 8 月整理的 500 題真實 GitHub issue,請模型修 bug,再用專案原本的測試判定修對沒有。發表後,它成了各家發表新模型時必報的分數。2026 年 2 月 23 日,OpenAI 宣布不再回報這項成績,理由有兩個,剛好對上設計卡的兩格。

    第一個是評分本身有問題。最佳成績在六個月內只從 74.9% 進到 80.9%,OpenAI 於是去查剩下的題目:挑出 o3 跑 64 次都沒能穩定解出的 138 題,每題至少六位資深工程師獨立審查,發現 59.4% 的題目在測試設計或題目描述上有實質問題,有的測試會擋下功能正確的解法,有的測試檢查了題目根本沒提到的功能。分數卡住的地方,有一大半是考卷出錯。

    第二個是保留集已經不再保留。題目來自公開的開源專案,各家都可能拿來訓練;OpenAI 測試的前沿模型都能重現部分題目的標準答案或題目細節,而看過題目的模型比較容易過關。OpenAI 的結論是,這份 benchmark 上的進步,越來越只反映模型在訓練時看過多少題目,不代表真實的寫程式能力。

    一份被全產業反覆使用兩年的保留集,最後量到的是大家看過它幾次。團隊內部的測試集也會走到同一步,只是沒有人會替你發公告。

    實務落地五個決定:分層抽樣、鎖定保留集、校正評審偏誤、定好停止規則與交代配對差異

    把上面的機制落到一次真的 LLM Eval,大致是五個要事先決定的事,順序就是設計卡的順序。

    決定一:題目怎麼抽

    測試集要從產品真正會遇到的問題抽出來,而且要分層。以文件問答為例,先列出題型:簡單問答、跨文件整合、資料不足應該拒答、需要引用原文位置。每一層各抽一定題數,讓小題型也有足夠的題目可以單獨看;總分再依實際流量的比例加權。

    只從過去答得好的案例抽樣,分數會很漂亮,但回答不了上線後最棘手的問題。拒答題尤其容易被漏掉,因為它在日誌裡看起來像「沒有答案」。

    決定二:開發集和保留集怎麼切、多久換

    開發集讓團隊每天看、每天改 Prompt;保留集鎖起來,只在要做決定時打開,例如上線前,而且每打開一次都記下來。Dwork 等人 2015 年在《Science》的研究說明了原因:同一份保留集被反覆查詢,選出來的方案會開始貼合保留集本身。

    保留集也要輪替。定期從最新的產品日誌補進新題目、汰換舊題目,避免它和實驗 (1) 的開發集一樣,被看熟了。保留集一旦被拿來挑方案,那一輪的結論就降級成探索性結果,下一輪再用新題目確認。

    決定三:誰來評分

    能用規則判定的就用規則,例如有標準答案的題目或單元測試;但規則本身也要查,SWE-bench Verified 就是測試寫錯的例子。開放式的答案,越來越多團隊用另一個 LLM 當評審。Zheng 等人 2023 年的研究發現,GPT-4 當評審時和人類的一致率超過 80%,和人與人之間的一致程度差不多;同一篇研究也列出它的偏誤:偏好排在前面的答案、偏好比較長的答案、偏好自己產生的答案。

    評分方式適合要小心

    規則比對(標準答案、單元測試)
    適合
    有明確對錯的題目
    要小心
    規則本身可能寫錯,或比題目要求得更多
    人工標註
    適合
    建立基準、開放式答案
    要小心
    慢又貴,標註者之間也會不一致
    LLM 當評審
    適合
    大量開放式答案
    要小心
    位置、長度、自家模型三種偏誤
    LLM 評審加人工抽查
    適合
    多數團隊的預設
    要小心
    抽查比例要固定,評審模型換了就重算一致率

    實務上的做法:兩兩比較時把答案順序對調再評一次,兩次一致才算數;評審不要和受測模型同一家;定期抽一批題目給人工標註,算評審和人的一致率,一致率不夠就先別相信評審給的排名。人工標註也一樣,先給標註者相同的判準,再抽一部分重複標,看分歧集中在哪些題型。評分者自己都判不一致時,精確到小數點的排名只是看起來精確。

    決定四:什麼時候停

    實驗 (2) 說明了「看到顯著就停」的代價。停止規則有幾種寫法:

    停止規則怎麼做代價

    固定題數
    怎麼做
    事先估要測幾題才看得出想要的差距,測完才看
    代價
    最乾淨,但要先估差距多大
    每批都看,顯著就停
    怎麼做
    實驗 (2) 的做法
    代價
    假陽性從約 5% 變成 27%
    序列檢定
    怎麼做
    用專為反覆查看設計的方法,例如 Johari 等人提出的 always-valid p 值
    代價
    可以提早停,但方法要事先選好

    候選組數也算在停止規則裡:事先寫下要比幾組,跑到一半想加新組合,就記下來,報告時一起交代。實驗 (1) 已經量過,組數本身就會把第一名推高。

    決定五:報告怎麼寫

    報告的目的是讓讀者判斷這次比較能支持多強的說法。Anthropic 2024 年整理的模型評估建議是同一個方向:分數旁附標準誤;比較兩個模型時,用同一批題目算配對差異;用檢定力分析決定需要幾題。一份 Eval 報告至少交代:

    • 總分與 95% 信賴區間,以及和基準版本的配對差異
    • 各層的分數與題數,退步的層要列出來
    • 一共試了幾組才挑出這一組
    • 評分方式,以及評審和人工抽查的一致率
    • 保留集這次是第幾次打開

    Anthropic 那篇建議用一張圖說明「分數旁附標準誤」的理由:Eval 的題目只是所有可能題目裡抽出來的一批,換一批,分數就會跟著動。

    Anthropic 用這張圖說明分數為什麼要附標準誤:同一個模型換一批題目,分數就可能從 72 跳到 91;只報一個數字,讀者看不出這次比較的把握有多大。(圖片來源:Anthropic〈A statistical approach to model evaluations〉,經 Sunny DataScience 中文重點標註)

    切片看到落差時,小切片樣本少、波動大,先回頭檢查題目與不確定性,不急著宣稱某群使用者受益或受害。

    避開「分岔小徑」的多重比較風險:看資料才發現的切片標為探索,留給新題目驗證

    Gelman 與 Loken 把一種常見的處境叫做「分岔小徑」:就算只做了一次分析,只要分析方式是看過資料才決定的,結論就帶著多重比較的風險。

    所以探索時才發現的新切片,不用假裝它不存在,也不能當成原本的假設。把它標成「後來發現」,記下為什麼值得追,下一輪用新題目驗證。團隊照樣能從意外裡學到東西,又不會把意外包裝成早就預測到的勝利。

    設計卡也有不必寫得那麼重的時候。探索期每天改 Prompt、看開發集,本來就是在偷看,只要結論標成探索、不拿去做上線決定就好。差距大到二十個百分點、怎麼看都看得出來時,統計細節的影響也小。真正需要整張卡的,是那些差距只有幾個百分點、又要拿去做上線或採購決定的比較。

    結論:實驗跑得越便宜第一名裡的運氣越多,跑之前先定好標準才不會把雜訊當進步

    六十組實驗,一個下午跑得完。實驗 (1) 已經算給你看:所有組其實一樣好,第一名在開發集上平均還是多出 7 個百分點。跑得越便宜,這份運氣越常被當成進步。

    實驗跑得越多,第一名裡的運氣就越多。

    回頭看你們現在的測試集:它被拿來挑過幾次方案?如果你正在考慮換模型,可以接著讀〈新模型出來了要不要換?AI 功能答錯時,換模型多半沒用(2026 除錯懶人包)〉。

    常見問題

    用 LLM 當評審(LLM-as-a-judge)可靠嗎?

    可以用,但要防三種偏誤。Zheng 等人 2023 年的研究發現,GPT-4 當評審和人類的一致率超過 80%,和人與人之間差不多;它也偏好排在前面、比較長、自己產生的答案。實務上,兩兩比較時把順序對調再評一次,評審不要和受測模型同一家,定期抽題給人工標註、算一致率。

    A/B 測試為什麼不能每跑一批就看一次 p 值?

    每看一次,就多一次被雜訊騙到的機會。在一組模擬裡,兩個完全相同的 Prompt(真實答對率都是 70%)每 50 題看一次 p 值、顯著就停,有 27.4% 會宣布「有差」;只在 1,000 題時看一次是 5.9%。要嘛事先估好題數、測完才看,要嘛改用序列檢定,它在設計時就把反覆查看算進誤判機率。

    LLM Eval 的保留集(holdout)要怎麼用?

    開發集讓團隊每天看、每天改 Prompt;保留集鎖起來,只在上線前這類要做決定的時候打開,每打開一次都記下來。Dwork 等人 2015 年在《Science》的研究說明,同一份保留集被反覆查詢,選出來的方案會開始貼合它本身。保留集要定期從最新日誌補新題、汰換舊題。

    OpenAI 為什麼不再回報 SWE-bench Verified 的成績?

    SWE-bench Verified 是 OpenAI 2024 年整理的 500 題真實 GitHub issue。2026 年 2 月 OpenAI 宣布不再回報這項成績,理由有兩個:審查 138 道難題後,59.4% 在測試設計或題目描述上有實質問題;題目來自公開專案,前沿模型能重現部分標準答案,分數越來越反映看過多少題。

    延伸閱讀

    參考資料

    留言0

    登入後就能留言。

    登入
    sunny 桑尼
    sunny 桑尼

    AI 資料科學 · 產品經理 · 蒙奇 D 桑尼

    專注於 AI 工具應用與資料科學教育,致力於讓每個人都能用 AI 提升工作效率。曾任職於科技業,現為全職教育創作者。

    讀更多文章 →想自己動手試?領免費 Starter Kit →