程式碼持有閾值,模型只給機率
如果把幾百個真實專案放在一起看,最穩定的一條共同點是:
模型只負責回答「有多可能」,程式碼負責回答「夠了沒有」。
這不是風格偏好。它是從模型自報的置信度不可信這個事實裡推出來的唯一穩妥做法 —— 而這一點在置信度到底可不可信那篇裡有獨立的實測證據。
具體長什麼樣
Choice 與 Score 返回答案時附帶一個 confidence,Noul 直接返回 0 到 1 的機率。
介面本身不替你做任何判斷,閾值是你的。真實專案裡這句話落實成了很具體的形態:
- 一個跑在 Cloudflare Worker 上的髒話過濾器,閾值、
max()的聚合策略、以及 對外的 OpenAPI schema 全都寫在 Worker 程式碼裡,模型只是其中一個被呼叫的函式。 - 一個瀏覽器擴充套件用它判斷評論是否要遮起來,擴充套件自己釘著 0.85 / 0.7 / 0.5 三檔, 並且檢查失敗時保持遮住(寧可多遮,不可漏遮)—— 這也是閾值策略的一部分。
- 一個工單告警分流器把「要 page」定義成
P(SEV1) + P(SEV2) ≥ 0.80, 這個 0.80 寫在它自己的配置裡,不在模型裡。
三者的共同點是同一個:換模型時閾值不動,換閾值時模型不動。 把閾值交給模型去「決定」的話,這兩件事就綁在一起了 —— 而你要調閾值的時候, 會發現自己在改一個提示詞。
為什麼這條原則這麼重要
因為它把兩種失敗分開了:
- 模型回答得不好 —— 去改問題、改 state、換模型。
- 閾值定得不好 —— 去改程式碼裡那個數。
混在一起之後,一個「準確率不夠」的問題既可能是模型的問題也可能是閾值的問題, 而你沒有任何辦法把它們分開。上一條的告警分流器之所以敢把 0.80 直接寫進配置, 正是因為那個數可以被單獨拿出來復盤、單獨拿出來調。
反例:置信度不總是它看起來的那個東西
這條原則有一個必須知道的前提:你拿到的那個數,未必是校準過的機率。
有獨立復算發現,Score 題返回的 confidence 經常正好等於分數的小數部分,
而且這類輸出高度集中(在 121 個這樣的輸出裡)。這不是「模型很自信」,
更像這個欄位是從分數本身推匯出來的一個值。
區別很大:
- 如果它是校準過的機率,那麼 0.85 可以用在「85% 的情況下我會是對的」這種推理裡。
- 如果它是分數的函式,那麼 0.85 只表示「這一題得了高分」,和「我有多大機率對」 沒有關係 —— 拿它去定閾值,是在給一個沒有機率含義的數設門檻。
同樣地,有一篇獨立的測量報告直接去核對模型自報的欄位與真值是否相符, 結論是那些欄位的取值遠沒有描述裡寫的那麼細(詳見公開質疑)。
怎麼辦
實踐裡的做法可以歸納成三步,而且順序不能反:
- 先用閾值做事,別信它的含義。 0.8 這個數是不是「80% 正確」不重要 —— 重要的是在你的資料上,0.8 以上的那些是不是明顯更準。這是可以用留出集驗的。
- 用你自己的標註擬合閾值。 有工具專門做這件事:拿你自己的標註資料, 為每個問題擬合出「達到目標準確率所需的閾值」,用留出集驗證, 並且當模型更新破壞了已鎖定的閾值時讓 CI 失敗。
- 把閾值鎖進程式碼,並給它一個複核日期。 閾值會隨著模型版本過期 —— 和價格一樣,是要有人定期回頭看的東西,不是一次定終身。
一句話
模型的可信度應該體現在你的閾值上,而不是體現在它的自報數字上。 你可以在自己的資料上度量前者,沒法度量後者。