TL;DR:網路上很常看到一句建議——要 AI 每次給一樣的答案,把 temperature 設成 0 就好。聽起來天衣無縫:temperature 0 就是叫它每次都挑機率最高的字,沒有隨機,那不就該每次一樣?但實際上不是。有人拿同一個 prompt、temperature 0 連跑 1000 次,還是跑出 80 種不一樣的輸出。原因不是「浮點誤差」這麼簡單,而是你的請求在 GPU 上跟多少別的請求湊成一批一起算,會偷偷改掉算術的順序。最確定,不等於可重現。
「想讓 AI 每次都給一樣的答案?把 temperature 設成 0 就好。」這句建議在網路上幾乎是標準答案,而且乍看完全合理——temperature 0 就是把那層隨機性整個關掉,關掉了不就每次都一樣?
這也是上一篇 為什麼同一個問題問 AI,每次答案都不一樣? 很自然會接到的下一步——那篇講它預設在照機率抽籤、所以會飄,那把那層隨機關掉不就得了。
這話幾乎是對的——壞就壞在「幾乎」。真的拿去跑跑看,它會破在一個意外的地方。
把溫度關到底,它還是會變
2025 年 Thinking Machines Lab 有一篇 Defeating Nondeterminism in LLM Inference,就老老實實去測了這件事。他們拿同一個 prompt、temperature 設成 0——理論上最「確定」的設定——對同一個模型連跑 1000 次。結果跑出 80 種不一樣的輸出。而且不是一開始就亂,前面都一樣,一路到第 103 個 token 才開始分岔。
也就是說,你把那個「隨機」的旋鈕轉到底了,它照樣給你 80 個版本(多半是同個意思的不同寫法,不是答案在對錯之間跳)。所以問題顯然不在 temperature。隨機性早就關了,那這個「變」是哪來的?
不是浮點誤差這麼簡單
這時候最常聽到的解釋是「喔那是浮點誤差啦」。這個答案對一半、偷懶一半,而且偷懶的那半剛好是重點。
浮點數確實有個怪脾氣:它的加法不符合結合律。白話講就是 (a+b)+c 跟 a+(b+c) 算出來可能差那麼一點點——電腦處理小數本來就會在尾巴留一點誤差,加的順序一換,誤差就落在不一樣的地方。這是地基沒錯。但光有這個地基,還不足以讓你每次結果不一樣。因為假如每次「加的順序」都固定,那誤差也會每次都一樣,結果照樣可重現。
真正的扳機,是那個順序其實沒固定。
它跟多少人擠在一起算,你管不到
關鍵在它是「怎麼被算出來的」。你以為你送一個請求進去,它就單獨幫你算——其實沒有。為了效率,伺服器會把同時湧進來的一堆請求湊成一批(batch)一起算。而這一批有多大,是隨時在變的:當下多少人在用、你的請求剛好跟多少別人的湊在一起,每次都不一樣。而批次的大小一變,GPU 為了算這一批,會用不一樣的方式把工作切開、把一長串數字分段加總——也就是負責矩陣運算的那個 kernel,把數字加起來的順序變了。順序一變,前面講的浮點誤差就落在不同位置。
多數時候這點誤差沒差。但偶爾——兩個候選字機率咬得很近的時候——這一丁點誤差剛好就把原本的第一名擠下去,換成第二名上場。一個 token 一變,後面整串就順著岔開了。
所以它不是真的在「隨機」,而是有一件你完全插不上手的事在左右你的答案:這一瞬間,機房裡有多少人在跟你擠同一張卡。temperature 0 關掉的是「主動抽籤」那層,可是這層藏在運算底層的飄移,它根本沒碰到。
那修得好嗎?修得好,但要花力氣
能修。Thinking Machines 那篇後半就是去做這件事:把那幾個關鍵 kernel 改寫成「不管批次怎麼湊,算術順序都固定」(他們叫 batch-invariant)。改完之後,同樣 1000 次,真的就 bitwise 完全一致了。代價是慢一點,但對真的需要可重現的場景(像他們在意的強化學習訓練)划得來。
重點是這個:可重現不是預設就附贈的東西,是要有人特地去把它釘死。把 temperature 設 0、打個勾,並不會自動到手。(也補一句:這種飄主要是線上這種多人共用的服務才明顯;你在自己機器上、把批次固定好跑開源模型,其實常常是能重現的——所以這不是「LLM 天生就不可能一樣」,是「線上服務的預設沒幫你保證」。)
那實際上該記得什麼
講這麼多底層,對日常用 AI 其實就收成一句很實用的話:別把「我跑一次、它對了」當成「它每次都會這樣」。連最確定的設定都不保證一字不差,更別說你平常根本沒在關隨機。
如果你拿 AI 做的事需要「同樣輸入、同樣輸出」——核對一個答案、跑一段自動化流程——那層保證得你自己另外想辦法(把要求講死,或乾脆用程式兜住),不能假設它天生就穩。這跟我在 AI 說「完成了」,怎麼確認它真的做完? 裡那條囉嗦的習慣是同一個道理:它這次對,只能算這次對。


