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 < 1、top_k > 1,只是温度降到 0; - 请求
n > 1,服务端对多条采样结果再做内部选择; - 模型供应商 对
temperature=0做了特殊处理或者忽略0,比如强制改成一个很小但非 0 的温度; - 部分供应商接口文档应该写的是 “mostly deterministic” 或 “best effort reproducibility”,并未承诺严格一致。
这些都意味着你以为关掉了随机性,实际上还在采样,而且 seed 只保证“这条采样序列可复现”,并不保证不采样。工程上遇到的多数“T=0 还在变”的案例,根因都在这一层。
1 | |
请求调度层
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、零宽空格)或换行差异。
日志里看上去完全一样,但序列化出来并不一样。这一类问题本身不深,只说明排查非确定性前先校验输入字节级是否一致。

如何尽量确定性
下面区分两种场景:云 API 调用 / 自建推理。
防御策略
黑盒对抗赛
- 配置层:参数去随机化
- 配置:temperature 非 0 但极低(如 0.01–0.1),避免 0 被特殊处理;
- 采样:锁定 top_p = 1、不使用 top_k、n = 1;
- 文档:查阅各家关于 deterministic 字段的说明,按官方建议传参。
- 输入层:严格归一化 (针对“输入一致性”)
- 确保在计算签名或调用前,对 Prompt 进行 字节级清洗对比, 严查时间戳等变量注入;
- 剔除零宽空格、统一换行符 (\n vs \r\n)、并在 JSON 序列化时保证 key 顺序固定。
- 业务层:利用缓存构造“伪确定性” (针对“链路复现性”)
- 定义一个请求签名: (model_version, temperature, top_p, system prompt, user prompt, seed);
- 命中即返回:确保“相同参数 + 输入 ⇒ 永远返回同一条缓存结果”,在业务侧屏蔽底层的微小波动。
- 兜底策略:把 LLM 视为噪声组件
- 结构化输出:LLM 生成候选 → Schema/Parser 严格校验 → 失败则重试;
- 多数票机制:对关键分类任务发起 3 次调用取共识(Majority Vote);
- 预期管理:在业务逻辑里显式兼容小范围的不一致。
控制策略
白盒自控主场赛
- 解码层:强制 Greedy
- 在 vLLM / Transformers 中显式设置 do_sample=False;
- 彻底禁用 top_p / top_k,防止框架内部的“低温采样”行为;
- 若用 Beam Search,禁用所有涉及随机扰动的参数。
- 配置层:全链路种子固定
- 代码级固定:torch.manual_seed、torch.cuda.manual_seed_all、numpy.random.seed;
- 这只能解决“采样层”的随机性,无法解决“算子层”的并发噪声。
- 算子层:开启确定性模式 (牺牲性能)
- 开启 PyTorch 确定性算法:torch.use_deterministic_algorithms(True);
- 禁用优选 Benchmark:torch.backends.cudnn.benchmark = False;
- 配置环境:设置 CUBLAS_WORKSPACE_CONFIG 使用确定性算法实现。
- 代价:吞吐量显著下降,且部分高性能算子(FlashAttention 等)可能无法在确定性模式下运行。
- 调度层:牺牲 Batching (针对“批次差异”)
- 独占推理:不跨请求拼 Batch,每个请求单独执行;
- Batch-invariant 库:仅使用明确承诺了“批量无关性”的推理库版本。
- 代价:GPU 利用率暴跌,成本激增。通常仅适用于离线审计或基准评测。



总结
从研究与工程实践看:
- 即使在 配置层 (temperature=0) 和 配置层 (seed) 拉满的情况下,算子层 和 调度层 的噪声依然存在;
- 在云端 API 上追求 Bit-wise Deterministic 是不切实际的;
- 在自建推理中,获得严格确定性的代价是大幅牺牲 吞吐与算力成本。
更合理的心智模型是:
LLM = 强大但带噪声的推理器
——在设计系统时,默认它“不完全可复现”,通过参数、缓存和上层逻辑来吸收这种噪声。
适合追求强一致性的环节(计费、风控、合规决策),应优先考虑确定性模型或规则系统;
LLM 更适合作为“辅助决策 + 文本代理”,而不是唯一的“权威判官”。
这样设计出来的系统,更符合当下大模型技术的真实边界。
文章主要借助
Perplexity+NotebookLM检索文献和生成配图,对其中一篇核心参考强烈推荐原文阅读 Defeating Nondeterminism in LLM Inference