8.5 采样与解码算法:生成质量的后台旋钮
SamplingParams 全参数语义(temperature/top_p/top_k/min_p/惩罚)、logprobs、并行采样 n、beam search 的移除、采样对延迟与质量的影响
前几章优化的是”怎么更快地出 token”,8.5 回答”token 是怎么被选出来的”。采样参数(temperature、top-p……)看似简单,实则是质量、多样性、延迟的三角权衡——调错参数,前面所有性能优化都白费(吐一堆废话)。这一节把 vLLM 的 SamplingParams 逐个讲透,并澄清工程实现上的关键差异。
📑 目录
- 1. 解码的两种模式:贪心与采样
- 2. 核心采样参数逐个拆解
- 3. 惩罚项:Presence / Frequency / Repetition
- 4. Logprobs:拿到底层概率
- 5. 并行采样 n 与 Best-of 的工程真相
- 6. Beam Search 在 vLLM 的现状
- 7. 采样参数与性能的相互作用
- 📝 总结
- 🎯 自我检验清单
- 📚 参考资料
1. 解码的两种模式:贪心与采样
| 模式 | 行为 | 适用 |
|---|---|---|
| 贪心(Greedy) | 每步选概率最高的 token | 确定性任务(抽取、分类、JSON) |
| 采样(Sampling) | 按概率分布随机抽 | 创意任务(写作、对话、代码注释) |
数学上,采样分布 = 模型输出的 logits 经 temperature 缩放 → 惩罚修正 → top-k/top-p/min-p 截断 → softmax → 采样。vLLM 的 SamplingParams 就是这个管线的参数面板。
📌 关键点:贪心不是采样参数的”一种取值”,而是独立模式——vLLM 里
temperature=0即贪心(等价于始终选 argmax)。测试时如果输出不具多样性,先检查是否 temperature 被设成了 0。
2. 核心采样参数逐个拆解
vLLM(v0.26)SamplingParams 的默认值与语义:
| 参数 | 默认 | 语义 | 常见用法 |
|---|---|---|---|
temperature | 1.0 | logits 缩放:logits / T。T>1 更平(随机)、T<1 更尖(确定) | 0.3-0.8 创作;0 贪心 |
top_p | 1.0 | 核采样:保留累计概率 ≥ p 的最小 token 集合 | 0.9-0.95 常用 |
top_k | 0(=禁用) | 只保留概率最高的 k 个 token | 40-50(旧式) |
min_p | 0.0 | 保留概率 ≥ min_p × 最高概率 的 token | 0.05-0.1(动态截断) |
seed | None | 随机种子(复现实验) | 固定 seed 可复现 |
2.1 temperature 的语义细节
- T=0:贪心(argmax)
- T=1:原始分布
- T>1:分布变平——低概率 token 被放大,多样性↑ 质量↓(幻觉风险↑)
- T<1:分布变尖——确定性↑,但过度压缩会退化(重复、死板)
2.2 top_p vs top_k vs min_p
三个都是”截断”手段,但机制不同:
原始分布: [0.50, 0.20, 0.10, 0.05, 0.04, 0.03, ...]
top_k=3: [0.50, 0.20, 0.10] ← 固定数量
top_p=0.85: [0.50, 0.20, 0.10, 0.05] ← 累计到 0.85(动态数量)
min_p=0.1: [0.50, 0.20, 0.10, 0.05] ← 相对最高概率的阈值
- top_k:固定数量,对分布形状不敏感(分布很平时会砍掉合理的候选)
- top_p:按概率质量截断,分布平时自动放宽——vLLM 默认仅 top_p=1.0(禁用),推荐开 0.9-0.95
- min_p:相对阈值,分布自适应——分布尖时保留少、平时保留多,是较新的推荐实践
💡 提示:现代实践倾向 top_p + min_p 组合(替代纯 top_k):top_p 管”总量”,min_p 管”相对下限”,两者配合能在多样性与质量间取得更好平衡。top_k 的”固定数量”问题(对分布形状不敏感)是它渐被替代的原因。
3. 惩罚项:Presence / Frequency / Repetition
| 参数 | 默认 | 语义 |
|---|---|---|
presence_penalty | 0.0 | 出现过的 token 整体降权(出现一次即惩罚,与次数无关) |
frequency_penalty | 0.0 | 按出现次数降权(出现越多压得越狠) |
repetition_penalty | 1.0 | 按出现次数指数级降权(>1 惩罚重复,<1 鼓励重复) |
工程实现细节(OpenAI 兼容层的换算):OpenAI API 的 presence/frequency penalty 取值 [-2, 2],vLLM 内部会做线性映射。正负号语义:
- 正值:惩罚重复(抑制复读)
- 负值:奖励重复(鼓励延续话题/模仿风格)
📌 关键点:三个惩罚的作用域差异要分清——presence 治”说过没”(话题多样性),frequency 治”说了几遍”(复读机),repetition 是”次数指数惩罚”(激进防复读)。复读问题优先上 repetition_penalty 1.1-1.3 或 presence_penalty;三个同时拉满会过度扭曲分布,输出生硬。
4. Logprobs:拿到底层概率
logprobs 参数返回每个生成 token 的对数概率(以及候选 top 序列):
resp = client.chat.completions.create(
model="...",
messages=[...],
max_tokens=16,
logprobs=True, # 返回 top-5 候选
top_logprobs=5,
)
用途:
- 置信度评估:输出 token 的平均 logprob → 回答可靠性信号(下游路由/重试依据)
- 调试:看模型”犹豫”在哪(候选概率接近 = 不确定)
- Agent 可靠性:工具调用参数的低概率 → 提醒校验
工程注意:prompt_logprobs 返回 prompt 侧概率(诊断 prefill 行为);logprobs 会增加响应体积与内存(每 token 多带 k 个候选),高吞吐场景注意带宽与序列化开销。
💡 提示:logprob 是 Agent 生产化的重要信号源——“低置信度 → 重试/换模型/询问用户” 的兜底策略可以完全基于 logprob 实现,不必依赖额外模型打分。但注意 logprob 是”模型自评”,与真实正确率有差距(校准问题),做阈值时要先标定。
5. 并行采样 n 与 Best-of 的工程真相
5.1 n:一个请求生成 n 条候选
resp = client.chat.completions.create(
model="...",
messages=[...],
n=3, # 同 prompt 生成 3 条独立样本
)
- 每条样本独立采样(不同随机路径)→ 多样性候选
- 工程实现:
n个样本共享 prefill(同一 prompt 只算一次),decode 阶段并行推进——比发 n 个请求省 prefill - 配合 logprobs 可做”采样-打分-择优”(自洽性方法,Self-Consistency)
5.2 Best-of 的真相
OpenAI 协议里的 best_of 字段(生成 n 条取 logprob 最高者):vLLM 的 SamplingParams 没有独立的 best_of 实现——v0.26 用 n + 客户端择优,或依赖 n 采样后自行排序。别指望服务端自动帮你”选最好的”,“最好”的定义取决于你的任务(多数是外部打分器,不是 logprob)。
📌 关键点:
n的代价账:n 条候选 = decode 计算 ×n(共享的只有 prefill)。n=4 时 decode 吞吐降到约 1/4——用 n 换质量必须算吞吐账。生产实践:n 采样主要用于离线批处理(质量优先)或低峰时段;在线高吞吐场景慎用。
6. Beam Search 在 vLLM 的现状
结论先说:vLLM 已不支持 Beam Search(v0.26 的 SamplingParams 中没有 beam 相关参数)。
- 历史上 vLLM 曾支持 beam search(早期版本),后因实现复杂度与收益比低而移除
- 原因:beam search 需要并行维护 k 个序列 + 每步去重,与 Continuous Batching 的调度模型冲突;且大模型场景下 beam 的收益(相对 n 采样 + 打分)并不明显
- 替代路径:
n采样 → 外部评分(logprob / 规则 / 奖励模型)→ 择优——灵活且能与业务评分器结合
💡 提示:需要”结构化搜索”(约束下找最优)时,优先考虑 8.1 的受约束解码 + n 采样 组合,而不是 beam——约束保证合法性,n 提供多样性,打分器择优。这也是现代推理引擎的共识方向。
7. 采样参数与性能的相互作用
7.1 采样对性能的直接影响
| 因素 | 影响 |
|---|---|
n 并行采样 | decode 计算 ×n(最大影响项) |
logprobs / top_logprobs | 每步多算候选概率,响应体积↑(影响小但存在) |
max_tokens | 决定最长 decode 步数——采样质量差 → 输出更长 → 成本更高 |
stop 序列 | 及时截断废话,间接省 token |
7.2 参数与质量的三角
质量(确定性)
╱ ╲
╱ ╲
多样性 ──────── 成本
(temperature↑、n↑ 都推高成本)
- 确定性任务:temperature=0(或极低)+ 结构化输出(8.1)——质量与成本双优
- 创意任务:temperature 0.7-1.0 + top_p 0.9 + min_p——多样性可控
- 质量兜底:低 temperature + n 采样 + 打分——成本换质量
📌 关键点:采样参数是产品参数,不是性能参数——但性能团队必须懂它:一个”temperature=1 + 无 stop + n=4”的配置,能让所有延迟优化白费。上线前把每个端点的采样配置纳入评审(SLO 的输入之一),跟 7.4 的 goodput 视角闭环。
7.3 快速调参表
| 症状 | 调整 |
|---|---|
| 输出重复/复读 | repetition_penalty 1.1-1.3 或 presence_penalty 0.5-1.0 |
| 输出太随机/幻觉 | temperature ↓(0.3-0.6)、top_p ↓(0.85-0.9) |
| 输出太死板/千篇一律 | temperature ↑(0.8-1.0)、min_p 打开 |
| 需要可复现 | seed 固定 |
| 需要候选择优 | n + logprobs + 外部打分 |
📝 总结
- 两种模式:贪心(T=0)与采样;采样管线 = logits → 缩放 → 惩罚 → 截断 → softmax → 采样
- 截断三兄弟:top_k(固定数量)/ top_p(累计质量)/ min_p(相对阈值)——推荐 top_p + min_p
- 惩罚三件:presence(出现一次即罚)/ frequency(按次数)/ repetition(指数)——各治一种重复
- logprobs:置信度信号源,可做”低置信→重试”兜底;注意响应体积
- n 采样:共享 prefill、decode ×n——离线质量优先场景用,在线算清账
- Beam Search 已移除:替代 = n 采样 + 外部打分
- 性能联动:采样配置直接影响成本与延迟,纳入上线评审
🎯 自我检验清单
- temperature=0 是什么模式?T>1 对分布和多样性/质量的影响?
- top_k / top_p / min_p 的机制差异?为什么推荐 top_p+min_p?
- presence / frequency / repetition 三个惩罚各治什么?
- logprobs 能做什么?响应体积影响怎么评估?
- n 并行采样的成本结构?(共享什么、放大什么)
- vLLM 为什么移除 beam search?替代方案是什么?
- 你的端点采样配置和 SLO/成本怎么联动?
📚 参考资料
- vLLM 源码:vllm/sampling_params.py(v0.26.0)(https://github.com/vllm-project/vllm/blob/v0.26.0/vllm/sampling_params.py)
- Holtzman et al., The Curious Case of Neural Text Degeneration(top-p)(https://arxiv.org/abs/1904.09751)
- OpenAI API 文档:Sampling parameters(https://platform.openai.com/docs/api-reference/chat/create)
- Wang et al., Self-Consistency Improves Chain of Thought Reasoning(https://arxiv.org/abs/2203.11171)