语言模型每走一步,都会对整个词汇表产出一组概率,接着由三道裁决器把它收窄。temperature 缩放 logits——小于 1 会拉开强弱差距,大于 1 则把差距压平;top_k 只留概率最高的 k 个并重新正规化;top_p 由高到低累加,直到累积值达到 p 为止,跨过门槛的那一个仍然留下。这里的四个阶段就是这四个时点,被淘汰的候选会留在原位,带着砍掉它的那个参数名称。
这三道裁决器不可交换。先缩放,代表截断看到的是已经被重塑过的分布——调高 temperature 会把曲线压平,于是 top_p 更晚才达到门槛、留下更多候选;先截断,则是用原始概率来判定去留,temperature 只重塑幸存下来的那些。各家 SDK 选的顺序不同,所以这个工具把选择摊开来,而不是把其中一种藏在预设值后面、暗示存在单一标准行为。
这里的起始分布是构造的,不是撷取来的:三种形状各自挑来让一道裁决器现形——一枝独秀、势均力敌、长尾。画面上会标明它们是构造的,因为一个要展示因果的工具,没有资格对「哪一半是真的」含糊其辞。而真的那一半正好是重要的那一半:temperature、top_k、top_p 的实作与真实取样器里的完全相同,所以你看到的每一次变化都是货真价实的运算。构造分布给不了的是真实词汇表的手感,这也是为什么「载入浏览器内的小模型」被当成下一步,而不是可有可无的附加功能。
关于这个主题的常见疑问与实用解答。
它们作用的对象不同。temperature 重塑整条分布但不删掉任何人——它决定强的候选看起来比弱的强多少;top_p 则是直接删人,累积概率一达到你设的门槛就切线。之所以不建议一起调,是因为两者会互相干扰:调高 temperature 会把曲线压平,同一个 top_p 就需要更多候选才累积到门槛,于是留下你以为已经排除掉的字。只动一个、看着裁决链,就能直接看见这种干扰。
top_k 是固定人数:留下概率最高的 k 个、其余丢掉、重新正规化。top_p 是固定的概率份额,常称为核取样(nucleus sampling):从最可能的开始往下累加,累积值一达到 p 就停。把总和推过 p 的那一个会被留下,因为少了它就凑不到门槛——这也是为什么 p 设得小的时候可能只剩一个字。top_k 永远留同样数量的选项;top_p 留下的数量则随模型在那一步有多确定而变。
因为最后一步是抽签,不是决策。三个参数只决定哪些候选还有资格、各自的权重是多少;真正吐出来的那个字,是从这组加权集合里抽出来的。所以参数完全相同的两次执行共用同一个候选池,仍然可能落在不同的字上。在这里按「再抽一次」,会看到裁决链完全不动、结果却换人——那就是剩下的随机性的全部。把 temperature 设成 0 会让候选池收成单一候选,这也是它表现得像确定性行为的原因。
一次只动一个,并且看它对裁决链做了什么,而不是去找一个建议数值。太发散通常代表低概率的候选还有资格留下,这时收紧裁切——把 top_p 或 top_k 调小——可以删掉它们,而不动到剩下那些的形状。一直重复通常代表候选池已经塌缩到一两个强势候选上,这时调高 temperature 才是把差距拉开的那根杠杆。一个实用的方法:固定其中两个,把第三个从保守扫到积极,停在存活集合看起来符合你任务的地方。没有一组普遍正确的数值,这也是这个工具展示机制而不推荐设定的原因。
起始分布是为了演示而构造的,画面上也这样标示,所以它不是来自模型。但它下游的一切都是在你浏览器里即时运算,而且与真实取样器的做法一致。所以机制可以带到你自己的调用上,具体数字不行。你的调用用的是不同的 prompt,可能还是不同的模型、tokenizer 与裁决器顺序,而且供应商可能加上这个页面没有模拟的步骤,例如重复或频率惩罚。想要一组真实分布来实验,可以载入浏览器内的小模型,同一条链会跑在它真正的输出上。
三种,每一种都刻意让不同的裁决器成为主角。一枝独秀时,截断几乎没东西可删,只有 temperature 动得出可见的效果。势均力敌时,top_p 稍微一动就换一批存活者,这是体会「为什么同一个问题会有不同答案」最直接的方式。长尾时,做粗活的是 top_k——它砍掉的是整条尾巴而不是几个落单的。依形状而不是依主题挑情境是刻意的:形状才决定哪个参数值得动,而那正是值得学的东西。