Prompt 消融實驗:結果變好後,我才知道自己還不知道哪個改動有效
一次內部評估裡,系統表現明顯改善;但同時改了多個地方的 before/after,不能直接說明因果。這是我如何用 2×2 消融,重新看待 Prompt 改版的方法。

TL;DR
- 改版後結果變好,不等於知道是哪一項改動有效。
- 同時修改多個 Prompt 因素時,單看 before/after 無法判斷因果。
- 把「結構」與「情境規則」拆成 2×2 組合重跑,才看得出各自在什麼條件下有幫助。
- Prompt 優化的重點不是規則愈多愈好,而是清楚知道每條規則的適用範圍與影響。
- 保留可重跑的測試資料、Prompt 組裝方式與評分規則,才有辦法讓結論被驗證。
這是一個我做完覺得十分有趣的實驗,它把所有變因拆開,接著排列組合,再把這些結果拿出來一一比較,才看見較可靠的改善歸因,但這也不是一開始就想到,而是做完第一輪實驗後,發現不太合理,才回頭補做這個驗證。
日前在處理系統誤報率時,我曾經把一組內部評估的誤報問題明顯壓下來。第一眼看到結果時,我很想替它寫下一句結論:Prompt 調好了,但我後來發現,這個結論言之過早。
因為同一輪裡,我們同時動了輸出結構、共用判讀規則和情境規則。如果只比較改版前後,任何一項都可能被錯誤地冠上功勞。真正重要的問題不是「有沒有變好」,而是:到底是哪一個改動讓它變好?
這篇不公開任務類型、資料內容、模型、實作架構或原始數字;我想保留的是其中可複用的驗證方法:當 Prompt 一次改了很多地方時,怎麼避免把相關性誤寫成因果。
我們同時改了結構、共用規則和情境規則
有些 AI 任務看起來像是分類問題,實際上卻同時包含好幾層判斷。
模型不只要辨識輸入,還要理解哪些狀態是可接受的、哪些狀態需要保守處理、輸出要如何符合系統規格。只要其中一層沒有說清楚,模型就可能把「不確定」或「看起來不同」誤當成需要升級處理的事件。
當時我們同時調整了幾個地方:
- 讓輸出結構更固定,減少模型為了填完格式而自行補出判斷。
- 重整共用規則,讓模型知道哪些條件必須優先確認。
- 加入特定情境下的正常基線與排除條件。
改完後,誤報確實降低了。
- 改動 01輸出結構固定輸出契約,減少自行補出判斷
- 改動 02共用判讀規則重整必須優先確認的條件
- 改動 03情境規則加入正常基線與排除條件
功勞屬於哪一項?只比較 before/after 無法回答。
但「整包改完再看結果」只能告訴我們結果變了,不能告訴我們下一次應該保留什麼、重寫什麼,或哪一條規則其實不值得帶到別的情境。
用四種組合重跑同一批資料
所以我們把這次修改先抽象成兩個因素:
- 結構因素:輸出契約與共用判讀邏輯的新版結構。
- 情境因素:只針對特定使用條件加入的正常基線與排除規則。
接著,我們將已確認為正常的一組測試資料,放進四種組合重跑:
- 舊結構 + 舊情境規則:誤報明顯,無法接受。
- 新結構 + 舊情境規則:誤報下降,但仍未降至可接受範圍。
- 舊結構 + 新情境規則:在這組測試資料上,誤報被壓到可接受範圍。
- 新結構 + 新情境規則:同樣維持在可接受範圍。
我刻意省略資料量和實際數字,因為它們屬於內部專案內容;不過四種組合的關係,已經足以支持一個較精確的判斷。
在這組已確認為正常的測試資料、這四個版本與既定的誤報門檻下,新版結構有幫助;新情境規則才是能否達標的關鍵。這不代表所有任務都需要同一條規則,也不代表結構對其他指標沒有價值。
只要保留情境規則,即使沒有使用新版結構,結果仍能維持;反過來,只換結構而不補足情境基線,問題雖然變小,卻沒有真正消失。
假設 AI 把正常包裹判成異常
假設我要請 AI 檢查包裹,測試用的 100 件都已經由人確認正常。只要 AI 把其中一件判成異常,就算一次誤報。
包裹情境、數字和門檻都是為了說明方法而假設的,與內部專案無關,也沒有還原原始實驗。這裡先訂一個目標:100 件正常包裹中,誤報不超過 5 件。
在這個例子裡,我想試兩種改法:
- A 是新結構:把回答整理成「觀察到什麼 → 有沒有符合異常條件 → 最後判定」,希望模型先檢查條件,再下結論。
- B 是新情境規則:告訴模型「外箱有配送用貼紙是正常的,不能只因為有貼紙就判定異常。」補上這條,模型才知道這種情況可以接受。
A 像是把檢查表排清楚,B 則是告訴檢查員哪些情況本來就沒問題。檢查表排得再整齊,檢查員如果不知道配送貼紙是正常的,還是可能把它當成瑕疵。
情境 ↓舊結構新結構 A舊情境
規則
規則 B
橫向比較:情境不變,只換結構。
縱向比較:結構不變,只換情境規則。
四個結果分別是:都不改,誤報 30 件;只改 A,12 件;只改 B,4 件;兩者都改,3 件。接下來的每一張圖,都用這同一組數字。
先改 A 或先改 B,算出來的貢獻不同
我們原先高估新版結構的貢獻,就跟修改順序有關。套用到包裹的例子,會是下面這種情況。
如果我先換 A,再加入 B,我看到的路徑是 30 → 12 → 3。第一步少了 18 件誤報,第二步又少了 9 件。我很容易寫成:「結構貢獻 18 件,情境規則只貢獻 9 件,所以結構比較重要。」
18 件和 9 件都算對了,但不能就這樣認定 A 比 B 有用。測 A 時還沒有 B;測 B 時,A 已經先減少了一部分誤報。B 能改善的是剩下的問題,兩者的比較條件不同。
如果先改 B,再改 A,路徑就變成 30 → 4 → 3:B 先減少 26 件,A 後來只再減少 1 件。四個版本都沒變,只是換個順序比較,這次就變成 B 的貢獻比較大。
路徑一:先 A,後 B
路徑二:先 B,後 A
兩條路都從 30 到 3,總共少 27 件。
加入同一項改動,先加或後加,改善件數也會不同。
想像兩個人整理同一間房間。第一個人進去時東西還很亂,收掉大半後,第二個人能收的就少了。不能只看各自收了多少,就說第二個人比較不會整理。這個比喻對應的是比較條件不同;實際測試時,每個 Prompt 版本都是各自跑同一批資料。
A 單獨少 18 件誤報,B 單獨少 26 件,兩個一起用卻只少 27 件,不能直接把 18 + 26 加起來。它們可能改善了部分相同的問題,但光看總件數,還不知道是哪幾件重疊,也不能確定原因。
不過,先改的項目也不一定佔便宜。有些改動要搭配另一項才有用,後加入的反而可能改善更多。只照一種順序測,就看不到換個順序後會怎樣。
固定其他條件,再比較每項改動的效果
有了四種組合,我就可以固定一個因素,看看另一個因素改了以後差多少。每個因素都有兩次比較:
- 沒有新情境規則時,換結構:30 → 12,少 18 件。
- 已有新情境規則時,換結構:4 → 3,只少 1 件。
- 沒有新結構時,換情境規則:30 → 4,少 26 件。
- 已有新結構時,換情境規則:12 → 3,少 9 件。
這四個差值都算得出來,先看哪一格都一樣。結構在沒有情境規則時,能少 18 件誤報;有了情境規則後,只再少 1 件。同一項改動的效果會隨另一項改動而變,這就是這個例子裡的交互作用。
也可以從兩者都改的完整版開始,每次拿掉一項,檢查剩下的版本還能不能達標。
只拿掉 A
4 − 3 = 多 1 件
仍然達標
只拿掉 B
12 − 3 = 多 9 件
不再達標
左右分開測,每次都從完整版開始。
測完拿掉 A 的版本,先還原 A,再測拿掉 B。
拿掉 A、保留 B,誤報從 3 件變成 4 件,仍達標。另一次回到完整版,拿掉 B、保留 A,誤報從 3 件變成 12 件,就不達標。測完拿掉 A 的版本後,要回到完整版,再測拿掉 B 的版本。如果一路拆下去,第二次的比較條件又變了。
在這個例子裡,少了 B 就過不了門檻,所以要達標,保留 B 更重要。不過,拿掉 A 多 1 件、拿掉 B 多 9 件,加起來的 10 件和整體改善的 27 件對不上。這很正常:消融回答的是「其他改動還在時,少了這一項會差多少」,無法直接把全部 27 件分配給 A 和 B。
原本的內部實驗也是補齊四格後,我們才發現先前把結構的貢獻看得太高。在那組正常資料和誤報門檻下,補足情境基線更重要。至於結構裡的輸出契約、共用判讀邏輯,這輪仍是放在一起測;想知道各自的影響,還得再拆開比較。
下次記錄改善件數時,我會把比較的兩個版本一起寫下來,免得過一陣子只記得少了幾件,忘了當時是怎麼比的。
把 Prompt 規則分成全域、共用和情境三層
這次之後,我不再把 Prompt 想成一段可以愈寫愈長的文字。
比較合理的做法是把它拆成幾層:
- 全域規則:所有情境都必須遵守的定義與邊界。
- 共用規則:輸出格式、判讀順序,以及模型應保留不確定性的時機。
- 情境規則:只在特定條件下才成立的正常基線、排除條件與覆寫規則。
這樣做不只是為了讓設定檔看起來更整齊,也能讓它更容易維護與擴充。更重要的是,它迫使我們回答一個很實際的問題:某條規則解決了眼前問題後,它會不會悄悄影響到其他情境?之後會有另一篇文章談談我遇過的另一個問題,發現 Prompt 已經改到極限了怎麼辦?
如果不知道一條規則的適用範圍,就很難全然放心地複用它,要據此下決策也容易被挑戰,明明花了時間做實驗,卻說不清楚為何要這樣做。
下次改 Prompt 時,我會留下哪些紀錄
這次沒有讓我得到一個「萬用 Prompt」,反而讓我多了一個比較慢、但可靠的工作流程:
- 先把要解決的錯誤類型寫清楚,不讓單一總分掩蓋真正的風險。
- 修改 Prompt 時,記下每個改動想處理什麼;不要一次加入太多無法拆開的修補。
- 先用 before/after 看整包改版有沒有改善;要分辨兩個改動各自的影響,再補齊 2×2。四組用相同的測試資料、模型版本、生成設定和評分方式,分散或隨機安排執行順序,再重跑幾輪,看差異是否穩定。
- 將測試資料、Prompt 組裝方式、模型版本與評分規則一起保存;存下 Prompt 文字,不等於存下實驗。詳細實驗經驗請看 LLM 模型選型怎麼做?快 8–10 倍,為什麼我們還是放棄了這個設定。
- 01定義錯誤類型不讓單一總分掩蓋真正的風險
- 02記錄改動目的不一次加入無法拆開的修補
- 03保留對照組至少 before/after,或 2×2 組合
- 04保存整套實驗測試資料、Prompt 組裝、模型版本、評分規則
誤報降低後,還要檢查漏報
- 這次只測正常樣本,看得到誤報,卻不知道模型會不會漏掉真正的異常。還要放入已確認的異常樣本,檢查漏報。畢竟模型全部回答「正常」,誤報也會是零,但異常就全漏掉了。
- 一組內部測試結果,不足以推論到所有任務或情境;單次相差一兩件,也可能只是模型輸出的波動。
- 局部改善,不等於整個系統的品質、成本與可靠性都已改善。
- 消融實驗能協助定位改動的影響,但不能替代正式驗收、長期監測或使用者回饋。
但我覺得,這些限制反而是方法真正有價值的地方。
它讓我們知道這輪實驗回答了什麼,也知道下一輪還缺什麼。
結果變好當然值得高興;但如果不知道它為什麼變好,下次遇到相似問題時,我們還是只能靠運氣重來一次。
如果你也曾遇過「改版後變好了,但不知道是哪一段救了你」的情況,歡迎到 Threads 和我交流。
延伸閱讀:完整因子設計
這種四格對照在實驗設計裡,屬於兩個因素、各有兩種設定的完整因子設計。四種組合都測過,才能比較一個因素的效果會不會隨另一個因素改變。想多了解這個方法,可以看 NIST:Full factorial designs。