大语言模型:推理采样策略(Sampling Strategy)

采样是什么

当我们问大语言模型一个问题时,模型不是一次性就生成所有答案的。

模型每次根据当前当上下文 token 序列 ​\mathbf{u}=[u_1,u_2,\cdots,u_t] 预测下一个 token 的概率分布 ​P,然后采样策略从这个分布中选出一个token ​u^\prime,选出的token ​u^\prime 会拼接在 ​\mathbf{u} 的后面作为新的上下文重复上述步骤,直到遇到停止条件,比如生成了结束符、达到最大token 数。

这个过程可以简化成:

上下文 -> 模型 -> logits -> softmax -> 概率分布 -> 采样策略 -> 下一个 token -> 更新上下文

这个根据概率分布选择输出 token 的过程就是采样(Sampling),采样方法主要关注如何基于概率分布 ​P 选择合适的下一个词 ​u^\prime

所以,LLM 的输出并不只由模型能力决定,也由采样策略决定。模型负责给出“接下来哪些 token 可能出现?其出现的概率分别是多少”;采样策略负责给出“在这些可能性中,这一次选择哪一个token”。

采样方法的分类

分类 代表方法 核心问题
确定性解码 Greedy Search、Beam Search 如何选择概率最高或整体分数最高的序列
概率采样 Random Sampling、Temperature、Top-k、Top-p 如何在质量和多样性之间取平衡
约束或惩罚型调整 Repetition Penalty、Frequency Penalty、Presence Penalty、No-repeat N-gram 如何减少重复、控制话题展开或禁止某些模式
组合策略 temperature + top_p + repetition_penalty 如何把多个旋钮组合成适合任务的生成行为

在实践中,这四类方法不是互斥的,而是模型生成过程中的不同控制方式。

一个经典的采样流程可能是:

模型输出 logits
  -> 应用 repetition penalty 等惩罚
  -> 应用 temperature 调整分布
  -> 应用 top-k 或 top-p 截断候选集合
  -> 从剩余分布中随机采样

也就是说,temperature、top-k、top-p 可以一起出现,但它们控制的不是同一件事:temperature 改变概率分布的形状,top-k/top-p 改变候选集合,penalty 改变某些 token 的分数。

确定性采样

贪心搜索(Greedy Search):每一步都选最可能的 token

贪心搜索是最直观的采样方法,每一步都选择概率最高的 token,其数学形式可以描述为:

u_i = \mathrm{arg max}\quad P(u|\mathbf{u}_{<i})

Greedy Search 的稳定性较高,对于摘要、分类解释、短答案、格式化输出这类任务,通常希望模型少一点随机发挥,贪心搜索的确定性就很有价值。但 Greedy Search 的问题也很明显:有时候会因为过于关注局部最优,而生成不自然、重复的句子。更麻烦的是,在长文本生成中,Greedy Search 容易变得平淡、重复,甚至卡进某些循环句式里。

束搜索(Beam Search)

Beam Search 不只保留当前最可能的一个 token,而是保留多个候选序列。这个候选数量通常由 num_beams 控制。

例如 num_beams = 3 时,模型会维护 3 条目前看起来最有希望的生成路径。每一步扩展这些路径,再按累计分数筛选出新的前 3 条路径。

num_beams = 1 时,Beam Search 实际变成 Greedy Search。

Beam Search 通常使用累计 log 概率给一条候选序列打分:

\mathrm{score}(x_1, \ldots, x_T) = \sum_{t=1}^{T} \log P(x_t \mid x_{<t})

使用 log 概率是为了把连乘变成求和,数值上更稳定,也更方便比较不同候选路径。

有些实现还会加入长度归一化,避免模型过度偏好短句:

\mathrm{score}_{norm} = \frac{\mathrm{score}}{T^\alpha}

这里的 ​\alpha 用于控制长度惩罚强度。

Beam Search 解决的是 Greedy Search 存在的短视问题。Greedy Search 可能第一步选了最高概率 token,但后续越走越差;Beam Search 允许某些第一步稍弱但整体更好的路径留下来。

举个简化例子:

路径 1: A -> A1 -> A2,整体分数 0.21
路径 2: B -> B1 -> B2,整体分数 0.25

Greedy Search 可能因为第一步 AB 概率高而选 A,但 Beam Search 有机会发现 B -> B1 -> B2 的整体分数更高。

Beam Search 很适合输入强约束任务,比如机器翻译、语音识别、图像描述,因为这些任务往往有较明确的目标输出。但它不一定适合开放式写作。开放式生成里,累积概率最高的句子通常不是最自然、最有信息量或最有创意的句子,Beam Search 有“安全但无聊”的倾向。

概率采样

确定性解码强调“最可能”,概率采样强调“按概率选择”。它不一定选概率最高的 token,而是让多个合理候选都有机会被选中。

随机采样(Random Samping)

Random Sampling 通过引入随机性来获取输出的多样性,最基础的Random Sampling 就是按完整概率分布抽样。

它的公式可以写成:

x_t \sim \mathrm{Categorical}(P(\cdot \mid x_{<t}))

​t 个 token 不是固定取最大值,而是从当前条件概率分布中随机抽一次。

对于下面这样一个 token 概率分布

token 概率
A 0.40
B 0.30
C 0.15
D 0.10
E 0.05

Random Sampling 的含义是

token 被选中的机会
A 40%
B 30%
C 15%
D 10%
E 5%

Random Sampling 的优点是输出具有多样性,缺点是长尾低概率 token 也有机会被选中,而低概率 token 往往更容易带来跑题、事实错误或语义突兀。因此,纯 Random Sampling 在实际应用里不常单独使用,通常会搭配 temperature、top-k 或 top-p。

Temperature Sampling:调节概率分布的形状

详见:大模型文本生成中 temperature 参数的数学机制

Temperature 是最常见的采样参数之一。它不直接决定候选 token 集合,而是调整概率分布的形状。

temperature 效果
接近 0 分布更尖锐,更接近 Greedy Search
1 保持原始分布
大于 1 分布更平坦,低概率 token 更有机会被选中

Temperature 通常作用在 softmax 之前:

p_i(T) = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}

其中 ​T 就是 temperature。

  • ​T < 1 时,大 logit 会被进一步放大,分布更尖锐;
  • ​T > 1 时,不同 token 的概率差距会被拉平。

如果 temperature 很低,最高概率 token 会变得更突出,输出更稳定、更保守。

如果 temperature 较高,不同 token 的概率差距会缩小,输出更多样、更有惊喜,但也更容易跑偏。

注意:temperature 提高的是随机性,不是能力。高 temperature 不会让模型懂得更多,只是让模型更加偏向输出低概率 token。

Top-k Sampling:只在前 k 个 token 中抽样

Top-k 的做法是:先按概率排序,只保留概率最高的 ​k 个 token,然后在这 ​k 个 token 之间重新归一化并采样。

​V_k 表示概率最高的 ​k 个 token 集合:

V_k = \mathrm{TopK}(P, k)

截断之后,把保留下来的 token 概率重新归一化:

p'_i = \begin{cases} \frac{p_i}{\sum_{j \in V_k} p_j}, & i \in V_k \\ 0, & i \notin V_k \end{cases}

Top-k 解决的是长尾风险。它把概率很低的候选挡在外面,避免随机采样选到奇怪 token。

Top-k 存在的问题是候选token 数量 ​k 是固定的,不是动态变化的,有时候模型输出的合理候选token可能只有1-3个,这时候 ​k 如果设置的是50,会导致候选范围过于宽泛;而有时候模型输出的合理候选token可能有几十个,设置 ​k=10 又会导致候选范围过小。

Top-p / Nucleus Sampling:只保留累计概率达到 p 的候选token

Top-p 也叫 Nucleus Sampling(核采样),其核心思想是:不固定候选数量,而是保留累计概率达到 ​p 的最小候选集合。

它的候选集合可以写成:

V_p = \min \left\{ V: \sum_{i \in V} p_i \ge p \right\}

其中给你 ​p 是累计概率阈值,​V_p 是按概率从高到低累加后,累计概率达到阈值 ​p 的最小集合,后续会在这个集合内重新归一化并采样。

以下面这组预测 token 分布为例:

token 概率 累计概率
A 0.40 0.40
B 0.30 0.70
C 0.15 0.85
D 0.10 0.95
E 0.05 1.00

如果 top_p = 0.8,从高到低累加:

A = 0.40
A + B = 0.70
A + B + C = 0.85

超过 0.8 的最小集合是 {A, B, C}。所以本轮只在 A、B、C 中采样。

如果 top_p = 0.95,候选集合会变成 {A, B, C, D}

Top-p 和 Top-k 的关键区别是:

方法 候选集合大小 特点
Top-k 固定 k 个 token 简单,但不看模型是否确定
Top-p 动态变化 模型确定时集合小,模型不确定时集合大

Top-p 能够在排除 长尾低概率 token 和保留生成多样性之间取得自然的平衡。

约束惩罚

前面的几种方法主要控制“如何从分布中选择token”,约束惩罚则更像是在采样前先修改分布:降低某些 token 的分数,或者直接禁止某些模式。

重复惩罚(Repetition Penalty):惩罚已经出现过的 token

Repetition Penalty 用来减少重复,它会降低已出现 token 的得分,让模型不那么容易反复生成同一个token。

一个简化写法是:

z'_i = \begin{cases} z_i / r, & \text{token } i \text{ 已出现且 } z_i > 0 \\ z_i, & \text{其他情况} \end{cases}

其中, ​r 是 repetition penalty。现实实现通常还会处理负 logits 等细节,其效果都是:已经出现过的 token 会被压低分数。​r 的值越大,惩罚越强。

例如模型已经生成:

这个方法很重要,因为这个方法

如果没有惩罚,模型可能继续生成“很重要”,形成重复句式。加上 repetition penalty 后,已经出现过的“这个”“方法”“很”“重要”等 token 得分会被压低,模型更可能换一种表达。

频率惩罚(Frequency Penalty):出现次数越多,惩罚越强

Frequency Penalty 关注 token 的出现次数,一个 token 出现得次数越多,它受到的惩罚强度越大。

Frequency Penalty 可以和 Presence Penalty 放在同一个公式中理解:

z'_i = z_i - c_i \alpha_\mathrm{frequency} - \mathbf{1}_{c_i > 0}\alpha_\mathrm{presence}

其中 ​c_i 表示 token ​i 已经出现的次数,​\alpha_\mathrm{frequency} 表示频率惩罚强度,​\alpha_\mathrm{presence} 表示存在惩罚强度。Frequency Penalty 关注的是出现了多少次,所以惩罚项和 ​c_i 成正比。​\mathbf{1}_{c_i > 0} 是一个指示函数:只要 token 出现过,它就是 1;没出现过就是 0。

Frequency Penalty 适合处理模型不断重复同一个词、同一个口头禅、同一句式的问题。

例如模型反复输出:

非常非常非常重要

Frequency Penalty 会随着“非常”出现次数增加而加大惩罚。和 Repetition Penalty 相比,它更强调累计次数,而不是简单判断是否出现过。

存在惩罚(Presence Penalty):出现过就惩罚,鼓励话题展开

Presence Penalty(存在惩罚)关注是否出现过,只要某个 token 已经出现,它就会受到惩罚,不随着次数线性增加。

Presence Penalty 的作用更像是鼓励模型引入新内容,而不是围绕已经说过的词一直打转。例如在头脑风暴中,如果模型一直围绕“性能”展开,Presence Penalty 可以稍微鼓励它转向“成本”“用户体验”“可维护性”等新角度。

No-repeat N-gram:禁止重复 n 元片段

No-repeat N-gram 是更硬的约束,它不是降低重复片段概率,而是禁止已经出现过的 n-gram 再次出现。可以将其看作一个硬过滤规则:

p'_i = 0,\quad \text{if appending } i \text{ creates a repeated } n\text{-gram}

其中 p'_i = 0 表示 token i 在当前步被完全禁止。也就是说,如果追加某个 token 会形成已经出现过的 n-gram,这个 token 在当前步就被直接排除,而不是只降低概率。

如果 no_repeat_ngram_size = 3,那么已经出现过的三 token 片段不能再次生成。

例如已生成:

机器学习 是 一种 方法

如果三元片段“是一种方法”已经出现过,后续就不能再次生成同样的三元片段。

这种方法对减少机械重复很有效,但约束过强时会误伤自然表达。尤其是专有名词、固定短语、诗歌、歌词、法律文本这类本来就需要重复结构的文本,要谨慎使用。

采样策略的组合

实际生成中,我们很少只用一种策略。更常见的是组合多个采样方法,让它们各司其职。

控制点 常用策略 主要解决什么
修改 token 分数 Repetition/Frequency/Presence Penalty 重复、啰嗦、话题停滞
调整概率形状 Temperature Sampling 输出保守还是发散
裁剪候选集合 Top-k / Top-p Sampling 排除低质量长尾候选
最终选择 token Random Sampling 或 Greedy Search 是否引入随机性

一个简化的组合流程可以写成:

x_t \sim \mathrm{Sample}(\mathrm{TopP}(\mathrm{TopK}(\mathrm{Softmax}(\mathrm{Penalty}(z) / T))))

Penalty 先改变 logits,temperature 决定概率分布尖锐程度,Top-k/Top-p 决定候选范围,最后再从剩余候选里采样。

总结

方法 是否随机 主要控制什么 常见参数 输出特点 适用场景
Greedy Search(贪心搜索) 当前最高概率 token 无或默认 稳定、保守、可能重复 短答案、格式化输出
Beam Search(束搜索) 多条候选序列的整体分数 num_beams 更重视整体概率,可能平淡 翻译、语音识别、图像描述
Random Sampling(随机采样) 完整概率分布随机抽样 do_sample 多样但风险高 很少单独使用
Temperature Sampling(温度采样) 概率分布尖锐程度 temperature 低温稳定,高温发散 问答、写作、对话
Top-k Sampling(Top-k 采样) 固定数量候选 token top_k 排除长尾,简单直接 通用生成、轻量控制
Top-p / Nucleus Sampling(核采样) 动态累计概率候选集 top_p 更自适应,开放生成常用 聊天、创作、头脑风暴
Repetition Penalty(重复惩罚) 取决于主策略 已出现 token 的得分 repetition_penalty 减少重复 长文本、对话
Frequency Penalty(频率惩罚) 取决于主策略 出现次数越多惩罚越强 frequency_penalty 抑制高频重复 对话、开放生成
Presence Penalty(存在惩罚) 取决于主策略 出现过即惩罚 presence_penalty 鼓励新话题 头脑风暴、创意探索
No-repeat N-gram(禁止重复 N-gram) 取决于主策略 禁止重复 n-gram no_repeat_ngram_size 强力去重,但可能生硬 摘要、长文本去重
RAG中的精确检索算法:从TF-IDF到BM25 2025-11-05
【论文阅读】Late Chunking:Contextual Chunk Embeddings Using Long-Context Embedding Models 2025-09-08