同一個 Prompt,為什麼這次跑對上次跑錯:LLM 推論的非確定性與工程對策
在生產環境裡,最折磨人的 bug 往往不是報錯,而是「時靈時不靈」:同一個 prompt,連發五次,兩次答對,三次答錯。這背後不是玄學,而是 LLM 推論裡幾個可以量化的機制。

同一個 Prompt,為什麼這次跑對上次跑錯:LLM 推論的非確定性與工程對策
在生產環境裡,最折磨人的 bug 往往不是報錯,而是「時靈時不靈」:同一個 prompt,連發五次,兩次答對,三次答錯。這背後不是玄學,而是 LLM 推論裡幾個可以量化的機制。
溫度、Top-p:隨機性從哪裡來
採樣參數直接決定輸出的隨機程度。temperature=0 只是把 argmax 變成確定的選擇路徑,但只要存在浮點數捨入、batch 尺寸變化或不同硬體後端,底層 logit 可能有微小差異,輸出仍可能漂移。top_p 截斷會讓「第二選項」有機會上位,當第一名和第二名的機率很接近時,換一次採樣結果就翻轉了。工程上的第一個對策:把 temperature 和 top_p 寫進設定並納入版本管理,而不是散落在呼叫程式碼裡。復現問題之前,先確認「這兩次請求的參數真的相同」。
再往下一層看,softmax 前的 logit 差值才決定翻轉機率。假設第一名 51%、第二名 49%,無論溫度怎麼調,兩次採樣之間出現翻轉都是常見事件;而第一名 95%、第二名 5% 時,結果基本穩定。也就是說,「同一個 prompt 有時對有時錯」往往說明任務處在模型能力邊界上,prompt 本身需要更強的約束(範例、格式、判據),而不是單純調採樣參數。調參數治標,改任務定義才治本。
批次處理和硬體引入的擾動
推論引擎裡,continuous batching 會讓同一請求和不同請求拼進同一個 batch,GPU 上的浮點數累加順序隨之改變。結果就是:同一個模型、同一台機器、同一個 prompt,不同時間點的輸出可能不同。這類差異通常是輕微的措辭變化,但一旦下游用正規表示式或字串比對解析輸出,輕微措辭變化就會變成解析失敗。對策是兩層:解析層不要依賴「恰好是這個詞」,用結構化輸出(JSON schema、函式呼叫)加校驗重試;如果業務要求嚴格復現,就要固定 batch 行為(比如獨佔 batch)或接受「輸出會變」這個前提去做容錯設計。
快取命中路徑不一致
KV cache 複用、前綴快取、投機解碼,這些加速機制會讓「同一段輸入走不同的計算路徑」。大部分實作能保證數值近似一致,但近似不等於相等。做 A/B 對比或離線評測時,一個常見坑是:評測跑在無快取的冷啟動路徑上,線上跑在熱快取路徑上,兩邊結果分佈不一樣,結論就偏了。最小可行做法:評測環境和線上環境用同一套推論設定,並在報告裡註明快取狀態。
重試不是萬靈丹
「錯了就重試三次」是成本最低也最危險的對策。它把偶發錯誤變成成本波動:錯誤率 5% 時,重試三次能把單請求成功率提到 98.75%,但平均成本接近 1.15 倍,且每次重試都要重新付整條 prompt 的 token 費。更穩的做法是給重試加「記憶」:第二次重試時把第一次的失敗輸出附進 prompt(「上一次回答錯在 X,請修正」),這類 self-correction 在有明確判據的任務上有效,在開放式任務上收益有限。判據越明確(可執行測試、schema 校驗、關鍵字核對),重試策略越值得投入。
一個可執行的檢查清單
1. 固定並版本化 temperature、top_p、seed(如後端支援);
2. 解析層用結構化輸出 + 校驗,不靠字串比對;
3. 評測與線上同設定,報告註明快取狀態;
4. 重試帶失敗上下文,並設上限(建議 2 次);
5. 對「時靈時不靈」的請求保留完整請求/回應日誌,先復現再優化。
非確定性消除不了,但可以把它關進籠子裡:讓它在措辭層面抖,而不是在正確性層面抖。
留言區
歡迎分享你的想法!
載入留言中…