为什么同一个问题 AI 每次回答不一样

很多人第一次调用 LLM API 时,会遇到一个现象:同一个问题,模型每次回答不完全一样。

这和传统前端调用接口的直觉很不同。普通接口通常像这样:

GET /api/user/123

只要数据库没变、代码没变,返回结果就应该一样。

但 LLM 不是普通查询接口。它是在给定上下文后,按概率生成下一个 token。回答的不稳定性不是偶然 bug,而是生成式模型的基本特征之一。

LLM 不是在查固定答案

当你问:

什么是 React 的 useEffect?

模型不是去某个标准答案库里查出唯一文本。它会根据输入上下文,预测接下来更可能出现哪些 token,然后一步步生成回答。

可以粗略理解为:

  1. 读取 prompt 和历史消息。
  2. 计算下一个 token 的概率分布。
  3. 按某种采样策略选出一个 token。
  4. 把这个 token 加入上下文。
  5. 重复以上过程,直到生成完成。

每一步都有多个可能选择。早期一个小差异,后面就可能扩展成不同措辞、不同例子、不同结构。

这就是为什么 LLM 输出通常不是确定性函数。

什么是 token 概率

模型生成文本时,不是一次生成整段文章,而是一个 token 一个 token 地生成。

假设上下文是:

React 是一个用于构建

下一个 token 可能有很多候选:

候选粗略可能性
用户
界面
UI
组件
数据库

真实模型的候选远比这个复杂,但直觉类似:模型会给不同 token 分配不同概率。

采样策略决定了模型是总选最可能的那个,还是允许从多个合理候选中选择。

Temperature 是什么

Temperature 是影响采样随机性的常见参数。

可以把它理解为“让模型在候选 token 之间选择时有多开放”。

较低的 temperature 会让模型更偏向高概率候选,输出更稳定、更保守。较高的 temperature 会让模型更愿意选择次高概率候选,输出更多样、更有创意,但也更容易跑偏。

常见经验是:

场景temperature 倾向
事实问答较低
代码生成较低到中等
JSON 抽取很低
文案改写中等
创意命名中等到较高
头脑风暴较高

这不是绝对规则。不同模型、不同任务、不同上下文都会影响结果。

低 temperature 不等于绝对确定

很多人以为把 temperature 设为 0,就一定每次输出完全一样。

现实里不一定。

原因可能包括:

  • 服务端实现仍可能存在非完全确定行为。
  • 模型版本可能更新。
  • 请求上下文里包含时间、检索结果或动态数据。
  • 并发和底层推理优化可能带来微小差异。
  • prompt 本身有歧义,允许多种合理答案。

所以低 temperature 的意义是降低随机性,而不是把 LLM 变成普通纯函数。

如果业务强依赖稳定输出,你还需要结合格式约束、校验、缓存、测试和后处理。

Sampling 是什么

Sampling 指的是从候选 token 概率分布里选择输出的过程。

Temperature 是 sampling 的一个控制参数。除了 temperature,很多模型接口还会提供类似 top_p 的参数。

top_p 可以粗略理解为:只从累计概率达到某个阈值的候选集合里采样。

例如 top_p 较低时,模型只在最可能的一小批 token 里选择;top_p 较高时,可选范围更大。

学习早期不需要同时调很多参数。对大多数前端工程实践来说,先理解 temperature 就够了:

  • 想要稳定,降低 temperature。
  • 想要多样,提高 temperature。
  • 想要可靠结构,不只调参数,还要做约束和校验。

为什么措辞会变,意思却差不多

同一个问题可能有很多正确表达。

例如用户问:

用一句话解释 debounce。

模型可能回答:

Debounce 是在事件停止触发一段时间后再执行回调。

也可能回答:

Debounce 用来把连续触发的事件合并成最后一次执行。

这两句都合理。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 输出的边界、容错和验证链路。