2026年10月6日

06 采样:选出一个 token

LLM

一个 token 到底是怎么被"抽"出来的?

"采样"是什么意思

上一步得到了一个概率分布。采样就是按照这个概率随机抽取,可以想象成掷一个不均匀的骰子: "好"占 40% 的面,"热"占 25% 的面……每次掷出的结果是随机的,但概率高的选项更容易被掷到。

这意味着,同样的输入,每次运行可能得到不同的输出。这正是同一个问题问两遍,模型回答不完全相同的原因。

为什么不直接选概率最高的

总是选概率最高的 token,叫做贪心解码(greedy decoding),相当于 temperature = 0。它看起来最"稳",但有几个问题:

  • 容易陷入重复。 一旦某个短语出现,它后面最可能的续写往往又会导回这个短语,模型可能陷入"我认为……我认为……"的循环。
  • 文本单调。 每一步都选最常见的说法,写出来的内容平淡、模板化。
  • 每步最优不等于整体最优。 第一步选了概率 40% 的"好",但可能接下来的选项都很平庸;选 25% 的"热",后面反而能写出一句更自然的话。贪心只看眼前一步。

所以对于开放性的生成任务,适度的随机性反而让输出更自然。但对于需要稳定、可复现的任务,比如 agent 的工具调用,就应该降低随机性。

完整的执行顺序

把上一步和这一步连起来,一个 token 的诞生过程是:

  1. 模型输出 logits(每个 token 一个分数)
  2. 除以 temperature
  3. softmax 转成概率
  4. 用 top-k / top-p 剔除长尾的低概率选项
  5. 对剩下的选项重新归一化,让概率总和回到 1
  6. 按新的概率随机抽取一个 token

用数字走一遍。假设 temperature = 1 时,概率分布是:

"好" 40%、"热" 25%、"冷" 15%、"糟" 5%、其余几万个 token 合计 15%

设置 top-p = 0.8 后,从高到低累加:"好" + "热" + "冷" = 80%,刚好达到阈值,于是只保留这三个。重新归一化后变成:

"好" 50%、"热" 31%、"冷" 19%

然后在这三者之间掷骰子。注意那"其余 15%":每个 token 的概率都很小,但几万个加在一起并不小。如果不做截断,每生成几个 token 就有相当可能抽中一个离谱的选项,比如突然冒出一个毫不相关的词。Top-p 的主要作用就是砍掉这条长尾,而 temperature 负责调整保留下来的选项之间的差距。

每次选择都不可撤回

最后一个值得理解的特点:token 一旦被选中,就会拼回输入,成为后续所有计算的前提,模型没有"回退"的能力。

如果在第 5 个 token 时偶然抽中了一个不太好的选项,比如回答一道数学题时第一步就写错了数字,后面的所有内容都会在这个错误的基础上继续"合理地"写下去。模型不会自动回头修改,而是会尽力让后文和前文保持一致,有时甚至会为一个错误找理由。

这也解释了一些实践中的技巧为什么有效:让模型"先思考再回答"(现在很多模型的推理模式就是这样),相当于给它一段草稿空间,在给出最终答案前,有机会在后续 token 里发现并纠正前面的错误;而在 agent 开发中,为关键步骤加上校验环节,或者在失败时重新生成,也是在弥补这种"一步错、步步错"的特性。

06 采样:选出一个 token · Kevin's Blog