【大模型应用开发】采样与生成参数详解 —— temperature、top-p、top-k 怎么调?
5.1 先搞清楚:LLM 的输出不是"查答案"
很多人的误解:LLM 像数据库,查一下就知道该输出什么。
实际上:模型每生成一个 Token,都是在做"选择题"。
模型会为词汇表里的每个词计算一个概率,然后从这个概率分布里挑一个词作为输出。
输入:"中国的首都是____"
模型内部(简化):
北京 → 概率 0.85
上海 → 概率 0.07
南京 → 概率 0.03
东京 → 概率 0.01
其他词 → 概率 0.04
看到没有?模型眼里没有"唯一正确答案",只有一个概率分布。而 temperature、top-p、top-k 这些参数,控制的就是"怎么从分布里选词"。

图 1:LLM 不是查答案,而是面对概率分布做选择题。
5.2 temperature(温度):调节"胆子"
原理
在选词之前,模型会先把原始概率经过一个"软化"步骤(softmax),temperature 就是这个过程的缩放因子:
概率'ᵢ = exp(得分ᵢ / temperature) / Σ exp(得分ⱼ / temperature)
看不懂公式没关系,记住直觉就行:
| temperature | 效果 | 类比 |
|---|---|---|
| 低(0~0.3) | 几乎总是选最高概率的词 | 刻板的优等生,每次都写标准答案 |
| 中(0.7~1.0) | 偶尔选概率稍低的词 | 正常人,回答自然有变化 |
| 高(1.2~2.0) | 经常选冷门词,输出天马行空 | 喝醉的诗人,啥都敢说 |
实际效果演示(同一问题"讲个笑话")
temperature = 0.1 → 每次回答都差不多,风格固定
temperature = 0.7 → 每次略有不同,但都在正常范围
temperature = 1.5 → 可能冒出很怪的梗,甚至逻辑混乱
怎么选
| 任务类型 | 推荐 temperature |
|---|---|
| 代码生成 | 0 ~ 0.2 |
| 数学/逻辑推理 | 0 ~ 0.3 |
| 翻译 | 0.3 |
| 通用对话 | 0.7 |
| 文案创意/头脑风暴 | 0.9 ~ 1.2 |
| 诗歌/脑洞 | 1.2+ |
核心心法:任务越"需要确定性",温度越低;任务越"需要多样性",温度越高。

图 2:temperature 就像旋钮,低则刻板,高则"喝醉"。
5.3 top-k:只给前几名机会
top-k 的意思是:只允许模型从概率最高的 k 个词里选,其余全部清零。
k = 5 时:
排序后的概率:
北京 0.85 ✅
上海 0.07 ✅
南京 0.03 ✅
天津 0.02 ✅
广州 0.01 ✅
东京 0.01 ❌ 被排除
纽约 0.008 ❌ 被排除
k = 1≈ 每次选概率最高的(等价于贪心)k = 10左右比较常用- 作用:剔除概率太低、明显不合理的词,避免突然蹦出奇怪的词
5.4 top-p(核采样):按累计概率截断
top-p 不看排名,看累计概率:从概率最高的词开始累加,直到累计概率超过 p 就截断。
p = 0.9 时:
累加过程:
北京 0.85 → 累计 0.85
上海 0.07 → 累计 0.92 ≥ 0.9 停止 ✅
南京 0.03 → 被排除 ❌
对比 top-k 和 top-p:
| 参数 | 截断依据 | 特点 |
|---|---|---|
| top-k | 固定数量 | 简单,但 k 设多少不看分布情况 |
| top-p | 动态比例 | 分布集中时保留少,分布分散时保留多,更智能 |
OpenAI 官方建议:temperature 和 top-p 通常只调一个,不要同时猛调,否则输出可能不稳定。

图 3:top-k 按"前 k 名"截断,top-p 按"累计概率"截断。
5.5 惩罚参数:frequency_penalty 和 presence_penalty
这两个参数解决的是同一个痛点:模型爱重复自己。
presence_penalty(存在惩罚)
这个词出现过就扣分。防止模型反复提同一个词/话题。
presence_penalty = 0 → 模型可能反复说"我觉得"
presence_penalty = 0.6 → 说过"我觉得"后,再说的概率降低
frequency_penalty(频率惩罚)
出现次数越多扣分越多。专门治"一句话说三遍"的毛病。
| 参数 | 范围 | 典型用途 |
|---|---|---|
| presence_penalty | -2 ~ 2 | 让回答不跑题、不唠叨 |
| frequency_penalty | -2 ~ 2 | 治复读机、治列表刷屏 |
一般设
0.3 ~ 0.8就够用,设太大模型会说话不自然(故意避开常用词)。
5.6 动手实验:手写一个 mini 采样器
不用调 API,纯 Python 就能模拟整个采样过程:
import numpy as np
vocab = ["北京", "上海", "南京", "东京", "纽约", "巴黎"]
logits = np.array([4.0, 2.0, 1.5, 0.5, 0.3, 0.2]) # 模型原始的"得分"
def softmax_with_temperature(logits, temperature):
"""temperature 越大,分布越平(更随机)"""
scaled = logits / temperature
exp = np.exp(scaled - np.max(scaled)) # 数值稳定处理
return exp / exp.sum()
def top_k_filter(probs, k):
"""只保留概率最高的 k 个词"""
threshold = np.sort(probs)[-k] # 第 k 大的概率
filtered = np.where(probs >= threshold, probs, 0)
return filtered / filtered.sum()
def top_p_filter(probs, p):
"""按累计概率截断"""
sorted_idx = np.argsort(probs)[::-1]
cumsum = np.cumsum(probs[sorted_idx])
keep = sorted_idx[cumsum <= p]
filtered = np.zeros_like(probs)
filtered[keep] = probs[keep]
return filtered / filtered.sum()
def sample(probs):
"""按概率分布随机抽一个"""
return np.random.choice(len(probs), p=probs)
# 实验:不同 temperature 下的分布变化
for temp in [0.2, 0.7, 1.5]:
probs = softmax_with_temperature(logits, temp)
print(f"temperature={temp}: 北京={probs[0]:.3f} 上海={probs[1]:.3f} "
f"东京={probs[3]:.3f} 巴黎={probs[5]:.3f}")
运行结果(示意):
temperature=0.2: 北京=0.987 上海=0.012 东京=0.000 巴黎=0.000
temperature=0.7: 北京=0.728 上海=0.164 东京=0.014 巴黎=0.009
temperature=1.5: 北京=0.433 上海=0.196 东京=0.054 巴黎=0.040
看到没有?温度一高,"北京"从 98.7% 掉到 43.3%,冷门词的机会上来了。 这就是 temperature 的全部秘密。
5.7 组合建议速查表
| 场景 | temperature | top_p | 惩罚 |
|---|---|---|---|
| 代码生成 | 0.1 | 1(关闭) | 0 |
| 结构化数据抽取 | 0 | 1 | 0 |
| 翻译 | 0.3 | 1 | 0 |
| 智能客服 | 0.5 | 0.9 | 0.3 |
| 文案创作 | 0.9 | 0.9 | 0.6 |
| 头脑风暴 | 1.2 | 0.95 | 0.6 |
最后记住一条铁律:先调 temperature 一个参数,不够再加 top-p,最后才考虑惩罚参数。别一上来全调满,你根本不知道是谁的锅。
更多推荐
所有评论(0)