一、很多人调过 temperature,但不一定懂它在干嘛

用过 OpenAI / Anthropic / 各大模型 API 的人,几乎都在请求参数里见过 temperature。有人告诉我"调低更稳定,调高更有创造性",于是也就这么用了。但如果追问一句:**为什么温度高就更"有创造性"?它到底动了模型内部的什么?**很多人就答不上来了。

这篇就用最直观的方式把这件事讲清楚。我们不堆公式,用 Python 一步步把大模型生成一个 token 的过程拆开看:logits → softmax → top-k / top-p → temperature 缩放 → 采样。看完你能真正理解这坨参数的关系,以后调参不再靠玄学。

二、第一步:模型输出一堆未归一化的分数(logits)

先明确一点:大模型其实是个"下一词预测器"。给定前面已经生成的所有 token,它要做的是给词汇表里每个可能的词都打一个分,然后选一个作为下一个词。

模型最后输出的这一堆原始分数,就叫 logits——它是模型"原始的马力",还不是概率。随便给个例子,假设词表只有 5 个词:

vocab = ["苹果", "香蕉", "运行", "很好", "今天"]
logits = [2.0, 1.0, 0.5, -1.0, -2.0]   # 模型输出的原始分数

分数越高,表示模型越"倾向"选这个词。这里 苹果 得了 2.0 分,今天 是 -2.0。关键在这:**这些分数还没有经过任何加工,可以直接当"概率"看吗?不行。**因为它们可以是负数、也没有加起来等于 1,根本不是一个合法的概率分布。

所以下一步,要把 logits 变成"合法概率"。

三、第二步:softmax 把分数变成概率

softmax 这个函数就是干这个活的:把任意一串实数,变成一串"都为正、加起来等于 1"的概率。公式很简单:

p_i = exp(logit_i) / Σ exp(logit_j)

用代码写出来:

import math

def softmax(logits):
    # 为了数值稳定,先减掉最大值(不影响结果,只让 exp 不溢出)
    m = max(logits)
    exp_i = [math.exp(x - m) for x in logits]
    total = sum(exp_i)
    return [e / total for e in exp_i]

probs = softmax(logits)
for word, p in zip(vocab, probs):
    print(f"{word}: {p:.4f}")

输出大概是:

苹果: 0.49
香蕉: 0.20
运行: 0.13
很好: 0.09
今天: 0.09

看到没,苹果 的概率约 0.5,并不是 1.0——即使模型最看重某个词,其它词也依然有概率,只是小一些。这正是语言模型"有随机性"的根源:它不是在"选最可能的词",而是在"按概率抽一个词"。

那么问题来了:如果我们把 logits 每项都放大或缩小,会怎样?

四、第三步:temperature 就是给 logits 做缩放

这就是温度的实质——temperature 是对 logits 做除法缩放,再进 softmax

p_i = exp(logit_i / T) / Σ exp(logit_j / T)     # T 就是 temperature

  • T < 1(如 0.2):logits 被放大,最大值在 softmax 里更"一枝独秀",概率分布更尖锐 → 生成更稳定、更保守、更接近"最可能答案"
  • T = 1:不变,就是原始分布
  • T > 1(如 1.5):logits 被缩小,分布更"平坦",概率差距变小 → 生成更多样、更有"随机感"

看代码(在上一节 softmax 基础上加一个除法就行):

def softmax_t(logits, temperature):
    scaled = [x / temperature for x in logits]
    return softmax(scaled)

print("T=0.2:", ["%.4f" % p for p in softmax_t(logits, 0.2)])
print("T=1.0:", ["%.4f" % p for p in softmax_t(logits, 1.0)])
print("T=2.0:", ["%.4f" % p for p in softmax_t(logits, 2.0)])

假设输出:

T=0.2: [0.97, 0.02, 0.00, 0.00, 0.00]   # 几乎只选苹果
T=1.0: [0.49, 0.20, 0.13, 0.09, 0.09]   # 原始分布
T=2.0: [0.31, 0.21, 0.17, 0.09, 0.21]   # 更平坦,候选更分散

看到 T=0.2 那行了吗?苹果 几乎被独占。T=2.0 时,今天 的概率爬到和 香蕉 差不多了——所以温度高不等于"想得更好",而是"更敢乱猜、更发散"

现在你再回头理解文档里写的"temperature 调低 = 更稳定/更符合事实",就通了:因为低温度下模型基本只敢选它最有把握的词,奇奇怪怪的想象被概率压掉了;调高则相反。

五、第四步:采样还要配 top-k / top-p

实际工程里,光靠温度还不够,因为词表动辄几万甚至十几万 token,低概率的"幺蛾子"累积起来也不小。所以绝大多数推理栈会在 softmax 之后、选词之前,再套两个"截断器":

  • top-k:只从概率最高的前 k 个词里选。k=50 表示"49 个备胎都不要,就看前 50 名"
  • top-p(nucleus sampling):从累计概率达到 p 的最小候选集里选。p=0.9 表示"一直从最高概率往下加,加到 0.9 为止,这些词才准参与抽签"

一个典型的完整采样过程(Hugging Face 的 generate 底层就是这么做的):

import random
random.seed(42)

def sample_greedy(probs):
    return vocab[probs.index(max(probs))]   # 总是选最大

def sample_top_k(probs, k):
    idx = sorted(range(len(probs)), key=lambda i: probs[i], reverse=True)[:k]
    chosen = random.choices(idx, weights=[probs[i] for i in idx])[0]
    return vocab[chosen]

def sample_top_p(probs, p):
    order = sorted(range(len(probs)), key=lambda i: probs[i], reverse=True)
    acc, keep = 0.0, []
    for i in order:
        keep.append(i); acc += probs[i]
        if acc >= p:
            break
    chosen = random.choices(keep, weights=[probs[i] for i in keep])[0]
    return vocab[chosen]

probs = softmax_t(logits, 1.0)
print("greedy  :", sample_greedy(probs))
print("top-k 3 :", sample_top_k(probs, 3))
print("top-p .8:", sample_top_p(probs, 0.8))

三者差别在哪:

  • greedy 永远是"最大概率",稳定但容易重复、死板
  • top-k 固定候选数量,但 k 值难调(不同时刻"合适"的词数量不一样)
  • top-p 按累计概率动态收缩候选集,是现在最主流的方案(GPT/Claude 默认都以它为核心)

工程经验:temperature 负责"热闹程度",top-p 负责"纪律底线"。两者通常配合用——尤其在需要"有点创造性但不能跑偏"的场景(比如代码注释、创意文案前半段),常见的配比是 T 调 0.81.1、p 保持 0.91.0。

六、总结:一张表记住它们的关系

参数作用对象取值含义直观效果
logits模型原始分数分数越高越被偏好数据的"源头"
softmaxlogits → 概率归一化,和为1把分数变候选概率
temperature缩放 logits<1 收敛,>1 发散低=稳定,高=创造性
top-ksoftmax后截断只看前 k 个词压掉低概率噪音
top-psoftmax后截断累计概率到 p动态收窄候选集
greedy采样策略总选最大最稳但易重复

一句话收尾:temperature 不是"聪明度",而是"胆量"——它决定模型敢不敢在低概率的词里冒险。真正要冲质量,靠的是好的 prompt、可靠的流程和够用的数据;采样参数只是在"创造性与稳定性"之间帮你找一个合适的平衡点。调参表再多,都不如先想清楚"这一步到底需要多大胆"。

本文为技术科普,示例代码可直接运行;不同框架参数名略有差异(如 OpenRouter 用 temperature、Hugging Face 用 do_sample+temperature),但底层原理一致。

更多推荐