你大概調過這幾個參數。OpenAI、Claude、還是本地跑的 Llama,API 文件裡總會列著 temperature、top_p、top_k,旁邊寫一句「控制隨機性」就沒了。
於是你把 temperature 調高一點,輸出真的變亂了;調低一點,又變得死板。但到底發生了什麼事?這三個東西看起來都在「控制隨機性」,那它們是不是在做同一件事?只是換個旋鈕?
不是。它們動的是同一條生產線上的不同工序。要看懂差別,得先知道一件事:模型生成文字的時候,根本不是在「想答案」,而是在抽籤。
模型每吐一個字,都在抽一次籤
語言模型一次只產生一個 token。它的運作方式是這樣:給定目前已經有的文字,模型會對「下一個 token 可能是什麼」算出一整張機率表。
假設你輸入「今天天氣真」,模型內部算出來的可能長這樣:
好 → 60%
熱 → 20%
不錯 → 12%
糟 → 5%
藍 → 0.5%
香蕉 → 0.0001%
...(後面還有幾萬個 token,機率趨近於 0)
注意,模型給的是一整張機率分布,不是一個答案。真正決定「這次到底要選哪個字」的,是另一個步驟——取樣(sampling)。
最笨的取樣法是「永遠選機率最高的」,也就是每次都挑「好」。這叫 greedy decoding(貪婪解碼)。問題是,這樣模型會變得完全固定:同樣的輸入,永遠吐同樣的輸出,毫無變化,而且很容易卡進重複的鬼打牆。
所以實務上會「按機率抽」——機率 60% 的「好」有六成機會中籤,20% 的「熱」有兩成機會。這樣輸出才有變化。
Temperature、Top-K、Top-P 三個參數,全都是在動這張機率表,或動這場抽籤怎麼抽。 搞清楚這點,剩下的就好懂了。
Temperature:把機率表拉平還是拉尖
temperature(溫度) 控制的是這張機率表的「對比度」。
想像那張表是一座山。機率高的字是山峰,機率低的字是山腳。temperature 做的事,就是調整這座山的陡峭程度。
- 溫度低(例如 0.2):山變得又高又尖。本來 60% 的「好」可能變成 90%,其他選項被壓到趨近於 0。抽到「好」幾乎是必然——輸出變得保守、可預測。
- 溫度高(例如 1.5):山被壓扁攤平。「好」從 60% 掉到剩 35%,原本沒機會的「藍」「糟」開始浮上來。輸出變得發散、有創意,但也更容易語無倫次。
原始分布 低溫 (0.2) 高溫 (1.5)
好 60% 好 90% 好 35%
熱 20% 熱 8% 熱 22%
不錯 12% 不錯 2% 不錯 18%
糟 5% 糟 ~0% 糟 14%
藍 0.5% 藍 ~0% 藍 11%
關鍵在於:temperature 不刪掉任何選項,它只是調整大家的相對機率。 「香蕉」就算在高溫下,機率還是低到幾乎不可能中——它只是把每個選項之間的差距放大或縮小。
一個常見的特例:temperature = 0。這等於把山拉到無限尖,永遠只剩機率最高的那個,效果就跟 greedy decoding 一樣。所以你想要模型「每次都給一樣的答案」,就把溫度設成 0。
Top-K:只留前 K 名,其他直接淘汰
Temperature 是調整每個選項的機率,但所有選項都還在牌桌上。top-k 換了個思路:先把候選名單砍短。
Top-K = 5 的意思是:只保留機率最高的前 5 個 token,剩下幾萬個全部丟掉,然後只在這 5 個裡面抽籤。
Top-K = 3,只留前三名再抽:
好 60% ✓ 留下
熱 20% ✓ 留下
不錯 12% ✓ 留下
─────────────── 砍掉這條線以下全部
糟 5% ✗ 淘汰
藍 0.5% ✗ 淘汰
香蕉 ... ✗ 淘汰
被留下的前三名會重新算一次比例(讓三者加起來等於 100%),然後在它們之間按機率抽。
好處很直接:那些超低機率的離譜選項,從一開始就沒機會出現。 模型不會突然蹦出一個「香蕉」。它砍掉的是長尾的雜訊。
但 top-k 有個先天的笨拙——K 是個固定數字,不管當下情況。 這會在兩種極端情況下出問題:
- 模型很確定的時候(例如「2 + 2 =」後面幾乎篤定是「4」),其實只有 1 個合理答案,但 top-k = 5 還是硬留了 5 個,等於放進 4 個不該考慮的雜選項。
- 模型很不確定的時候(例如寫小說的下一句,幾十個詞都通順),合理選項明明很多,top-k = 5 卻硬砍到只剩 5 個,扼殺了該有的多樣性。
固定的 K,沒辦法同時應付這兩種狀況。這就是 top-p 想解決的事。
Top-P:不數人頭,改看累積機率
top-p,又叫 nucleus sampling(核心取樣),做的事跟 top-k 很像——都是砍候選名單——但它的砍法聰明在:不固定留幾個,而是固定留多少「機率總量」。
Top-P = 0.9 的意思是:從機率最高的開始往下加,加到累積超過 90% 為止,後面的全部砍掉。
回到原本那張表,看看同一個 P 值在不同情況下會留下幾個:
情況 A:模型很確定(top_p = 0.9)
好 92% ← 加到這裡就破 90% 了
─────────────── 後面全砍
熱 5% ✗
其他 ... ✗
結果:只留 1 個
情況 B:模型很發散(top_p = 0.9)
好 25% 累積 25%
熱 20% 累積 45%
不錯 18% 累積 63%
還行 15% 累積 78%
普通 12% 累積 90% ← 加到這裡才破 90%
─────────────── 後面才砍
結果:留了 5 個
看出差別了嗎?同樣是 top_p = 0.9,模型有把握時自動只留 1 個,模型發散時自動留 5 個。 候選名單的長度,是隨著當下這張機率表的「形狀」動態伸縮的。
這正好補上 top-k 的死穴。Top-k 數的是「人頭」,永遠固定幾個;top-p 看的是「機率總量」,名單該長就長、該短就短。所以現在主流的設定,多半是 top-p 為主、top-k 為輔,甚至直接不開 top-k。
放在一起:它們是一條生產線
講到這你可能會問:那這三個到底要怎麼搭?是三選一嗎?
不是三選一——它們會依序套用,像一條生產線。實際生成一個 token 的順序通常是:
1. 模型算出原始機率分布(幾萬個 token)
2. Temperature → 把整張表拉尖或拉平
3. Top-K → 砍到只剩前 K 名
4. Top-P → 再從累積機率切一刀
5. 在剩下的候選裡,按機率抽一個籤
每一道工序都在縮減或重塑候選池,最後才抽。所以它們不衝突,是接力。
用一個比喻收尾——這像在一群人裡選一個代表:
Temperature 決定大家的呼聲差距要拉多開(有人特別突出,還是勢均力敵); Top-K 說「只有排名前 K 的有資格」; Top-P 說「從最高票開始點名,點到累積過半就截止」。 最後,在剩下的候選人裡抽籤。
那實際上該怎麼設
規則沒有絕對,但有幾個堪用的起點:
| 你想要 | Temperature | Top-P | 場景 |
|---|---|---|---|
| 穩定、可重現 | 0 ~ 0.3 | 1.0 | 程式碼、翻譯、抽取結構化資料 |
| 平衡 | 0.7 ~ 0.8 | 0.9 | 一般對話、問答 |
| 發散、有創意 | 1.0 ~ 1.3 | 0.95 | 寫作、發想、腦力激盪 |
兩個實務提醒:
別同時把 temperature 和 top-p 都調到很激進。 兩個都放很開,輸出容易直接崩成亂碼。要嘛靠 temperature 主導,要嘛靠 top-p 主導,動一個就好。
要完全確定性,temperature 設 0 就夠了。 這時候 top-k、top-p 設什麼都沒差——反正只剩機率最高的那一個,沒得抽。
小結
這三個參數看起來都在「控制隨機性」,但它們其實站在生產線的不同位置:temperature 重塑整張機率表的對比度,top-k 用固定人數砍候選名單,top-p 用累積機率動態砍候選名單。一個在調形狀,兩個在切範圍,切法不同。
所以下次你在調這些旋鈕,不會再覺得是三個都在「控制亂度」的重複開關。你會知道自己正站在哪道工序上:是要把那座機率的山拉尖一點,還是要把山腳的雜訊掃掉幾個。模型從頭到尾都在抽籤——你只是在決定,籤筒裡該放哪些籤。