为什么同一个问题 AI 每次回答不一样
很多人第一次调用 LLM API 时,会遇到一个现象:同一个问题,模型每次回答不完全一样。
这和传统前端调用接口的直觉很不同。普通接口通常像这样:
只要数据库没变、代码没变,返回结果就应该一样。
但 LLM 不是普通查询接口。它是在给定上下文后,按概率生成下一个 token。回答的不稳定性不是偶然 bug,而是生成式模型的基本特征之一。
LLM 不是在查固定答案
当你问:
模型不是去某个标准答案库里查出唯一文本。它会根据输入上下文,预测接下来更可能出现哪些 token,然后一步步生成回答。
可以粗略理解为:
- 读取 prompt 和历史消息。
- 计算下一个 token 的概率分布。
- 按某种采样策略选出一个 token。
- 把这个 token 加入上下文。
- 重复以上过程,直到生成完成。
每一步都有多个可能选择。早期一个小差异,后面就可能扩展成不同措辞、不同例子、不同结构。
这就是为什么 LLM 输出通常不是确定性函数。
什么是 token 概率
模型生成文本时,不是一次生成整段文章,而是一个 token 一个 token 地生成。
假设上下文是:
下一个 token 可能有很多候选:
真实模型的候选远比这个复杂,但直觉类似:模型会给不同 token 分配不同概率。
采样策略决定了模型是总选最可能的那个,还是允许从多个合理候选中选择。
Temperature 是什么
Temperature 是影响采样随机性的常见参数。
可以把它理解为“让模型在候选 token 之间选择时有多开放”。
较低的 temperature 会让模型更偏向高概率候选,输出更稳定、更保守。较高的 temperature 会让模型更愿意选择次高概率候选,输出更多样、更有创意,但也更容易跑偏。
常见经验是:
这不是绝对规则。不同模型、不同任务、不同上下文都会影响结果。
低 temperature 不等于绝对确定
很多人以为把 temperature 设为 0,就一定每次输出完全一样。
现实里不一定。
原因可能包括:
- 服务端实现仍可能存在非完全确定行为。
- 模型版本可能更新。
- 请求上下文里包含时间、检索结果或动态数据。
- 并发和底层推理优化可能带来微小差异。
- prompt 本身有歧义,允许多种合理答案。
所以低 temperature 的意义是降低随机性,而不是把 LLM 变成普通纯函数。
如果业务强依赖稳定输出,你还需要结合格式约束、校验、缓存、测试和后处理。
Sampling 是什么
Sampling 指的是从候选 token 概率分布里选择输出的过程。
Temperature 是 sampling 的一个控制参数。除了 temperature,很多模型接口还会提供类似 top_p 的参数。
top_p 可以粗略理解为:只从累计概率达到某个阈值的候选集合里采样。
例如 top_p 较低时,模型只在最可能的一小批 token 里选择;top_p 较高时,可选范围更大。
学习早期不需要同时调很多参数。对大多数前端工程实践来说,先理解 temperature 就够了:
- 想要稳定,降低 temperature。
- 想要多样,提高 temperature。
- 想要可靠结构,不只调参数,还要做约束和校验。
为什么措辞会变,意思却差不多
同一个问题可能有很多正确表达。
例如用户问:
模型可能回答:
也可能回答:
这两句都合理。LLM 的输出空间里有很多“差不多正确”的路径。只要采样时选了不同 token,最终表达就会不同。
这对用户体验未必是坏事。聊天、写作、总结、解释类产品通常可以接受一定变化。真正要警惕的是:变化是否影响事实、格式、权限、金额、代码行为或业务决策。
工程上如何控制不确定性
前端接入 LLM 时,不要只问“怎样让它每次一样”。更好的问题是:哪些地方允许变化,哪些地方必须稳定?
对于允许变化的场景,可以保留模型自由度:
- 学习解释。
- 文案润色。
- 创意标题。
- 客服话术草稿。
- 需求讨论。
对于必须稳定的场景,要加入工程约束:
- 使用低 temperature。
- 明确输出格式。
- 使用 JSON Schema 或类型校验。
- 对关键字段做程序化验证。
- 把事实来源限制在数据库或检索结果里。
- 对相同输入做缓存。
- 记录 prompt、参数和模型版本。
- 为核心场景建立测试用例。
LLM 的不确定性不能只靠一句 prompt 解决。它需要产品设计和工程系统一起管理。
前端状态也会制造“不一样”
有时用户以为是模型不稳定,其实是应用传给模型的上下文不一样。
常见原因包括:
- 每次请求带入的历史消息不同。
- 前端重复发送了用户消息。
- 流式输出中断后又重试,历史里多了一段半截回答。
- 检索接口返回了不同文档。
- 系统 prompt 在不同页面或不同用户组里不一致。
- 用户输入里包含当前时间、页面状态或随机内容。
调试 LLM 应用时,必须记录最终发给模型的请求,而不是只看输入框里的文本。
对于前端工程师来说,一个实用习惯是:在开发环境里提供“查看本次 messages”的调试面板。这样你能确认模型到底看到了什么。
什么时候应该追求稳定
不是所有 AI 功能都需要输出完全一致。
如果你在做学习助手,回答略有不同可能更自然。如果你在做营销文案生成,多样性甚至是价值。如果你在做代码解释,轻微措辞差异通常可以接受。
但下面这些场景要更谨慎:
- 生成可执行代码。
- 生成数据库查询。
- 生成订单金额或折扣规则。
- 输出权限判断。
- 抽取合同字段。
- 生成要进入生产流程的 JSON。
- 医疗、法律、金融等高风险建议。
这些场景里,模型应该更多承担“候选生成”或“语言理解”角色,最终执行要由确定性代码、人工确认或可信工具完成。
常见误区
第一个误区:认为回答不一样就是模型坏了。
生成式模型天然会产生多种合理表达。关键是判断变化是否影响任务目标。
第二个误区:把 temperature 当作质量按钮。
Temperature 控制随机性,不直接等于聪明程度。高 temperature 不代表更强,低 temperature 也不代表一定更正确。
第三个误区:以为 temperature 设为 0 就万事大吉。
低随机性不能替代清晰 prompt、稳定上下文、输出校验和业务规则。
第四个误区:在同一个任务里同时乱调多个采样参数。
如果 temperature、top_p、惩罚项等参数一起变化,很难判断到底是什么影响了结果。早期应该一次只改一个变量。
第五个误区:忽略请求上下文差异。
同一个输入框文本,不代表同一个模型请求。messages、system prompt、历史、检索结果、模型版本和工具结果都可能不同。
小结
AI 对同一个问题每次回答不一样,是因为 LLM 按概率逐 token 生成文本,而不是从固定答案表里查结果。
Temperature 和 sampling 会影响这种不确定性。低 temperature 更稳定,高 temperature 更多样,但参数只能调节倾向,不能替代工程约束。
前端工程师真正要做的是区分场景:哪里可以允许自然变化,哪里必须通过低随机性、格式约束、校验、缓存、日志和人工确认来保证可靠。
理解这一点之后,你就不会把 LLM 当成普通接口,也不会被它的“不稳定”吓住。你会开始像设计任何复杂交互系统一样,设计 AI 输出的边界、容错和验证链路。