07 · 生成 · 7 min

选择下一个词

温度、top-ktop-p。将概率分布转化为文本的艺术。

分布算出来了,然后呢?

到目前为止,模型已经知道如何在下一个 Token 上计算一个概率分布。要生成文本,它现在必须选出一个。这就是**采样(sampling)**这一步。

我们已经在第 01 章里瞥见过这个机制。是时候认真地回过头来看了:正是这一步,区分了一个谨慎的模型和一个有创造力的模型,区分了一个可靠的助手和一只重复的鹦鹉。

为什么不总是选概率最高的?

最简单的策略——贪婪解码(greedy decoding)——总是挑选概率最高的 Token。快速、确定、可复现。

然而,它几乎从不被单独使用。为什么?

因为贪婪解码会产生一种奇怪地平淡的文本。它会陷入循环("非常 非常 非常 有趣 有趣 有趣……")。它总是选择最循规蹈矩的词。它能生成技术上正确的句子,但毫无层次。模型是在人类文本上训练的,而人类文本永远包含某种程度的不可预测性——这种不可预测性必须出现在生成中。

由此引出了随机采样(stochastic sampling):我们按照分布随机抽取一个 Token。一个 Token 概率越高,被选中的可能性就越大——但其他 Token 也有机会。

三个杠杆

裸的随机采样会过于嘈杂。我们通常会在抽取之前应用三个过滤器:

温度(Temperature

温度 Tsoftmax 之前对 logits 做除法。这是最强大的一个调节项。

  • T = 1.0 —— 模型原本输出的分布(参考值)
  • T < 1.0 —— 分布变得更尖锐:高的更高,低的更低。模型变得更可预测。
  • T → 0 —— 等同于贪婪解码(只剩一个可能的 Token)。
  • T > 1.0 —— 分布被压平:低概率的选项重新抬头。模型变得有创造力,甚至古怪。
  • T → ∞ —— 均匀分布,模型完全随机抽取。

温度是一个介于可预测性和想象力之间的旋钮。

Top-k

与其允许整个词表(5 万+)的所有 Token,不如保留概率最高的 k 个,把其余的归零,再重新归一化。k = 40 是创造性写作的经典值,k = 1 则退化为贪婪解码。

优点:直接排除掉那些荒谬的 Token(概率 0.0001% 那种),免得它们靠运气被抽中。缺点:最优的 k 值取决于每一步——有时候 5 个候选就够,有时候 100 个都同样合理。

Top-p核采样,nucleus sampling

top-k 更聪明。我们保留累积概率刚好超过 p 的最小集合,然后重新归一化。

  • 在某一步,模型在 30 个相近选项之间犹豫不决 → top-p 会保留所有累积和达到 p 的选项。
  • 在某一步,模型 95% 确定 → top-p 只保留一个 Token

实践中,top-p ≈ 0.9 已经成为现代 LLM 的默认设置。它会自动适应模型的置信度。

再玩一次

我们在第 01 章已经见过这个可视化——这里再放一次,因为正好就是这个话题:

调节 temperature:当 temperature 为 0,模型确定且重复;当为 1.5,模型变得有创意,直至失去连贯。Top-ktop-p 修剪掉那些不太可能的候选词,而不影响概率高的候选。

这次,注意观察:

  • 在 **Capitale(首都)**这个例子中,模型如此自信(10.0 对下一个的 5.0),以至于需要极高的温度(>1.5)才能让它输出 Paris 以外的东西。这是答案已知的提示词的典型情况。
  • 在 **Le ciel(天空)**第二步,几个续写在语义上都成立。在 temperature = 1.5 下,你可能会得到 couleur(颜色)或 mer(海)而不是 lumière(光)。意思仍然正确,但文本变得不那么可预测。
  • top-k = 1 时,其他任何设置都失去意义:你已经处于贪婪模式。
  • Capitale 提示词上设 top-p = 0.5,只有 Paris 能存活下来(因为它一个就已经达到 50%)。

一些约定俗成的设置

按使用场景的典型设置:

场景TemperatureTop-p
代码、结构化数据0.0–0.21.0
事实性回答0.3–0.50.9
通用对话0.70.9
头脑风暴、创意写作0.9–1.20.95
生成多样化变体1.2–1.50.95

这些不是死规则。但你在大多数使用 LLM 的产品里会看到的就是这个量级。

还有三个值得了解的旋钮

除了温度 / top-k / top-p 之外,在各家 API 里你会反复见到几个参数。

Repetition penalty(在 OpenAI 那边叫 frequency penalty / presence penalty)。对已经出现过的 Token 进行惩罚。在不需要把温度调高的情况下,就能打破重复循环。典型取值:1.05–1.2。

Stop sequences。 一组字符串,一旦它们出现在输出中,就立即停止生成。对于结构化用法来说不可或缺:在格式化的对话里,你会用 <|im_end|>\n\nUser: 来停下,避免模型自己接着替"用户"说话。

Beam search 不再做随机采样,而是在每一步同时保留k条最优的部分序列,最后挑出整体概率最大的那一条。结果会更"平滑",但通常也更不自然。常用于机器翻译和语音识别,在创意生成中用得很少。

确定性的幻觉

最后一个微妙之处。即使 temperature = 0,对同一个模型的两次调用,在实践中也可能给出不同的结果:

  • 量化(Quantization)的非确定性(INT8/FP8 计算存在误差容限)。
  • 服务端的动态批处理(取决于其他请求,浮点运算的执行顺序会变化)。
  • 模型版本在提供商那边悄无声息地更新。

如果你写的测试依赖 LLM 的精确输出,你会很痛苦。

接下来

到目前为止,你已经知道一个 LLM 是如何:

  • 把文本切成 Token
  • 把它们变成向量,
  • 通过注意力机制让它们彼此凝视,
  • 堆叠 Transformer 块来精炼表示,
  • 在下一个 Token 上预测一个分布,
  • 用某种采样策略从中抽取一个。

然而,我们所说的"助手"——像 ChatGPT 或 Claude 这样的东西——并不只是这些。一个停在这一步的基础模型只是一个文本补全器,而不是一个助手。怎么从前者变成后者?这就是最后一章的主题:对齐(alignment

更新于

选择下一个词元:temperature、top-k、top-p · Step by Token