每次调用 AI API 都能看到 temperature 这个参数,大多数人的理解是"越高越随机"。但这个理解是错的,或者说太浅了。这篇文章告诉你它真正控制的是什么。
从一个反直觉的例子开始
同样一个问题:"帮我起一个创业公司的名字"
temperature = 0:每次给你同样的答案temperature = 1:每次给你不同的答案temperature = 2:给你一堆你看不懂的奇怪组合
大多数人到这里就停了——"哦,temperature 控制随机性。"
但这个理解会让你在实际使用中犯很多错误:
- 为什么代码任务设高 temperature 反而更烂?
- 为什么创意写作设低 temperature 不是更"稳定",而是"无聊"?
- top-p 和 temperature 都能控制输出,用哪个?同时用会怎样?
先理解模型生成文本的底层机制
LLM 生成文本不是"随机乱选",而是每次计算所有可能的下一个词的概率分布,然后从这个分布中采样。
假设输入"今天天气",模型计算出:
"很好" → 概率 0.45
"不错" → 概率 0.25
"晴朗" → 概率 0.15
"糟糕" → 概率 0.08
"下雨" → 概率 0.05
其他词 → 概率 0.02
采样就是按照这个概率分布"抽奖":概率高的词更容易被选中,但不是一定被选中。
Temperature 和 Top-p 的作用,就是在采样之前修改这个概率分布的形状。
Temperature:改变概率分布的"陡峭程度"
Temperature(温度)来自热力学的玻尔兹曼分布,数学上它对每个 logit(原始分数)做这样的变换:
调整后的概率 = softmax(logits / temperature)
temperature < 1(降温):分布变陡峭
原始分布: temperature = 0.3:
"很好" 0.45 "很好" 0.75 ↑
"不错" 0.25 → "不错" 0.15 ↓
"晴朗" 0.15 "晴朗" 0.06 ↓
"糟糕" 0.08 "糟糕" 0.02 ↓
效果:最高概率的词被进一步强化,输出更可预测、更保守。
temperature > 1(升温):分布变平坦
原始分布: temperature = 1.5:
"很好" 0.45 "很好" 0.30 ↓
"不错" 0.25 → "不错" 0.22 ↓
"晴朗" 0.15 "晴朗" 0.18 ↑
"糟糕" 0.08 "糟糕" 0.15 ↑
效果:低概率词被"提升",输出更多样、更出乎意料,但也更容易产生错误。
temperature = 0(极限情况):贪心解码
直接选概率最高的词,每次输出完全一致。这不是"随机性为零",而是完全确定性输出。
Top-p(核采样):改变候选词池的大小
Top-p(也叫 Nucleus Sampling,核采样)的逻辑不同——它不改变概率,而是截断候选词列表。
原理:
- 将所有词按概率从高到低排列
- 从最高概率开始累加,直到累积概率达到 p
- 只在这个"核"(nucleus)里采样,丢弃其他所有词
top-p = 0.9,原始分布:
累积概率计算:
"很好" 0.45 → 累积 0.45
"不错" 0.25 → 累积 0.70
"晴朗" 0.15 → 累积 0.85
"糟糕" 0.08 → 累积 0.93 ✓ 超过 0.9,截止
候选词池:["很好", "不错", "晴朗", "糟糕"](4个词)
从这 4 个词中按原始概率比例采样
top-p 的意义:动态调整候选词数量。当模型"很确定"时,候选词池小;当模型"不确定"时,候选词池大。这比 temperature 更符合直觉。
Temperature vs Top-p:应该用哪个?
这是个常见问题,答案是:通常只调其中一个,另一个保持默认值。
| 参数 | 控制维度 | 默认值 | 典型调整场景 |
|---|---|---|---|
| Temperature | 概率分布陡峭程度 | 1.0 | 需要控制输出的"大胆程度" |
| Top-p | 候选词池大小 | 1.0(不截断) | 需要控制词汇多样性 |
如果两个都调:它们的效果会叠加,互相影响,很难预测结果,不推荐。
OpenAI 官方建议:temperature 和 top-p 只修改其中一个。
不同任务的推荐参数配置
代码生成:低 Temperature
# 代码要求确定性、正确性
response = client.messages.create(
model="claude-3-5-sonnet",
temperature=0.1, # 接近确定性输出
top_p=1.0,
messages=[{"role": "user", "content": "实现快速排序算法"}]
)
为什么:代码有正确答案,你不需要"创意",你需要的是模型选择最可能正确的实现方式。
创意写作:中等 Temperature
# 故事创作需要一定的意外性
response = client.messages.create(
model="claude-3-5-sonnet",
temperature=0.8,
messages=[{"role": "user", "content": "写一段开头很抓人的科幻故事"}]
)
数据提取 / 分类:Temperature = 0
# 从文本中提取结构化信息,要求完全确定性
response = client.messages.create(
model="claude-3-5-sonnet",
temperature=0, # 完全确定性
messages=[{"role": "user", "content": "从以下文本中提取姓名、日期、金额..."}]
)
头脑风暴:高 Temperature
# 需要多样化、非常规的想法
response = client.messages.create(
model="claude-3-5-sonnet",
temperature=1.2,
messages=[{"role": "user", "content": "给这个产品想 10 个完全不同的营销角度"}]
)
常见误区纠正
误区一:"temperature = 0 最安全,所有任务都用 0"
错。代码任务用 0 是对的,但让模型总结文章用 0,它会给你每次一模一样的摘要,不一定是最好的,只是"最保守的"。
误区二:"temperature 越高,模型越聪明/有创意"
错。超过 1.2 左右,模型开始输出语法错误、逻辑混乱的内容——那不是"创意",那是"胡言乱语"。
误区三:"top-p 是 top-k 的升级版"
这里顺带说一下 top-k:top-k 是只保留概率最高的 k 个词。top-p 比 top-k 更灵活(词池大小动态调整),但不是"升级"关系——它们解决的是同一个问题的不同思路。
用一个实验感受差异
同样的 Prompt:"描述一片森林",不同参数的典型输出风格:
| 参数 | 输出风格 |
|---|---|
| temp=0 | "森林是由大量树木组成的生态系统,通常包含..." (准确但干燥) |
| temp=0.7 | "阳光透过树冠洒落,斑驳的光影在地面上跳舞..." (流畅自然) |
| temp=1.2 | "树们低语,根系在黑暗中编织着古老的语言..." (有意境但稍偏) |
| temp=1.8 | "绿色的时间鳞片倒挂在光的织物边缘..." (费解) |
总结
Temperature 和 Top-p 不是"随机性开关",而是对模型概率分布的两种不同形式的干预:
- Temperature:拉伸或压缩整个概率分布的形状
- Top-p:截断候选词池,控制可选词汇范围
实际使用建议:
- 精确任务(代码、提取、分类):temperature ≤ 0.3
- 日常对话、总结:temperature 0.5-0.7
- 创意写作、头脑风暴:temperature 0.8-1.2
- 两个参数不要同时调整