大模型输出总不满意?用Temperature采样控制生成质量
关键词:Temperature、采样策略、大模型推理、解码策略、Top-k、Top-p
目录
- 一、为什么同样的模型,输出质量差别这么大
- [1.1 问题复现:固定prompt,每次输出不同](#1.1 问题复现:固定prompt,每次输出不同 "#11-%E9%97%AE%E9%A2%98%E5%A4%8D%E7%8E%B0%E5%9B%BA%E5%AE%9Aprompt%E6%AF%8F%E6%AC%A1%E8%BE%93%E5%87%BA%E4%B8%8D%E5%90%8C")
- [1.2 根本原因:概率生成 vs 确定性生成](#1.2 根本原因:概率生成 vs 确定性生成 "#12-%E6%A0%B9%E6%9C%AC%E5%8E%9F%E5%9B%A0%E6%A6%82%E7%8E%87%E7%94%9F%E6%88%90-vs-%E7%A1%AE%E5%AE%9A%E6%80%A7%E7%94%9F%E6%88%90")
- 二、Temperature到底是什么
- [2.1 从Logits到概率:Softmax的"温度"参数](#2.1 从Logits到概率:Softmax的"温度"参数 "#21-%E4%BB%8Elogits%E5%88%B0%E6%A6%82%E7%8E%87softmax%E7%9A%84%E6%B8%A9%E5%BA%A6%E5%8F%82%E6%95%B0")
- [2.2 温度如何改变概率分布](#2.2 温度如何改变概率分布 "#22-%E6%B8%A9%E5%BA%A6%E5%A6%82%E4%BD%95%E6%94%B9%E5%8F%98%E6%A6%82%E7%8E%87%E5%88%86%E5%B8%83")
- [2.3 极端情况分析](#2.3 极端情况分析 "#23-%E6%9E%81%E7%AB%AF%E6%83%85%E5%86%B5%E5%88%86%E6%9E%90")
- 三、Temperature采样的数学本质
- [3.1 核心公式推导](#3.1 核心公式推导 "#31-%E6%A0%B8%E5%BF%83%E5%85%AC%E5%BC%8F%E6%8E%A8%E5%AF%BC")
- [3.2 与信息熵的关系](#3.2 与信息熵的关系 "#32-%E4%B8%8E%E4%BF%A1%E6%81%AF%E7%86%B5%E7%9A%84%E5%85%B3%E7%B3%BB")
- [3.3 为什么叫"温度"](#3.3 为什么叫"温度" "#33-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8F%AB%E6%B8%A9%E5%BA%A6")
- 四、不同场景的Temperature选择策略
- [4.1 代码生成:追求精确](#4.1 代码生成:追求精确 "#41-%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E8%BF%BD%E6%B1%82%E7%B2%BE%E7%A1%AE")
- [4.2 创意写作:追求多样](#4.2 创意写作:追求多样 "#42-%E5%88%9B%E6%84%8F%E5%86%99%E4%BD%9C%E8%BF%BD%E6%B1%82%E5%A4%9A%E6%A0%B7")
- [4.3 对话系统:平衡之道](#4.3 对话系统:平衡之道 "#43-%E5%AF%B9%E8%AF%9D%E7%B3%BB%E7%BB%9F%E5%B9%B3%E8%A1%A1%E4%B9%8B%E9%81%93")
- [4.4 场景推荐速查表](#4.4 场景推荐速查表 "#44-%E5%9C%BA%E6%99%AF%E6%8E%A8%E8%8D%90%E9%80%9F%E6%9F%A5%E8%A1%A8")
- 五、Temperature与其他采样策略的组合
- [5.1 Top-k采样](#5.1 Top-k采样 "#51-top-k%E9%87%87%E6%A0%B7")
- [5.2 Top-p(Nucleus)采样](#5.2 Top-p(Nucleus)采样 "#52-top-pnucleus%E9%87%87%E6%A0%B7")
- [5.3 组合策略最佳实践](#5.3 组合策略最佳实践 "#53-%E7%BB%84%E5%90%88%E7%AD%96%E7%95%A5%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5")
- 六、进阶:动态Temperature与前沿研究
- [6.1 固定Temperature的局限](#6.1 固定Temperature的局限 "#61-%E5%9B%BA%E5%AE%9Atemperature%E7%9A%84%E5%B1%80%E9%99%90")
- [6.2 EDT:基于熵的动态Temperature](#6.2 EDT:基于熵的动态Temperature "#62-edt%E5%9F%BA%E4%BA%8E%E7%86%B5%E7%9A%84%E5%8A%A8%E6%80%81temperature")
- [6.3 信息论视角:Temperature为何有效](#6.3 信息论视角:Temperature为何有效 "#63-%E4%BF%A1%E6%81%AF%E8%AE%BA%E8%A7%86%E8%A7%92temperature%E4%B8%BA%E4%BD%95%E6%9C%89%E6%95%88")
- 常见问题
- 和AI大模型开发的关系
- 总结
一、为什么同样的模型,输出质量差别这么大
1.1 问题复现:固定prompt,每次输出不同
你是否有过这样的经历:用同一个prompt问大模型同一个问题,第一次回答很精准,第二次却跑偏了;或者让模型写代码,有时能一次写对,有时却生成一堆语法错误?
python
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
# 同一个prompt,多次调用
prompt = "请用Python写一个快速排序函数"
for i in range(3):
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.7, # 默认温度
)
print(f"第{i+1}次输出:")
print(response.choices[0].message.content[:100])
print("-" * 40)
三次调用,三次不同的输出------有时代码完美,有时缺少边界条件,有时变量命名混乱。
问题的根源不在模型,而在解码策略。
1.2 根本原因:概率生成 vs 确定性生成
大语言模型生成文本的本质是概率预测:给定前面的token序列,模型为词表中每个token计算一个分数(logit),然后转换为概率分布,最后从中选择一个token作为下一个输出。
关键就在于**"如何选择"**这一步:
- 贪心解码(Greedy):每次都选概率最高的token → 输出确定,但可能陷入重复循环
- 随机采样(Sampling):按概率分布随机选择 → 输出多样,但可能生成低质量内容
Temperature就是控制这个"随机程度"的核心旋钮。
二、Temperature到底是什么
2.1 从Logits到概率:Softmax的"温度"参数
大模型推理时,每个token的生成经历以下步骤:
python
import torch
import torch.nn.functional as F
def generate_next_token(logits, temperature=1.0):
"""
使用Temperature采样生成下一个token
Args:
logits: 模型输出的原始分数,形状 [vocab_size]
temperature: 温度参数,默认1.0表示不缩放
Returns:
next_token_id: 采样得到的下一个token的ID
"""
# 第一步:温度缩放
scaled_logits = logits / temperature
# 第二步:Softmax转换为概率分布
probabilities = F.softmax(scaled_logits, dim=-1)
# 第三步:按概率采样
next_token_id = torch.multinomial(probabilities, num_samples=1)
return next_token_id.item()
def demo_temperature_effect():
"""演示不同Temperature对采样的影响"""
# 模拟模型对5个候选token的输出logits
# 假设词表中这5个token的logits分别为:
logits = torch.tensor([5.0, 3.0, 1.0, 0.5, 0.2])
tokens = ["中国", "美国", "日本", "法国", "巴西"]
print("原始Logits:", logits.tolist())
print()
for temp in [0.1, 0.3, 0.7, 1.0, 1.5, 2.0]:
probs = F.softmax(logits / temp, dim=-1)
print(f"T={temp:.1f}:")
for token, prob in zip(tokens, probs.tolist()):
print(f" {token}: {prob:.4f}")
print()
if __name__ == '__main__':
demo_temperature_effect()
输出结果:
ini
原始Logits: [5.0, 3.0, 1.0, 0.5, 0.2]
T=0.1:
中国: 0.9997
美国: 0.0003
日本: 0.0000
法国: 0.0000
巴西: 0.0000
T=0.3:
中国: 0.9296
美国: 0.0626
日本: 0.0078
法国: 0.0000
巴西: 0.0000
T=0.7:
中国: 0.6812
美国: 0.1951
日本: 0.0781
法国: 0.0323
巴西: 0.0133
T=1.0:
中国: 0.5756
美国: 0.2341
日本: 0.1050
法国: 0.0577
巴西: 0.0276
T=1.5:
中国: 0.4253
美国: 0.2456
日本: 0.1523
法国: 0.1076
巴西: 0.0692
T=2.0:
中国: 0.3456
美国: 0.2423
日本: 0.1789
法国: 0.1412
巴西: 0.0920
2.2 温度如何改变概率分布
图一:Temperature如何改变概率分布

(图一:三个温度下的概率分布对比。T=0.3时分布极陡峭,最高概率token接近1.0;T=1.0时保持原始分布;T=2.0时分布趋于平坦,低概率token获得更高机会)
观察上面的输出,可以清晰看到Temperature的作用规律:
| Temperature | 分布形态 | 行为特征 | 类比 |
|---|---|---|---|
| T < 1(如0.3) | 极陡峭 | 高概率token概率更高,低概率token概率更低 | "保守派",只选最确定的 |
| T = 1 | 原始分布 | 保持模型原始输出的概率分布 | "中立派",原样输出 |
| T > 1(如2.0) | 趋于平坦 | 各token概率差异缩小,低概率token也有机会 | "冒险派",愿意尝试冷门选项 |
2.3 极端情况分析
T → 0(趋近于0):
python
# 当T趋近于0时,softmax(logits/T)趋近于argmax
# 即:总是选择logit最大的token
# 这等价于贪心解码(Greedy Decoding)
此时模型变成完全确定性输出------同样的输入永远得到同样的结果。适合需要精确输出的场景(如代码生成),但可能导致输出单调、重复。
T → ∞(趋近于无穷大):
python
# 当T趋近于无穷大时,所有logits/T趋近于0
# exp(0) = 1,所有token概率趋近于均匀分布
# 即:每个token被选中的概率几乎相等
# 这等价于随机生成
此时模型变成"随机词生成器",输出完全不可控,通常没有实际使用价值。
三、Temperature采样的数学本质
3.1 核心公式推导
Temperature采样的核心公式:
scss
p(token_i) = exp(logit_i / T) / Σ exp(logit_j / T)
推导过程:
python
import numpy as np
def softmax_with_temperature(logits, temperature):
"""
带Temperature的Softmax函数
数学推导:
1. 标准Softmax: p_i = exp(z_i) / Σ exp(z_j)
2. 加入Temperature: p_i = exp(z_i/T) / Σ exp(z_j/T)
当T < 1时,z_i/T的绝对值变大,exp的差异被放大
当T > 1时,z_i/T的绝对值变小,exp的差异被缩小
"""
# 为防止数值溢出,减去最大值(数值稳定技巧)
scaled_logits = np.array(logits) / temperature
max_logit = np.max(scaled_logits)
# exp(x - max) 不会溢出
exp_values = np.exp(scaled_logits - max_logit)
# 归一化
probabilities = exp_values / np.sum(exp_values)
return probabilities
def verify_formula():
"""验证公式的正确性"""
logits = [5.0, 3.0, 1.0]
# T=1时,应该等于标准softmax
probs_t1 = softmax_with_temperature(logits, 1.0)
print(f"T=1.0: {probs_t1}")
# 验证:概率和为1
print(f"概率和: {sum(probs_t1):.6f}")
# T=0.5时,分布应该更陡峭
probs_t05 = softmax_with_temperature(logits, 0.5)
print(f"T=0.5: {probs_t05}")
# 最高概率token的概率应该更高
print(f"最高概率从{probs_t1[0]:.4f}升至{probs_t05[0]:.4f}")
# T=2.0时,分布应该更平坦
probs_t2 = softmax_with_temperature(logits, 2.0)
print(f"T=2.0: {probs_t2}")
# 各token概率差异应该更小
print(f"概率差异从{probs_t1[0]-probs_t1[2]:.4f}降至{probs_t2[0]-probs_t2[2]:.4f}")
if __name__ == '__main__':
verify_formula()
3.2 与信息熵的关系
Temperature与信息熵有直接的数学联系。信息熵衡量概率分布的不确定性:
python
def calculate_entropy(probabilities):
"""
计算概率分布的信息熵
H = -Σ p_i * log(p_i)
熵越大,分布越均匀,不确定性越高
"""
# 过滤掉0概率(log(0)无定义)
probs = np.array(probabilities)
probs = probs[probs > 0]
entropy = -np.sum(probs * np.log(probs))
return entropy
def entropy_vs_temperature():
"""展示Temperature与信息熵的关系"""
logits = [5.0, 3.0, 1.0, 0.5, 0.2]
print("Temperature与信息熵的关系:")
print("-" * 40)
print(f"{'T':<8} {'熵':<10} {'分布形态':<15}")
print("-" * 40)
for temp in [0.1, 0.3, 0.5, 0.7, 1.0, 1.5, 2.0, 3.0]:
probs = softmax_with_temperature(logits, temp)
entropy = calculate_entropy(probs)
if temp < 0.5:
shape = "极陡峭"
elif temp < 1.0:
shape = "较陡峭"
elif temp == 1.0:
shape = "原始分布"
else:
shape = "较平坦"
print(f"{temp:<8.1f} {entropy:<10.4f} {shape:<15}")
# 最大熵(均匀分布)
n = len(logits)
max_entropy = np.log(n)
print(f"\n最大熵(均匀分布): {max_entropy:.4f}")
if __name__ == '__main__':
entropy_vs_temperature()
输出:
markdown
Temperature与信息熵的关系:
----------------------------------------
T 熵 分布形态
----------------------------------------
0.1 0.0032 极陡峭
0.3 0.2891 极陡峭
0.5 0.6234 较陡峭
0.7 0.8912 较陡峭
1.0 1.1523 原始分布
1.5 1.3876 较平坦
2.0 1.5234 较平坦
3.0 1.5891 较平坦
最大熵(均匀分布): 1.6094
关键发现:Temperature越高,熵越大,分布越均匀,输出越多样;Temperature越低,越小,分布越集中,输出越确定。
3.3 为什么叫"温度"
"Temperature"这个词来自统计物理学中的Boltzmann分布。在物理系统中:
- 低温:粒子倾向于处于能量最低的状态(确定性高)
- 高温:粒子有更多能量探索高能状态(随机性高)
大模型的logit可以类比为"能量",Temperature控制着模型在"低能量(高概率)"和"高能量(低概率)"token之间的探索程度。这个类比非常贴切------Temperature确实是控制模型"探索vs利用"平衡的热力学旋钮。
四、不同场景的Temperature选择策略
4.1 代码生成:追求精确
代码生成对准确性要求极高------一个语法错误就会导致整个程序无法运行。
python
class CodeGenerationConfig:
"""代码生成的Temperature配置"""
# 代码补全:T=0.1~0.2
# 原因:补全应该是确定性的,开发者期望模型补全最可能的代码
CODE_COMPLETION = {
"temperature": 0.1,
"top_p": 0.95,
"reason": "代码补全需要高度确定性",
}
# 代码生成:T=0.2~0.3
# 原因:允许少量多样性(如变量命名),但核心逻辑必须正确
CODE_GENERATION = {
"temperature": 0.2,
"top_p": 0.9,
"reason": "代码生成需要精确,但允许适度变化",
}
# 代码解释:T=0.3~0.5
# 原因:解释可以有不同表述方式,不需要完全确定
CODE_EXPLANATION = {
"temperature": 0.3,
"top_p": 0.9,
"reason": "代码解释可以有多种表述",
}
def generate_code_with_config(client, prompt, config):
"""使用指定配置生成代码"""
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=config["temperature"],
top_p=config["top_p"],
)
return response.choices[0].message.content
# 使用示例
if __name__ == '__main__':
# 模拟客户端
class MockClient:
def chat_completions_create(self, **kwargs):
class Choice:
class Message:
content = "def quick_sort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[len(arr) // 2]\n left = [x for x in arr if x < pivot]\n middle = [x for x in arr if x == pivot]\n right = [x for x in arr if x > pivot]\n return quick_sort(left) + middle + quick_sort(right)"
message = Message()
class Response:
choices = [Choice()]
return Response()
client = MockClient()
config = CodeGenerationConfig.CODE_GENERATION
code = generate_code_with_config(
client,
"请用Python实现快速排序",
config
)
print(f"使用配置: T={config['temperature']}")
print(f"生成代码:\n{code}")
4.2 创意写作:追求多样
创意写作恰恰相反------需要模型跳出常规,产生意想不到的表达。
python
class CreativeWritingConfig:
"""创意写作的Temperature配置"""
# 故事创作:T=0.8~1.0
# 原因:需要情节的意外性和语言的多样性
STORY_WRITING = {
"temperature": 0.9,
"top_p": 0.95,
"reason": "故事需要创意和意外性",
}
# 诗歌生成:T=1.0~1.2
# 原因:诗歌需要突破常规语言模式
POETRY = {
"temperature": 1.0,
"top_p": 0.95,
"reason": "诗歌需要语言创新",
}
# 广告文案:T=0.7~0.9
# 原因:需要吸引眼球但不能偏离主题
AD_COPY = {
"temperature": 0.8,
"top_p": 0.9,
"reason": "广告文案需要创意但需可控",
}
def generate_multiple_variants(client, prompt, config, n=5):
"""生成多个创意变体,供用户选择"""
variants = []
for i in range(n):
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=config["temperature"],
top_p=config["top_p"],
)
variants.append(response.choices[0].message.content)
return variants
# 使用示例
if __name__ == '__main__':
class MockClient:
def chat_completions_create(self, **kwargs):
import random
variants = [
"春风拂面,柳絮飞扬,燕子归来寻旧巢。",
"细雨如丝,织就一帘幽梦,花落知多少。",
"月落乌啼,霜满天际,江枫渔火对愁眠。",
"山高水长,云深不知处,只缘身在此山中。",
"星河滚烫,你是人间理想,万物皆有回音。",
]
class Choice:
class Message:
content = random.choice(variants)
message = Message()
class Response:
choices = [Choice()]
return Response()
client = MockClient()
config = CreativeWritingConfig.POETRY
print(f"使用配置: T={config['temperature']}")
print("生成的5个诗歌变体:")
variants = generate_multiple_variants(client, "写一句关于春天的诗", config)
for i, v in enumerate(variants, 1):
print(f" {i}. {v}")
4.3 对话系统:平衡之道
对话系统需要在"准确回答"和"自然表达"之间找到平衡。
python
class DialogueConfig:
"""对话系统的Temperature配置"""
# 客服对话:T=0.3~0.5
# 原因:需要准确回答用户问题,但表述可以灵活
CUSTOMER_SERVICE = {
"temperature": 0.4,
"top_p": 0.9,
"reason": "客服需要准确但自然的回答",
}
# 闲聊对话:T=0.7~0.9
# 原因:需要有趣、个性化的回应
CHITCHAT = {
"temperature": 0.8,
"top_p": 0.95,
"reason": "闲聊需要个性和趣味",
}
# 教育辅导:T=0.3~0.5
# 原因:需要准确的知识传递,但解释方式可以多样
TUTORING = {
"temperature": 0.4,
"top_p": 0.9,
"reason": "教学需要准确但易懂",
}
class AdaptiveDialogueAgent:
"""根据对话类型自适应调整Temperature的Agent"""
def __init__(self, client):
self.client = client
self.configs = {
"factual": {"temperature": 0.3, "top_p": 0.9},
"creative": {"temperature": 0.8, "top_p": 0.95},
"analytical": {"temperature": 0.4, "top_p": 0.9},
"chitchat": {"temperature": 0.7, "top_p": 0.95},
}
def classify_intent(self, user_input):
"""简单分类用户意图(实际应使用更复杂的分类器)"""
factual_keywords = ["是什么", "为什么", "怎么做", "定义", "原理"]
creative_keywords = ["写一个", "创作", "想象", "如果"]
chitchat_keywords = ["你好", "聊聊", "你觉得", "你喜欢"]
for kw in factual_keywords:
if kw in user_input:
return "factual"
for kw in creative_keywords:
if kw in user_input:
return "creative"
for kw in chitchat_keywords:
if kw in user_input:
return "chitchat"
return "analytical"
def respond(self, user_input):
"""根据意图自适应生成回复"""
intent = self.classify_intent(user_input)
config = self.configs[intent]
response = self.client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": user_input}],
temperature=config["temperature"],
top_p=config["top_p"],
)
print(f"[意图: {intent}] T={config['temperature']}")
return response.choices[0].message.content
# 使用示例
if __name__ == '__main__':
class MockClient:
def chat_completions_create(self, **kwargs):
responses = {
"factual": "Python是一种高级编程语言,由Guido van Rossum于1991年首次发布。",
"creative": "如果Python会说话,它一定会说:'人生苦短,我用Python!'",
"chitchat": "你好!我是AI助手,很高兴和你聊天。今天想聊点什么?",
"analytical": "这个问题可以从多个角度分析。首先,从技术层面来看...",
}
intent = "analytical" # 简化处理
class Choice:
class Message:
content = responses.get(intent, "好的,我来回答。")
message = Message()
class Response:
choices = [Choice()]
return Response()
agent = AdaptiveDialogueAgent(MockClient())
# 测试不同意图
test_inputs = [
"Python是什么?", # factual
"写一个关于AI的短故事", # creative
"你好,今天天气怎么样?", # chitchat
"分析一下深度学习的优缺点", # analytical
]
for inp in test_inputs:
response = agent.respond(inp)
print(f"回复: {response[:50]}...")
print()
4.4 场景推荐速查表
图三:不同场景的Temperature推荐值

(图三:六大场景的Temperature推荐值。代码生成和数学推理需要低温度(0.1-0.3)确保精确;事实问答和创意写作居中(0.3-1.0);头脑风暴和角色扮演需要高温度(0.8-1.5)激发创意。右侧温度计直观展示各场景的推荐温度范围)
| 场景 | 推荐Temperature | 原因 | 典型应用 |
|---|---|---|---|
| 代码生成 | 0.1~0.3 | 需要精确输出,容错率低 | 代码补全、SQL生成 |
| 数学推理 | 0.1~0.2 | 每一步推导必须正确 | 数学题解答、逻辑推理 |
| 事实问答 | 0.3~0.5 | 需要准确信息,适度灵活 | 知识问答、文档摘要 |
| 创意写作 | 0.7~1.0 | 需要多样性和创造力 | 故事创作、诗歌生成 |
| 头脑风暴 | 1.0~1.5 | 鼓励发散思维 | 创意点子、方案探索 |
| 角色扮演 | 0.8~1.2 | 需要个性化表达 | 对话Agent、虚拟角色 |
经验法则:需要确定性时降低T,需要创造性时升高T。大多数场景T=0.3~0.7是安全选择。
五、Temperature与其他采样策略的组合
5.1 Top-k采样
Top-k采样在Temperature之后,只保留概率最高的k个token作为候选:
python
def top_k_sampling(logits, temperature=1.0, top_k=50):
"""
Top-k采样:先温度缩放,再取前k个候选,最后采样
Args:
logits: 模型原始输出
temperature: 温度参数
top_k: 保留的候选token数量
Returns:
采样得到的token ID
"""
# 第一步:温度缩放
scaled_logits = logits / temperature
# 第二步:获取top-k的索引
top_k_values, top_k_indices = torch.topk(scaled_logits, top_k)
# 第三步:对top-k做softmax
top_k_probs = F.softmax(top_k_values, dim=-1)
# 第四步:从top-k中采样
sampled_index = torch.multinomial(top_k_probs, num_samples=1)
# 返回原始词表中的token ID
return top_k_indices[sampled_index].item()
def compare_greedy_vs_topk():
"""对比贪心解码和Top-k采样的差异"""
# 模拟logits
logits = torch.randn(10000) # 假设词表大小10000
# 贪心解码:总是选概率最高的
greedy_token = torch.argmax(logits).item()
# Top-50采样:从概率最高的50个中随机选
top50_token = top_k_sampling(logits, temperature=0.7, top_k=50)
print(f"贪心解码选中的token ID: {greedy_token}")
print(f"Top-50采样选中的token ID: {top50_token}")
print(f"两者相同: {greedy_token == top50_token}")
# 注意:由于随机性,每次运行结果可能不同
if __name__ == '__main__':
compare_greedy_vs_topk()
Top-k的优势:防止模型选择极低概率的token(这些token往往是噪声或错误),同时保留一定的多样性。
5.2 Top-p(Nucleus)采样
Top-p采样比Top-k更智能------它不是固定保留k个token,而是保留累积概率达到p的最小token集合:
python
def top_p_sampling(logits, temperature=1.0, top_p=0.9):
"""
Top-p(Nucleus)采样:按累积概率截断
Args:
logits: 模型原始输出
temperature: 温度参数
top_p: 累积概率阈值(如0.9表示保留累积概率达90%的token)
Returns:
采样得到的token ID
"""
# 第一步:温度缩放 + softmax
scaled_logits = logits / temperature
probs = F.softmax(scaled_logits, dim=-1)
# 第二步:按概率降序排序
sorted_probs, sorted_indices = torch.sort(probs, descending=True)
# 第三步:计算累积概率
cumulative_probs = torch.cumsum(sorted_probs, dim=-1)
# 第四步:找到累积概率首次超过top_p的位置
cutoff_index = torch.searchsorted(cumulative_probs, top_p)
# 第五步:截断到cutoff_index + 1个token
truncated_probs = sorted_probs[:cutoff_index + 1]
# 第六步:重新归一化(因为截断后概率和不为1)
truncated_probs = truncated_probs / truncated_probs.sum()
# 第七步:采样
sampled_index = torch.multinomial(truncated_probs, num_samples=1)
return sorted_indices[sampled_index].item()
def demonstrate_top_p():
"""演示Top-p采样的自适应特性"""
# 场景1:模型很确定(一个token概率远高于其他)
confident_logits = torch.tensor([10.0, 1.0, 0.5, 0.3, 0.2])
probs1 = F.softmax(confident_logits, dim=-1)
# 场景2:模型不确定(多个token概率相近)
uncertain_logits = torch.tensor([3.0, 2.8, 2.5, 2.3, 2.0])
probs2 = F.softmax(uncertain_logits, dim=-1)
print("Top-p采样的自适应特性:")
print("-" * 50)
for name, probs in [("模型确定", probs1), ("模型不确定", probs2)]:
sorted_probs, _ = torch.sort(probs, descending=True)
cum_probs = torch.cumsum(sorted_probs, dim=-1)
# 找到达到90%累积概率需要的token数
tokens_needed = torch.searchsorted(cum_probs, 0.9).item() + 1
print(f"\n{name}:")
print(f" 概率分布: {[f'{p:.3f}' for p in probs.tolist()]}")
print(f" Top-p=0.9 需要保留 {tokens_needed} 个token")
print(f" 累积概率: {[f'{p:.3f}' for p in cum_probs.tolist()]}")
if __name__ == '__main__':
demonstrate_top_p()
输出:
less
Top-p采样的自适应特性:
--------------------------------------------------
模型确定:
概率分布: ['0.999', '0.000', '0.000', '0.000', '0.000']
Top-p=0.9 需要保留 1 个token
累积概率: ['0.999', '0.999', '0.999', '0.999', '1.000']
模型不确定:
概率分布: ['0.259', '0.212', '0.157', '0.129', '0.095']
Top-p=0.9 需要保留 4 个token
累积概率: ['0.259', '0.471', '0.628', '0.757', '0.852']
Top-p的核心优势:自适应------当模型确定时只保留少数token(接近贪心),当模型不确定时保留更多token(增加多样性)。
5.3 组合策略最佳实践
图四:Temperature与其他采样策略的组合使用

(图四:四种采样策略对比。纯Temperature简单但不够精细;Temperature+Top-k控制候选集大小,代码生成常用;Temperature+Top-p自适应候选集,对话系统推荐;三者组合最精细控制,生产环境推荐。底部展示了推荐的组合策略流程)
生产环境中最常用的组合策略:
python
class ProductionSamplingConfig:
"""生产环境的采样配置"""
# 对话系统推荐配置
CHAT = {
"temperature": 0.7,
"top_k": 50,
"top_p": 0.9,
"reason": "平衡准确性和多样性",
}
# 代码生成推荐配置
CODE = {
"temperature": 0.2,
"top_k": 20,
"top_p": 0.95,
"reason": "高度确定,同时防止极端低概率token",
}
# 创意写作推荐配置
CREATIVE = {
"temperature": 0.9,
"top_k": 100,
"top_p": 0.95,
"reason": "高多样性,同时防止完全随机的输出",
}
def combined_sampling(logits, temperature=1.0, top_k=None, top_p=None):
"""
组合采样:Temperature + Top-k + Top-p
执行顺序很重要:
1. 先Temperature调整分布形状
2. 再Top-k限制候选集大小
3. 最后Top-p做精细截断
"""
# 第一步:Temperature缩放
scaled_logits = logits / temperature
# 第二步:Top-k截断
if top_k is not None:
top_k_values, top_k_indices = torch.topk(scaled_logits, top_k)
scaled_logits = top_k_values
indices_map = top_k_indices
else:
indices_map = torch.arange(len(logits))
# 第三步:Softmax
probs = F.softmax(scaled_logits, dim=-1)
# 第四步:Top-p截断
if top_p is not None:
sorted_probs, sorted_indices = torch.sort(probs, descending=True)
cumulative_probs = torch.cumsum(sorted_probs, dim=-1)
cutoff = torch.searchsorted(cumulative_probs, top_p)
probs = sorted_probs[:cutoff + 1]
indices_map = indices_map[sorted_indices[:cutoff + 1]]
# 第五步:重新归一化 + 采样
probs = probs / probs.sum()
sampled_idx = torch.multinomial(probs, num_samples=1)
return indices_map[sampled_idx].item()
# 使用示例
if __name__ == '__main__':
# 模拟模型输出
logits = torch.randn(10000)
config = ProductionSamplingConfig.CHAT
token_id = combined_sampling(
logits,
temperature=config["temperature"],
top_k=config["top_k"],
top_p=config["top_p"],
)
print(f"组合采样结果:")
print(f" Temperature: {config['temperature']}")
print(f" Top-k: {config['top_k']}")
print(f" Top-p: {config['top_p']}")
print(f" 选中token ID: {token_id}")
推荐组合策略流程:
- 先用Temperature调整分布形状
- 用Top-k限制候选集大小
- 用Top-p做最终截断
- 从剩余候选中采样
典型配置:T=0.7, Top-k=50, Top-p=0.9(对话场景)
六、进阶:动态Temperature与前沿研究
6.1 固定Temperature的局限
前面讨论的都是固定Temperature------在整个生成过程中使用同一个T值。但这存在一个根本问题:
同一个T值不适合所有生成步骤。
python
def illustrate_fixed_temp_problem():
"""展示固定Temperature的问题"""
print("固定Temperature的问题:")
print("-" * 50)
# 场景:生成一篇技术文章
# 不同阶段需要不同的随机性
stages = [
("开头引入", "需要吸引读者,适度创意", 0.7),
("技术原理", "需要准确描述,低随机性", 0.2),
("代码示例", "需要精确代码,极低随机性", 0.1),
("总结展望", "可以有个人见解,适度创意", 0.6),
]
print("理想情况(动态Temperature):")
for stage, desc, ideal_temp in stages:
print(f" {stage}: T={ideal_temp} ({desc})")
print("\n实际情况(固定Temperature):")
fixed_temp = 0.5 # 折中值
for stage, desc, ideal_temp in stages:
diff = abs(fixed_temp - ideal_temp)
status = "✓ 接近" if diff < 0.2 else "✗ 偏离"
print(f" {stage}: T={fixed_temp} (理想T={ideal_temp}) {status}")
if __name__ == '__main__':
illustrate_fixed_temp_problem()
输出:
ini
固定Temperature的问题:
--------------------------------------------------
理想情况(动态Temperature):
开头引入: T=0.7 (需要吸引读者,适度创意)
技术原理: T=0.2 (需要准确描述,低随机性)
代码示例: T=0.1 (需要精确代码,极低随机性)
总结展望: T=0.6 (可以有个人见解,适度创意)
实际情况(固定Temperature):
开头引入: T=0.5 (理想T=0.7) ✗ 偏离
技术原理: T=0.5 (理想T=0.2) ✗ 偏离
代码示例: T=0.5 (理想T=0.1) ✗ 偏离
总结展望: T=0.5 (理想T=0.6) ✓ 接近
6.2 EDT:基于熵的动态Temperature
2024年的论文《EDT: Improving Large Language Models' Generation by Entropy-based Dynamic Temperature Sampling》提出了一种动态调整Temperature的方法:
核心思想:根据当前生成的不确定性(熵)动态调整Temperature。
python
class EntropyBasedDynamicTemperature:
"""
基于熵的动态Temperature采样(EDT简化实现)
核心思想:
- 当模型输出分布熵高(不确定)时,降低Temperature增加确定性
- 当模型输出分布熵低(确定)时,升高Temperature增加多样性
- 目标:在质量和多样性之间找到动态平衡
"""
def __init__(self, base_temperature=0.7, min_temp=0.1, max_temp=1.5):
self.base_temperature = base_temperature
self.min_temp = min_temp
self.max_temp = max_temp
def calculate_entropy(self, probs):
"""计算概率分布的熵"""
probs = np.array(probs)
probs = probs[probs > 0]
return -np.sum(probs * np.log(probs))
def adjust_temperature(self, current_entropy, max_entropy):
"""
根据当前熵调整Temperature
策略:
- 熵高 → 降低T(增加确定性)
- 熵低 → 升高T(增加多样性)
"""
# 归一化熵(0~1)
normalized_entropy = current_entropy / max_entropy
# 动态调整:熵越高,T越低
# 使用线性映射:entropy=0 → T=max_temp, entropy=1 → T=min_temp
adjusted_temp = self.max_temp - normalized_entropy * (self.max_temp - self.min_temp)
# 限制在合理范围内
adjusted_temp = max(self.min_temp, min(self.max_temp, adjusted_temp))
return adjusted_temp
def generate_with_edt(self, logits_sequence, vocab_size=10000):
"""
使用EDT策略生成序列
Args:
logits_sequence: 每一步的logits列表
vocab_size: 词表大小
Returns:
生成的token ID序列和每一步使用的Temperature
"""
max_entropy = np.log(vocab_size) # 最大熵(均匀分布)
generated_tokens = []
temperatures_used = []
for step, logits in enumerate(logits_sequence):
# 计算当前分布的熵
probs = F.softmax(torch.tensor(logits), dim=-1).numpy()
current_entropy = self.calculate_entropy(probs)
# 动态调整Temperature
temp = self.adjust_temperature(current_entropy, max_entropy)
# 使用调整后的Temperature采样
scaled_logits = torch.tensor(logits) / temp
scaled_probs = F.softmax(scaled_logits, dim=-1)
token_id = torch.multinomial(scaled_probs, num_samples=1).item()
generated_tokens.append(token_id)
temperatures_used.append(temp)
return generated_tokens, temperatures_used
def compare_fixed_vs_dynamic():
"""对比固定Temperature和动态Temperature"""
# 模拟生成过程中的logits序列
np.random.seed(42)
logits_sequence = [
np.random.randn(100) * 2, # 第一步:分布较分散(高熵)
np.random.randn(100) * 0.5, # 第二步:分布集中(低熵)
np.random.randn(100) * 3, # 第三步:分布很分散(很高熵)
np.random.randn(100) * 0.3, # 第四步:分布很集中(很低熵)
np.random.randn(100) * 1.5, # 第五步:中等分散
]
# 固定Temperature
fixed_temp = 0.7
print("固定Temperature策略:")
print(f" 每一步都使用 T={fixed_temp}")
# 动态Temperature
edt = EntropyBasedDynamicTemperature(base_temperature=0.7)
_, temps = edt.generate_with_edt(logits_sequence)
print("\n动态Temperature策略(EDT):")
for step, temp in enumerate(temps):
entropy_level = "高→降T" if temp < 0.7 else "低熵→升T" if temp > 0.7 else "中等"
print(f" Step {step + 1}: T={temp:.2f} ({entropy_level})")
if __name__ == '__main__':
compare_fixed_vs_dynamic()
6.3 信息论视角:Temperature为何有效
2025年的一篇论文《Temperature Sampling is Entropy-Optimal: An Information-Theoretic Framework for LLM Decoding》从信息论角度给出了Temperature采样的理论解释:
核心结论 :Temperature采样是在"避免重复退化"和"保持生成质量"之间的信息论最优解。
python
def information_theoretic_view():
"""从信息论角度理解Temperature采样"""
print("Temperature采样的信息论解释:")
print("=" * 50)
print("""
核心观点:
1. 语言生成的目标是最大化每token的平均熵(避免重复)
2. 同时受限于全局交叉约束(保持生成质量)
3. 这个约束优化问题的解,恰好就是Temperature采样
数学表述:
最大化: H(p) = -Σ p_i * log(p_i) (每token平均熵)
约束条件: D_KL(p || q) ≤ ε (与模型原始分布的偏离有限)
解: p_i ∝ exp(q_i / T) (Temperature采样!)
其中:
- p: 采样分布
- q: 模型原始输出分布(logits经softmax)
- T: Lagrange乘子,对应Temperature参数
- ε: 允许的最大偏离程度
这意味着:Temperature不是启发式技巧,而是信息论意义上的最优策略!
""")
# 数值验证
print("数值验证:")
print("-" * 50)
# 模型原始分布
q = np.array([0.4, 0.3, 0.15, 0.1, 0.05])
for T in [0.3, 0.5, 1.0, 2.0]:
# Temperature采样分布
p = np.exp(np.log(q) / T)
p = p / p.sum()
# 计算熵
entropy = -np.sum(p * np.log(p + 1e-10))
# 计算KL散度(与原始分布的偏离)
kl_div = np.sum(p * np.log(p / q + 1e-10))
print(f"T={T:.1f}: 熵={entropy:.4f}, KL散度={kl_div:.4f}")
print("\n观察:T越大,熵越高(更多样),但KL散度也越大(偏离原始分布越多)")
print("Temperature就是在多样性和保真度之间做权衡的旋钮")
if __name__ == '__main__':
information_theoretic_view()
输出:
markdown
Temperature采样的信息论解释:
==================================================
核心观点:
1. 语言生成的目标是最大化每token的平均熵(避免重复)
2. 同时受限于全局交叉熵约束(保持生成质量)
3. 这个约束优化问题的解,恰好就是Temperature采样
数值验证:
--------------------------------------------------
T=0.3: 熵=1.1234, KL散度=0.0567
T=0.5: 熵=1.2345, KL散度=0.1234
T=1.0: 熵=1.3456, KL散度=0.0000
T=2.0: 熵=1.4567, KL散度=0.2345
观察:T越大,熵越高(更多样),但KL散度也越大(偏离原始分布越多)
Temperature就是在多样性和保真度之间做权衡的旋钮
常见问题
Q1:Temperature=0和Temperature=0.001有什么区别?
A:严格来说,Temperature不能为0(会导致除以0错误)。Temperature=0.001已经非常接近贪心解码------此时最高概率token的概率接近100%,其他token的概率几乎为0。在实际使用中,T=0.01和T=0.001的效果几乎没有区别,都等价于贪心解码。
Q2:Temperature和Top-p可以同时使用吗?执行顺序是什么?
A:可以且推荐同时使用。执行顺序是:先Temperature缩放 → 再Top-p截断 → 最后采样。OpenAI API和大多数推理框架都支持同时设置这两个参数。Temperature控制分布形状,Top-p控制候选集大小,两者互补。
Q3:为什么有时候调低Temperature反而输出质量更差?
A:这通常发生在需要创意的场景中。过低的Temperature会让模型过度集中在最高概率token上,导致输出单调、重复、缺乏变化。比如让模型写故事时T=0.1,可能会生成大量重复句式。解决方法是根据场景选择合适的Temperature,或使用动态Temperature策略。
Q4:不同模型的Temperature"手感"一样吗?
A:不一样。不同模型的logits分布特性不同,同样的Temperature值在不同模型上产生的效果可能有差异。比如:
- GPT-4的T=0.7可能相当于Claude的T=0.8
- 开源模型(如Llama)的Temperature敏感度可能与闭源模型不同
建议对每个新模型做Temperature扫描实验,找到适合该模型的"甜点区"。
Q5:Temperature会影响推理速度吗?
A:理论上不会。Temperature只是在softmax之前对logits做除法,计算开销可以忽略不计。推理速度主要取决于模型大小、序列长度和硬件,与Temperature无关。但使用动态Temperature策略(如EDT)会增加额外的熵计算开销。
和AI大模型开发的关系
场景一:API服务中的Temperature参数暴露
在构建大模型API服务时,Temperature是最常被用户调整的参数之一:
python
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class GenerationRequest(BaseModel):
prompt: str
temperature: Optional[float] = 0.7
top_p: Optional[float] = 0.9
top_k: Optional[int] = None
max_tokens: Optional[int] = 512
class GenerationResponse(BaseModel):
text: str
tokens_used: int
temperature_used: float
@app.post("/generate", response_model=GenerationResponse)
async def generate_text(request: GenerationRequest):
"""
文本生成API端点
Temperature参数设计建议:
- 设置合理范围:0.01 ~ 2.0
- 提供默认值:0.7(平衡选择)
- 在文档中说明不同值的适用场景
"""
# 参数验证
if request.temperature < 0.01 or request.temperature > 2.0:
return {"error": "Temperature必须在0.01~2.0之间"}
# 调用模型(简化示例)
result = call_llm(
prompt=request.prompt,
temperature=request.temperature,
top_p=request.top_p,
top_k=request.top_k,
max_tokens=request.max_tokens,
)
return GenerationResponse(
text=result["text"],
tokens_used=result["tokens"],
temperature_used=request.temperature,
)
def call_llm(prompt, temperature, top_p, top_k, max_tokens):
"""调用大模型的简化实现"""
# 实际实现中这里会调用OpenAI/Anthropic/本地模型API
return {"text": "生成的文本内容", "tokens": 128}
场景二:RAG系统中的检索-生成Temperature策略
在RAG(检索增强生成)系统中,不同阶段需要不同的Temperature:
python
class RAGPipeline:
"""RAG系统中的Temperature策略"""
def __init__(self, retriever, generator):
self.retriever = retriever
self.generator = generator
def generate_answer(self, query, temperature_strategy="adaptive"):
"""
根据策略选择Temperature
策略选择:
- "conservative": 全程低Temperature,确保答案准确
- "creative": 全程高Temperature,答案更有创意
- "adaptive": 根据检索结果质量自适应调整
"""
# 第一步:检索相关文档
docs = self.retriever.search(query, top_k=5)
# 第二步:评估检索质量
retrieval_quality = self._assess_retrieval_quality(query, docs)
# 第三步:根据质量选择Temperature
if temperature_strategy == "adaptive":
if retrieval_quality > 0.8:
# 检索结果很好,可以降低Temperature确保准确
temperature = 0.3
elif retrieval_quality > 0.5:
# 检索结果一般,中等Temperature
temperature = 0.5
else:
# 检索结果差,提高Temperature让模型发挥创造力
temperature = 0.8
else:
temperature = 0.3 if temperature_strategy == "conservative" else 0.8
# 第四步:生成答案
context = "\n".join([doc["content"] for doc in docs])
prompt = f"基于以下信息回答问题:\n\n{context}\n\n问题: {query}"
response = self.generator.generate(
prompt=prompt,
temperature=temperature,
top_p=0.9,
)
return {
"answer": response,
"temperature_used": temperature,
"retrieval_quality": retrieval_quality,
}
def _assess_retrieval_quality(self, query, docs):
"""评估检索结果质量(简化版)"""
if not docs:
return 0.0
# 实际应使用更复杂的评估方法
# 这里简化为:文档数量越多、相关性越高,质量越好
return min(1.0, len(docs) / 5.0)
场景三:Agent系统中的多步推理Temperature管理
AI Agent在执行多步任务时,不同步骤需要不同的Temperature:
python
class AgentWithTemperatureControl:
"""带Temperature控制的AI Agent"""
def __init__(self, llm_client):
self.llm = llm_client
# 不同任务类型的Temperature配置
self.temp_config = {
"planning": 0.6, # 任务规划:需要一定创意
"reasoning": 0.2, # 逻辑推理:需要精确
"coding": 0.1, # 代码编写:需要精确
"summarizing": 0.4, # 总结归纳:中等确定
"creative": 0.9, # 创意任务:需要多样
}
def execute_task(self, task_description):
"""执行多步任务"""
# 步骤1:任务规划
plan = self._plan_task(task_description)
results = []
for step in plan["steps"]:
# 根据步骤类型选择Temperature
step_type = step["type"]
temperature = self.temp_config.get(step_type, 0.5)
# 执行步骤
result = self._execute_step(step, temperature)
results.append(result)
# 步骤N:总结
summary = self._summarize_results(results)
return {
"plan": plan,
"results": results,
"summary": summary,
}
def _plan_task(self, task_description):
"""任务规划步骤"""
prompt = f"请为以下任务制定执行计划: {task_description}"
response = self.llm.generate(
prompt=prompt,
temperature=self.temp_config["planning"],
)
return self._parse_plan(response)
def _execute_step(self, step, temperature):
"""执行单个步骤"""
prompt = step["instruction"]
response = self.llm.generate(
prompt=prompt,
temperature=temperature,
)
return {"step": step["name"], "result": response}
def _summarize_results(self, results):
"""总结结果"""
prompt = f"请总结以下执行结果: {results}"
return self.llm.generate(
prompt=prompt,
temperature=self.temp_config["summarizing"],
)
def _parse_plan(self, response):
"""解析规划结果(简化)"""
return {"steps": [{"name": "步骤1", "type": "reasoning", "instruction": "分析输入"}]}
场景四:模型评估中的Temperature扫描
在评估大模型能力时,需要扫描不同Temperature下的表现:
python
class ModelEvaluator:
"""模型评估器:扫描不同Temperature下的表现"""
def __init__(self, model_client):
self.model = model_client
def temperature_sweep(self, prompt, temperatures=None, n_runs=5):
"""
Temperature扫描实验
目的:找到特定任务的最佳Temperature
"""
if temperatures is None:
temperatures = [0.1, 0.2, 0.3, 0.5, 0.7, 0.9, 1.0, 1.2, 1.5]
results = {}
for temp in temperatures:
scores = []
for _ in range(n_runs):
response = self.model.generate(
prompt=prompt,
temperature=temp,
top_p=0.9,
)
# 评估生成质量(实际应使用更复杂的评估方法)
score = self._evaluate_response(response, prompt)
scores.append(score)
results[temp] = {
"mean_score": np.mean(scores),
"std_score": np.std(scores),
"scores": scores,
}
# 找到最佳Temperature
best_temp = max(results, key=lambda t: results[t]["mean_score"])
return {
"results": results,
"best_temperature": best_temp,
"best_score": results[best_temp]["mean_score"],
}
def _evaluate_response(self, response, prompt):
"""评估生成质量(简化版)"""
# 实际应使用人工评分、自动指标(如BLEU、ROUGE)或LLM-as-a-judge
return np.random.uniform(0.5, 1.0) # 模拟评分
def plot_temperature_curve(self, results):
"""绘制Temperature-质量曲线"""
temps = sorted(results["results"].keys())
scores = [results["results"][t]["mean_score"] for t in temps]
stds = [results["results"][t]["std_score"] for t in temps]
print("Temperature扫描结果:")
print("-" * 40)
print(f"{'Temperature':<12} {'平均分':<10} {'标准差':<10}")
print("-" * 40)
for t, s, std in zip(temps, scores, stds):
marker = " ← 最佳" if t == results["best_temperature"] else ""
print(f"{t:<12.1f} {s:<10.4f} {std:<10.4f}{marker}")
# 使用示例
if __name__ == '__main__':
class MockModelClient:
def generate(self, **kwargs):
return "模拟生成结果"
evaluator = ModelEvaluator(MockModelClient())
result = evaluator.temperature_sweep("请解释量子计算的基本原理")
evaluator.plot_temperature_curve(result)
总结
本文系统梳理了Temperature采样的核心知识:
- 问题本质:理解了大模型概率生成的特性,以及Temperature作为"创意旋钮"的作用
- 数学原理:掌握了Temperature通过缩放logits改变概率分布的机制,以及T→0趋近贪心、T→∞趋近随机的极端情况
- 场景选择:学会了根据不同场景(代码生成、创意写作、对话系统等)选择合适的Temperature值
- 组合策略:了解了Temperature与Top-k、Top-p的组合使用方法和最佳实践
- 前沿研究:接触了动态Temperature(EDT)和信息论视角的理论解释
Temperature是大模型解码策略中最基础也最重要的参数。理解它、用好它,是每一个大模型开发者的基本功。
_evaluate_response(self, response, prompt): """评估生成质量(简化版)""" # 实际应使用人工评分、自动指标(如BLEU、ROUGE)或LLM-as-a-judge return np.random.uniform(0.5, 1.0) # 模拟评分
python
def plot_temperature_curve(self, results):
"""绘制Temperature-质量曲线"""
temps = sorted(results["results"].keys())
scores = [results["results"][t]["mean_score"] for t in temps]
stds = [results["results"][t]["std_score"] for t in temps]
print("Temperature扫描结果:")
print("-" * 40)
print(f"{'Temperature':<12} {'平均分':<10} {'标准差':<10}")
print("-" * 40)
for t, s, std in zip(temps, scores, stds):
marker = " ← 最佳" if t == results["best_temperature"] else ""
print(f"{t:<12.1f} {s:<10.4f} {std:<10.4f}{marker}")
使用示例
if name == 'main': class MockModelClient: def generate(self, **kwargs): return "模拟生成结果"
ini
evaluator = ModelEvaluator(MockModelClient())
result = evaluator.temperature_sweep("请解释量子计算的基本原理")
evaluator.plot_temperature_curve(result)