Temperature 和 Top-p:你以为在调"随机性",其实在调大模型的"性格"

6 阅读5分钟

每次调用 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,核采样)的逻辑不同——它不改变概率,而是截断候选词列表

原理:

  1. 将所有词按概率从高到低排列
  2. 从最高概率开始累加,直到累积概率达到 p
  3. 只在这个"核"(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 官方建议:temperaturetop-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
  • 两个参数不要同时调整