惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
小众软件
小众软件
量子位
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园_首页
V
Visual Studio Blog
Last Week in AI
Last Week in AI
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
博客园 - 【当耐特】
MyScale Blog
MyScale Blog
月光博客
月光博客

钟意博客

国家统计局数据查询 MCP 照见·硅·肆 涌现之前 照见·硅·叁 换行重启 照见·硅·贰 钢筋水泥 照见·硅·壹 你好世界 照见·硅·零 序言 科艺知识库 ARM64 胶东半岛观察 海光 K100 DCU VLLM 推理环境构建 博客多平台负载均衡方案 浅谈RAG Web技术构建桌面应用方案 Spring WebSocket 错误 SpringBoot WebSocket 代理模式、客户端模式 Spring AOP 调用自身失效 window 端口占用但是查不到 Coze同插件不同工具之间代码复用 Pachelbel's Greatest Hit: The Ultimate Canon - 纪念帕海贝尔:终极卡农 圣诞快乐,劳伦斯先生 Merry Christmas Mr. Lawrence
大语言模型的不确定性
钟意 · 2026-02-07 · via 钟意博客

temperature=0、seed=0 也不等于完全确定, 工程实践的过程中总会有取舍, 请允许理想与现实的偏差.

大佬的镇楼图

导读

温度=0 + 种子固定,最多是“更接近 deterministic”,而不是“数学意义的 deterministic”。介不就是光速与绝对零度嘛。

在真实工程环境下,即使做到:

  • temperature = 0
  • 随机种子(seed)固定为 0
  • 模型权重不变
  • 输入 Prompt 字节级一致

LLM 输出依然无法保证严格的确定性。 原因来自多个层级:采样配置陷阱、浮点数值误差、Batch 动态调度、MoE 路由竞争以及底层算子差异。
工程实践中,更现实的目标不是追求数学意义上的“位级完全一致(Bit-wise Deterministic)”,而是通过参数控制、架构设计与缓存机制,把模型行为收敛在业务可接受的稳定性范围内。

理想化推理链路:
固定权重 + 固定输入 + Greedy 解码(每步选 argmax) + 完全确定的数值计算 ⇒ 输出必然完全一致。

  • temperature (温度):
    • 越高 → 分布越“平”,强随机采样;
    • 越低 → 分布越“尖”,趋向于 Greedy;
    • 理论上 temperature=0 对应“总是选最大值(Argmax)”,但工程上常被框架处理为“极小噪声采样”或依赖特定的实现逻辑。
  • seed (随机种子):
    • 仅控制“伪随机数生成器(RNG)”的初始化序列;
    • 只对依赖随机采样的步骤生效;
    • 对并行计算中的归约顺序(浮点误差)、Batch 调度策略等物理层面的随机性完全无效。

下文将按照 “排查优先级” 对这些干扰因素进行分层解析,并给出相应的规避策略。

推理过程与参数参与情况

工程中概率排行

请求配置层

我不是像 AI 一样让你检查 temperature=0 , 是要理解配置层不只是请求参数, 这是高频误区:

  • 仍然在用采样:top_p < 1top_k > 1,只是温度降到 0;
  • 请求 n > 1,服务端对多条采样结果再做内部选择;
  • 模型供应商 对 temperature=0 做了特殊处理或者忽略0,比如强制改成一个很小但非 0 的温度;
  • 部分供应商接口文档应该写的是 “mostly deterministic” 或 “best effort reproducibility”,并未承诺严格一致。

这些都意味着你以为关掉了随机性,实际上还在采样,而且 seed 只保证“这条采样序列可复现”,并不保证不采样。工程上遇到的多数“T=0 还在变”的案例,根因都在这一层。

参数建议
1
2
3
4
5
6
7
8
9
10
11
{
"model": "xxx",
"temperature": 0.0, // 或一个非常小的值,例如 0.1
"top_p": 1.0, // 不再做 nucleus 截断
"n": 1, // 不要生成多候选再让服务端挑
"seed": 42, // 固定为某个整数,在同一测试中保持不变
"presence_penalty": 0.0, // 禁用额外的随机去重行为
"frequency_penalty": 0.0,
"max_tokens": 256, // 评估/回归测试时也建议固定
"stop": null // 如无特殊需要,不要动态变化
}

请求调度层

Batch 批次请求打包产生差异

在云端 API 上,请求通常如下情况:

  • 被和其他用户的请求一起打包进不同大小的 batch;
  • 由底层推理引擎根据 batch 维度选择不同的并行 kernel 或归约策略。

这会导致:

  • 并行计算的归约顺序不确定导致浮点加法结果差异(不满足结合律)=> (a+b)+c!=a+(b+c)
  • attention / matmul / RMSNorm 的归约路径不同;
  • logits 在 1e-6 量级上产生差异;
  • 若两个 token 概率本来就非常接近,argmax 可能翻转,后续生成路径完全分叉。

《Non-Determinism of “Deterministic” LLM Settings》在理论“应当确定”的配置下反复测试,发现输出字符串的一致率明显小于100%,下游任务准确率在不同 run 间可以差十几个百分点。

对云 API 来说,这是最常见且几乎不可控的非确定性来源。用户也不可能决定好每个批次元素的归约顺序.

模型算子层

浮点并行本身就是非确定性的

即便你在本地单机推理,只要使用 GPU / 并行 kernel,也会碰到:

  • 并行归约(atomicAdd 等)导致累加顺序未定义;
  • cudnn/cublas/自定义 kernel 采用了不同实现路径;
  • 多线程抢占导致不同 run 间执行顺序略有差异。

数值差异微小,但 softmax + argmax 会放大这些差异;自回归生成会进一步放大第一步 argmax 的差异。

PyTorch 论坛中多次讨论:即使 model.eval(),也需要额外开启 deterministic 模式,
否则多次 inference 仍然无法 bit-wise 一致。

批次与浮点计算可以合在一起看,下图是一个简单的归因链路示意:

浮点非结合性效应

模型解码层

不同框架/服务对于 “temperature=0” 的实现并不统一:

  • 有的分支直接走 greedy,不采样;
  • 有的把 0 改成一个很小的正数,仍然进行采样;
  • 有的在低温下仍然允许 nucleus / top-k 筛选后采样。

再叠加 tie-breaking 策略:

  • 概率相等或近似相等时,是按 token id 排序选第一个
  • 还是仍然用 RNG 做一次随机决策

这些实现级细节,很容易在“理论上相同配置”的两次调用之间,积累成肉眼可见的输出差异。

实际代码里,几个主流高 star 项目对 temperature=0 的处理就已经完全不一样:Transformers 直接视为非法值, vLLM 把它解释成“强制 greedy 并重写 top_p/top_k”, llama.cpp 则在不同版本中先后把非正温度当作 greedy 的捷径、后来又要求配合 top‑k 才能得到真正的 greedy 行为。
这本身就说明:“temperature=0”的语义强依赖具体框架实现,目前并没有统一标准。

模型架构层

对采用 Mixture-of-Experts(MoE)的模型:

  • 每个 token 会先经过 gating 网络决定路由到哪些专家子网络;
  • 为了负载均衡,路由逻辑中可能包含截断、近似甚至随机裁剪;
  • 当不同 batch 下竞争同一专家时,调度顺序变化会改变路由结果。

链路复现性

模型/系统版本漂移, 部署的集群非一致, 请求的链路不一定落到系统、驱动、算子全一致的软硬件上。

在云端服务里,以下情况都很常见:

  • 模型权重热更新、系统 prompt 调整;
  • 不同 region / 集群挂载了略有差异的模型快照;
  • 路由策略在多个版本间做灰度。

同一个 model name 在不同时刻/不同 region 调用,底层实际上可能已经不是同一个模型实例。
这更常见于“隔一段时间”再次调用发现结果不同,而非“连续两次立刻不同”。

输入一致性

常见人祸因素:

  • prompt 拼装引入 time、userid、skill 等隐变量;
  • system prompt / few-shot demo 在不同调用间细微变化;
  • 不可见字符(BOM、零宽空格)或换行差异。

日志里看上去完全一样,但序列化出来并不一样。这一类问题本身不深,只说明排查非确定性前先校验输入字节级是否一致。

llm-Indeterminacy-why

如何尽量确定性

下面区分两种场景:云 API 调用 / 自建推理。

防御策略

黑盒对抗赛

  1. 配置层:参数去随机化
    • 配置:temperature 非 0 但极低(如 0.01–0.1),避免 0 被特殊处理;
    • 采样:锁定 top_p = 1、不使用 top_k、n = 1;
    • 文档:查阅各家关于 deterministic 字段的说明,按官方建议传参。
  2. 输入层:严格归一化 (针对“输入一致性”)
    • 确保在计算签名或调用前,对 Prompt 进行 字节级清洗对比, 严查时间戳等变量注入;
    • 剔除零宽空格、统一换行符 (\n vs \r\n)、并在 JSON 序列化时保证 key 顺序固定。
  3. 业务层:利用缓存构造“伪确定性” (针对“链路复现性”)
    • 定义一个请求签名: (model_version, temperature, top_p, system prompt, user prompt, seed);
    • 命中即返回:确保“相同参数 + 输入 ⇒ 永远返回同一条缓存结果”,在业务侧屏蔽底层的微小波动。
  4. 兜底策略:把 LLM 视为噪声组件
    • 结构化输出:LLM 生成候选 → Schema/Parser 严格校验 → 失败则重试;
    • 多数票机制:对关键分类任务发起 3 次调用取共识(Majority Vote);
    • 预期管理:在业务逻辑里显式兼容小范围的不一致。

控制策略

白盒自控主场赛

  1. 解码层:强制 Greedy
    • 在 vLLM / Transformers 中显式设置 do_sample=False;
    • 彻底禁用 top_p / top_k,防止框架内部的“低温采样”行为;
    • 若用 Beam Search,禁用所有涉及随机扰动的参数。
  2. 配置层:全链路种子固定
    • 代码级固定:torch.manual_seed、torch.cuda.manual_seed_all、numpy.random.seed;
    • 这只能解决“采样层”的随机性,无法解决“算子层”的并发噪声。
  3. 算子层:开启确定性模式 (牺牲性能)
    • 开启 PyTorch 确定性算法:torch.use_deterministic_algorithms(True);
    • 禁用优选 Benchmark:torch.backends.cudnn.benchmark = False;
    • 配置环境:设置 CUBLAS_WORKSPACE_CONFIG 使用确定性算法实现。
    • 代价:吞吐量显著下降,且部分高性能算子(FlashAttention 等)可能无法在确定性模式下运行。
  4. 调度层:牺牲 Batching (针对“批次差异”)
    • 独占推理:不跨请求拼 Batch,每个请求单独执行;
    • Batch-invariant 库:仅使用明确承诺了“批量无关性”的推理库版本。
    • 代价:GPU 利用率暴跌,成本激增。通常仅适用于离线审计或基准评测。

自建确定性策略带来的延迟倍率对比

数值精度与管线设计在重现性、性能与显存代价上的折中示意图

llm-Indeterminacy-do

总结

从研究与工程实践看:

  • 即使在 配置层 (temperature=0) 和 配置层 (seed) 拉满的情况下,算子层 和 调度层 的噪声依然存在;
  • 在云端 API 上追求 Bit-wise Deterministic 是不切实际的;
  • 在自建推理中,获得严格确定性的代价是大幅牺牲 吞吐与算力成本。

更合理的心智模型是:

LLM = 强大但带噪声的推理器
——在设计系统时,默认它“不完全可复现”,通过参数、缓存和上层逻辑来吸收这种噪声。

适合追求强一致性的环节(计费、风控、合规决策),应优先考虑确定性模型或规则系统;
LLM 更适合作为“辅助决策 + 文本代理”,而不是唯一的“权威判官”。

这样设计出来的系统,更符合当下大模型技术的真实边界。


文章主要借助 Perplexity + NotebookLM 检索文献和生成配图,对其中一篇核心参考强烈推荐原文阅读 Defeating Nondeterminism in LLM Inference