← 返回资讯

temperature/top_p/max_tokens 等参数详解

2026-06-24

上周有个做客服机器人的朋友找我吐槽:同一句用户提问,模型有时候回答得规规矩矩,有时候突然开始”发散”,扯到毫不相关的话题上去,客户投诉说机器人在”胡说八道”。我让他把请求体发过来一看,temperature 写的是 1.4——这是别人写教程时随手抄的默认值,他自己压根没改过。这类问题在接入大模型 API 时太常见了:很多人调用接口时只填了 modelmessages,其余参数全部用默认值,出了问题却不知道从何查起

这篇把 temperaturetop_pmax_tokensfrequency_penaltypresence_penaltynseed 这几个真正决定输出质量和账单金额的参数掰开讲清楚:不只是”取值范围是多少”,更重要的是它们在底层到底改变了什么、什么场景下该调哪个、调错了会报什么错、怎么定位。

核心参数一览

参数类型默认值范围作用
temperaturefloat1.00–2控制输出随机性,越低越确定
top_pfloat1.00–1nucleus sampling,限制候选 token 的累积概率
max_tokensint模型上限1–模型最大值限制单次输出 token 数
frequency_penaltyfloat0-2–2惩罚已出现的 token,减少重复
presence_penaltyfloat0-2–2惩罚出现过的话题,鼓励新话题
stopstring/arraynull遇到指定字符串时停止生成
nint11–128同时生成 n 条候选回复
seedintnull固定随机种子,提高可复现性

temperature 详解

temperature 是最常调的参数,控制模型采样时的”温度”:

  • 0:贪心解码,每次取概率最高的 token,输出最确定但可能过于刻板
  • 0.2–0.5:低随机性,适合代码生成、数据提取、格式化输出
  • 0.7–1.0:平衡创意与连贯,适合通用对话、问答
  • 1.2–2.0:高随机性,输出更有创意但可能出现不连贯,适合头脑风暴

为什么调 temperature 会改变输出的”性格”? 模型在预测下一个 token 时,先算出一份候选 token 的原始得分(logits),再用 softmax 把它们转成概率分布。temperature 做的事情,是在过 softmax 之前,把每个 logit 除以这个值:温度越低,除完之后候选之间的分数差被放大,概率分布越”尖”,排第一的 token 越容易被反复选中;温度越高,分数差被压缩,概率分布越”平”,排名靠后的 token 也有机会被抽到。这就是为什么 temperature=0 的输出几乎每次都一样(本质上退化成贪心解码,只挑概率最高的那个),而 temperature 冲到 1.6 以上时,模型偶尔会选中一个概率很低、跟上下文不太搭的词,一步错步步错,句子就开始”飘”了——上面那个客服机器人的案例,本质就是这个道理。

我见过另一种更隐蔽的坑:多轮对话里前几轮用低 temperature 测试没问题,上线后偶发地”答非所问”,一查是有人为了让机器人”显得更有人情味”,单独给某一类问题的 temperature 调到了 0.9,结果那条分支的输出稳定性直线下降。经验是:客服、工单分类、信息抽取这类”一句话答错就是事故”的场景,temperature 尽量锁在 0.3 以内,别为了一点”人情味”去冒风险,语气可以靠 system prompt 里写措辞规范来解决,不用靠调高随机性。

# 代码生成:低 temperature,输出更可预测
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "写一个冒泡排序函数"}],
    temperature=0.2,
    max_tokens=512,
)

# 创意写作:高 temperature
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "给我一个独特的产品名称创意"}],
    temperature=1.2,
    max_tokens=128,
)

top_p vs temperature:不要同时调

top_p 是另一种控制随机性的方式(nucleus sampling):只从累积概率达到 top_p 的 token 集合中采样。

重要原则:temperaturetop_p 不建议同时调整,两者叠加会使行为难以预测。通常保持一个为默认值:

目标推荐做法
调输出确定性temperaturetop_p 保持 1.0
需要 nucleus samplingtop_p(如 0.9),temperature 保持 1.0

top_ptemperature 的作用机制不一样:temperature 是重新分配整个候选集合的概率,top_p 是先按概率从高到低排序,累加到达到设定阈值就截断,只在这个截断后的小集合里采样。举个例子:如果 top_p=0.1,模型可能只在两三个最可能的 token 里选,输出会非常保守;如果同时又把 temperature 调到 1.5,两个参数互相打架——一个说”只准在小圈子里选”,一个说”圈子里也要选得更随机”,实际效果很难预测,我自己测过同样的 prompt 跑十次,输出的方差比只调单一参数时明显更大。真出问题排查起来也麻烦,因为你分不清是哪个参数导致的异常,所以还是那句话:两个只调一个,另一个锁 1.0,调试成本会低很多。

max_tokens 设置建议

max_tokens 控制本次输出的最大 token 数,不包含输入:

场景推荐值
简短问答 / 分类64–256
通用对话512–1024
文章生成 / 代码2048–4096
长文档处理8192+

不设 max_tokens 会让模型尽可能生成到上下文窗口上限,既浪费费用又增加延迟。

max_tokens 和上下文窗口是两回事,很多人搞混。 上下文窗口是”输入 + 输出”加起来的总容量上限(比如某模型是 128K token),max_tokens 只限制”本次输出”这一部分。如果你的输入已经占了 127K token,又把 max_tokens 设成 4096,请求会直接报错,常见的报错文案类似 This model's maximum context length is 128000 tokens. However, your messages resulted in 127500 tokens and max_tokens is 4096, which together exceed the limit.——根因很直接:输入 + 你要的输出 > 窗口总量。修法有两个方向:一是把 max_tokens 调小(比如降到 500),先保证请求能跑通;二是从输入端下手,裁剪历史对话轮次或用摘要压缩长上下文,这个我在讲多轮对话构造的那篇里有具体展开,这里不重复。

另一个容易被忽略的点是输出被截断。如果返回结果里 finish_reason"length" 而不是 "stop",说明模型话还没说完就被 max_tokens 硬切断了——常见症状是 JSON 输出到一半缺了右括号,或者长文写到一半戛然而止。排查思路很简单:先看 finish_reason,如果是 length,直接把 max_tokens 调大,而不是去怀疑 prompt 写错了。

成本估算也建立在 max_tokens 上。 多数供应商按输入、输出 token 分别计价,输出单价通常比输入贵(不同模型倍率不同,具体以官方计价页为准)。如果你的产品是”生成 2000 字营销文案”这种确定性需求,与其让模型自由发挥然后被账单吓一跳,不如提前用分词器粗算一下大致会产出多少 token,把 max_tokens 卡在略高于预期值的位置——既能防止意外超长导致的费用暴涨,也能在模型”话痨”的时候及时截断。

frequency_penalty 与 presence_penalty

# 减少长文中词汇重复
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "写一段关于 AI 的 500 字介绍"}],
    frequency_penalty=0.5,   # 已出现越多次,该 token 被惩罚越重
    presence_penalty=0.3,    # 只要出现过,就给一定惩罚
    max_tokens=800,
)

两者均在 -2 到 2 之间:正值降低重复,负值允许模型反复使用同一词汇。

两个参数的算法差别在于惩罚力度是否跟出现次数挂钩frequency_penalty 是按 token 已出现的次数线性累加惩罚,出现得越多,下次被选中的概率压得越低;presence_penalty 只要 token 出现过一次,不管出现几次,惩罚力度都一样,它管的是”要不要聊点新话题”,而不是”这个词说太多次了”。所以如果你的场景是”长文里同一个词反复出现显得啰嗦”(比如写产品介绍老是”AI赋能""智能化”来回用),该调的是 frequency_penalty;如果是”模型讨论完一个点就死磕不放,聊不到新角度”,该调的是 presence_penalty

什么时候不该用这两个参数?做结构化数据提取或代码生成时尽量别碰,因为惩罚机制对必须重复出现的关键词(比如 JSON 里反复出现的字段名、代码里反复出现的变量名)也会生效,硬把这些词的概率压低,容易导致输出格式跑偏,我遇到过 frequency_penalty=0.8 时模型抽取字段名时突然写错字段名的情况,本质就是常用字段名被惩罚到不想再重复用了。这两个参数更适合”自由行文”类场景,结构化任务交给 temperature=0 加清晰的 prompt 就够了。

场景调参速查

场景temperaturetop_pmax_tokens备注
代码生成0.21.02048
数据提取 / 分类01.0256确定性最高
通用问答0.71.01024
创意写作1.11.02048
头脑风暴(多候选)1.21.0512配合 n=3
摘要生成0.51.0512

n 参数:一次请求生成多条候选

n 让你一次请求拿到多条独立生成的候选回复,常用在”选优”场景:比如让模型给三个不同的文案方向,或者给多个候选答案再由你自己(或另一个模型)打分挑最好的一条。用的时候要注意两个坑:

  1. 计费是按实际生成的总 token 算的n=3 意味着你要为 3 条输出各自的 token 数付费,不是”一份钱出三份货”,账单会直接翻倍甚至更多,做预算的时候一定要把 n 乘进去。
  2. n 和高 temperature 搭配才有意义。如果 temperature=0,三条候选大概率长得差不多(贪心解码本身随机性就低),花三倍钱换不来三种风格,等于白花钱。所以想用 n 做多样化候选,temperature 至少要给到 0.8 以上,让每条候选之间真的有差异。

seed:可复现性的边界在哪

seed 用来固定采样时的随机数种子,配合相同的 modelmessagestemperature 等参数,理论上能让多次调用返回一致(或非常接近一致)的结果。但这里有个常被忽视的边界:“确定性”不是绝对的。即便传了同样的 seed,模型底层的推理引擎在做批处理(把多个请求的计算打包到一起跑)时,浮点运算的执行顺序可能因为服务器当下的负载、批次拼接方式不同而产生细微差异,这些差异有时会在生成的后半段被放大成肉眼可见的文字不同。多数供应商的响应里会带一个 system_fingerprint 字段,标识当前后端配置的版本——如果两次调用返回的 system_fingerprint 不一样,那即便 seed 相同,输出也大概率会不同,这通常意味着服务端做了模型或推理引擎的更新,不是你代码写错了。

需要严格可复现性的场景(比如自动化测试、A/B 对比实验),建议做法是:固定 seed 的同时,把 system_fingerprint 也记录进日志,两次结果不一致时先去比对这个字段再排查自己的代码逻辑,能少走很多弯路。

常见问题

temperature=0 能保证完全可复现吗? 不能完全保证,模型权重、批处理策略等因素仍可能引入微小差异。若需高可复现性,同时设置 seed 参数。

为什么调高 temperature 之后输出变成乱码或无关内容? temperature > 1.5 对部分模型会导致采样失控。建议先从 0.7 起步,每次调整 0.1-0.2,观察输出质量再继续调整。

stop 参数怎么用? 传入字符串或数组,模型遇到后立即停止生成(不包含该字符串本身)。常用于让模型只输出到某个标记为止,如 "stop": ["\n\n", "---"]

开了 stream=True 之后,这些参数还生效吗? 生效,流式只是把同一次生成过程拆成一个个 token 分片推给你,temperaturetop_pmax_tokens 这些控制的是”怎么采样、采多少”,跟是否流式无关。但流式场景下有个实操细节要注意:max_tokens 截断时,你在客户端拿到的是一段不完整的分片流,finish_reason 只会出现在最后一个 data 块里,如果你的解析逻辑只处理了 content 字段、没检查最后一块的 finish_reason,就会误以为是网络中断导致的截断,排查方向就跑偏了——记得把 finish_reason 的判断也接进流式解析逻辑里。

请求报 Invalid value for 'temperature': must be between 0 and 2 怎么办? 这是参数越界,多半是代码里写了固定值又叠加了随机扰动(比如想让每次请求 temperature 有点随机浮动,写了 temperature + random.uniform(-0.2, 0.5),结果算出来超过了 2)。修法是加一层夹紧(clamp)逻辑,把最终值限制在 0–2 之间再发请求,而不是发出去让服务端拒绝了才回头查。


更多接入方案见大模型 API 接入完全指南接入教程专题。了解 messages 结构见messages 角色与多轮对话构造;system 提示词写法见system 提示词怎么设。需要统一多模型入口?申请力达云聚合 API 内测