生成参数控制
🎯 学习目标
- 理解 Temperature、Top P、Max Tokens、Stop、Seed 的作用机制
- 能为问答、抽取、创意、代码等场景选择合适的参数组合
- 通过代码实验观察参数变化对输出的影响
- 理解参数与延迟、成本、解析失败率的关系
引言
同样一句「介绍 Redis」,Temperature=0 可能每次输出几乎相同;Temperature=1.2 则措辞发散、例子随机。生成类 API 不只传 messages——采样参数决定模型从概率分布中如何「选词」。调参是 cheap 且高杠杆的技能:错误的 temperature 会导致 JSON 解析失败、幻觉增多或创意不足;合理的 max_tokens 则直接决定账单上限与截断风险。
本节先讲清 Temperature 与 Top P(nucleus sampling) 的直觉与区别,再覆盖 max_tokens、stop、seed、stream 等工程常参,最后用可运行脚本做 A/B 对比实验。记住:没有 universal 最优值,只有与任务、Eval 数据集匹配的配置。
章节正文
第 1 步:Temperature:控制随机性
模型对下一个 Token 输出 logits,经 softmax 得概率分布。Temperature(T) 在采样前缩放 logits:T 越低分布越「尖」,高概率 Token 几乎总是被选中;T 越高分布越平,低概率词也有机会出现。
典型区间:
| 场景 | Temperature | 原因 |
|---|---|---|
| 事实问答、分类、JSON 抽取 | 0 – 0.3 | 要稳定、可复现 |
| 通用对话 | 0.5 – 0.7 | 平衡自然与一致 |
| 头脑风暴、营销文案 | 0.8 – 1.0 | 需要多样性 |
| 强烈创意(慎用) | > 1.0 | 易离题、语法漂移 |
实验脚本(固定 prompt,改 T):
for (const temp of [0, 0.7, 1.2]) {
const res = await client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: '给一个学习 LLM 的比喻' }],
temperature: temp,
max_tokens: 80,
})
console.log(`T=${temp}:`, res.choices[0].message.content.trim())
}跑三次 T=0,输出应高度相似;T=1.2 则差异明显。
第 2 步:Top P 与 Temperature 如何配合
Top P(nucleus sampling) 只从累积概率达到 P 的最小 Token 集合中采样。例如 P=0.9 可能只剩几十个候选词,砍掉长尾低概率「胡言乱语」。
- Temperature 改变整体分布形状
- Top P 直接裁剪候选集
常见做法:固定其一,调另一个。OpenAI 文档建议不要同时大幅改动两者。抽取/Agent 场景常用 temperature: 0 或很低,top_p: 1 默认即可;创意写作用 temperature: 0.8, top_p: 0.95。
await client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'user',
content: '从下面句子提取城市,只输出 JSON:{"city":""}。我昨天去了上海。',
},
],
temperature: 0,
top_p: 1,
max_tokens: 50,
})低 T 提高 JSON 可解析率;若仍偶发多余解释文字,配合 2.6 节 JSON Schema 模式 更稳。
第 3 步:Max Tokens、Stop 与 Seed
max_tokens:限制 输出 Token 上限(不含输入)。设太小会 mid-sentence 截断;设太大浪费预算且模型可能啰嗦。
经验:先估输出长度。三条 bullet 摘要 ≈ 150–300 tokens;短 JSON ≈ 50–150。生产可对每类 intent 配置不同上限。
stop:字符串数组,模型生成到其中任一序列即停止(不含 stop 本身写入输出)。用于:
- 防止模型继续编造下一轮「User:」
- 代码补全停在
\n\n
await client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: '写一首四句绝句,不要解释' }],
max_tokens: 100,
stop: ['\n\n', '注释:'],
})seed(部分模型支持):固定随机源,相同请求更可能得相同输出,仍非 100% 保证。用于调试与回归测试;Eval 时配合 temperature=0。
stream(2.4 节详述):stream: true 不改变采样逻辑,只改变交付方式。
第 4 步:场景配方与反模式
推荐配方(起点,非教条):
export const presets = {
extract: { temperature: 0, max_tokens: 512, top_p: 1 },
qa: { temperature: 0.2, max_tokens: 1024, top_p: 1 },
chat: { temperature: 0.7, max_tokens: 2048, top_p: 0.95 },
creative: { temperature: 0.9, max_tokens: 4096, top_p: 0.95 },
code: { temperature: 0.2, max_tokens: 2048, top_p: 0.95 },
}反模式:
- 抽取任务 T=1.0 → JSON 失败率飙升
- max_tokens=8192 做「是/否」分类 → 成本浪费
- 每请求改随机 T → Eval 无法对比版本
- 忽视
finish_reason:length表示被 max_tokens 截断,应提示用户或续写
检查响应:
const choice = response.choices[0]
console.log(choice.finish_reason) // stop | length | content_filter ...length 时应缩短输入、增大 max_tokens 或让模型分步输出。
第 5 步:参数与成本、延迟的联动
成本 ≈ 输入 Token × 输入单价 + 输出 Token × 输出单价。降低 max_tokens 直接封顶输出 spend;降低 temperature 不 linear 降 Token,但减少胡写与 retry。
延迟:首 Token 时间(TTFT)主要受 输入长度 影响;总时间受 输出 Token 数 影响。低 T 有时略快(早停于高置信 end),但差异小于「少生成 500 tokens」带来的收益。
日志建议:每条记录 { temperature, top_p, max_tokens, usage, finish_reason },与 prompt_version 关联,便于事后分析「为何这次 JSON 坏了」。
综合实验:对同一 RAG 问答,用 extract vs chat preset 各跑 20 次,统计平均 completion_tokens 与人工评分——你会看到参数是 质量-成本曲线 上的旋钮,而非装饰字段。
动手练习
- 写脚本对同一 prompt 遍历 temperature ∈ {0, 0.5, 1.0},保存三次输出并注释差异。
- 实现 extract preset 提取「姓名+邮箱」,故意设 max_tokens=10 观察 finish_reason=length,再调到合理值。
- 为 presets 对象补充
reasoning配置(低 T、更大 max_tokens),说明与 chat preset 区别。 - 在日志中间接记录每次调用的 completion_tokens,估算 creative vs extract 成本差 10 倍请求。
常见问题
Q:temperature=0 是否完全 deterministic?
不一定。GPU 并行、批处理、厂商更新仍可能导致微小差异。要更高复现性用 seed(若支持)+ 固定 model 版本。
Q:Top P 和 Top K 选哪个?
OpenAI 兼容 API 常见 Top P;部分开源栈暴露 top_k。一般只调一个采样参数,避免过度约束。
Q:推理模型 R1 还要调 temperature 吗?
厂商文档常建议特定默认值;思考链很长时 max_tokens 要包含 reasoning tokens。查阅该模型专用说明。
本节小结
Temperature 与 Top P 控制采样随机性;max_tokens、stop、seed 约束输出形态与长度。问答与结构化抽取宜低温低 max_tokens;创意场景可提高 temperature。始终查看 finish_reason 与 usage,把参数纳入日志与 Eval,才能系统优化质量与成本。