跳到主要内容

非确定性税:在概率性基础设施上构建可靠的流水线

· 阅读需 11 分钟
Tian Pan
Software Engineer

在生产级 LLM 工程中,设置 temperature=0 并期望获得可重现的输出是最常见的误解之一。这种想法很直观:温度控制随机性,所以零温度意味着零随机性。但温度只控制 Token 选择规则 —— 将概率采样切换为贪婪的 argmax。它对稳定 Logits 本身 毫无作用,而这才是真正产生变数的地方。

实际后果是:在 temperature=0 的情况下,针对同一个模型运行同一段提示词一千次,可能会产生 80 种不同的补全结果。这并非假设 —— 而是在现实的推理服务器条件下测试 Qwen3-235B 模型的实证结果。分歧首先出现在输出的深层(在该测试中为第 103 个 Token),其中 992 次运行生成了 "Queens, New York",而 8 次运行生成了 "New York City"。同样的模型,同样的提示词,同样的温度,由于服务器上不同的批处理状态而导致了差异。

这篇文章将解释导致这种变数的真正原因、如何衡量它,以及在本质上是概率性的基础设施之上构建可靠系统的三种架构模式。

为什么 Temperature=0 也不是确定性的

核心问题在于浮点运算。浮点加法不符合结合律:(a + b) + c 不一定等于 a + (b + c),因为每次操作都会引入舍入误差。在 GPU 并行执行中,线程以非确定性的顺序运行,这意味着中间值在不同次运行中以不同的序列累加。这些微小的舍入差异通过注意力机制(Attention)、层归一化(Layer Norm)和 Softmax 不断累积 —— 偶尔会改变哪个 Token 具有最高的 Logit。当第二个 Token 以小于浮点噪声的微弱优势超过第一个 Token 时,输出就会发生分歧。

这是单机内部变数的来源。在生产环境中,你还会遇到几个额外的放大器。

批次组合效应(Batch composition effects)。 现代推理服务器(vLLM、SGLang、TensorRT-LLM)使用连续批处理来将多个请求打包在一起。Softmax、层归一化和注意力的内核归约策略会根据批次中的条目数量改变其数值路径。你单独处理的请求所产生的 Logit,与该请求与另外 17 个请求共同处理时产生的 Logit 是不同的。服务器负载 —— 每秒钟都在变化 —— 决定了你会被分配到哪个批次中。

跨 GPU 的张量并行(Tensor parallelism)。 当推理分布在多个 GPU 上时,行并行层会分割张量并在设备间进行归约。改变 GPU 的数量会改变归约顺序,从而改变浮点舍入路径。一篇论文显示,Qwen3-8B 模型在 1、2、4 和 8 个 GPU 的张量并行规模下产生了四种不同的输出,在数学基准测试上的准确率差异超过 4 个百分点 —— 这纯粹是由于 TP 规模造成的,而非任何模型或提示词的改变。

稀疏混合专家(MoE)路由。 在 MoE 架构中,来自不同序列的 Token 在一个批次内竞争固定大小的专家组。同一个 Token 可能会被路由到不同的专家,这取决于同一个批次中恰好有哪些其他 Token。这意味着 MoE 模型仅在批次级别是确定性的,而在序列级别不是:改变共享批次的其他请求,会改变处理你 Token 的专家。

硬件和 CUDA 版本的差异。 不同的 GPU 世代和 CUDA 版本在实现归约时略有不同。跨提供商区域 —— 可能运行不同的硬件或驱动程序版本 —— 同样的种子(Seed)会产生不同的输出。OpenAI 的 system_fingerprint 字段之所以存在,正是因为后端基础设施“每年更改几次”,而每次更改都会破坏任何基于种子的重现性保证。种子参数被记录为“尽力而为” —— 而非契约保证。

实际情况有多糟?

在自然运行中,最佳性能和最差性能之间的差距应该让你重新校准预期。

一项正式研究在八个任务上测试了五个 LLM,每个任务运行十次。自然运行中的准确率波动在某些任务上达到了 15%。但最令人震惊的发现是 最佳可能 vs 最差可能 的差距 —— 即最幸运和最不幸的运行配置之间的范围。在大学水平的数学测试中:

  • Mixtral-8x7b:75% 最佳 vs 3% 最差 —— 72 个百分点的波动
  • GPT-4o:88% 最佳 vs 44% 最差 —— 44 个百分点的波动
  • Llama-3-70B:85% 最佳 vs 22% 最差 —— 63 个百分点的波动

这些并不是不同的提示词或不同的模型。它们是同样的模型、同样的提示词、不同的运行过程。另一项针对两个主要软件工程会议的 85 篇 LLM 论文的可重现性审计发现,在五项可执行的研究中,没有一项实现了完全的可重现性。

生产环境的影响会进一步叠加。任何比较“模型版本 A”与“模型版本 B”的 A/B 测试都会受到这种噪声的干扰。如果版本 A 显示了 2% 的准确率提升,但仅批次引起的变数就能导致 15% 的结果波动,那么这种比较在统计上可能毫无意义。RLHF 微调流水线也悄然面临风险:如果推理引擎使用的张量并行配置与训练引擎不同,这两个系统对于相同的模型权重会有数值上不同的 Logit,从而产生隐蔽的离策略分布偏移(Off-policy distribution shift),这可能会在不产生明显错误信号的情况下使奖励训练变得不稳定。

衡量可重复性

字符串精确匹配不是衡量可重复性的正确指标。因为即使语义内容一致,微小的格式变化也会导致报告的不稳定性居高不下,精确匹配会给你一种灾难性的悲观视角。一个始终能给出正确答案,但有时写 “A” 有时写 “选项 A” 的模型,在精确匹配下看起来会完全不可靠。

语义等价性测试(Semantic equivalence testing)是实际的替代方案。对每个响应进行向量嵌入(Embed),计算两两之间的余弦相似度,并将这些距离的标准差报告为语义稳定性评分。对于大多数任务,余弦相似度在 0.95 以上的响应可以被视为语义等价。这可以转化为一个具体的 CI 检查:运行 N 次相同的请求,对所有响应进行嵌入,如果两两相似度低于你的阈值,则将输出标记为不稳定。

对于结构化输出,你可以采取更粗粒度的检查:检查解析后的答案(JSON 对象中的字段值,或多选题中的选项选择)在多次运行中是否匹配,忽略表面格式。这种解析后的吻合率通常比原始字符串匹配高得多,并能让你真实地了解变异是否实际影响了决策。

对于容量规划和回归检测,最有效的聚合指标是:运行 50 次相同的请求,计算唯一生成结果(unique completions)的数量。一个结构良好的输出格式,如果输出空间较窄,应该产生 1-3 个唯一的生成结果。如果你看到 10 个以上,说明你存在变异问题,可以通过结构化输出或缓存来抑制。

有助于解决问题的三种模式

这些模式都不能消除 Logit 级别的非确定性——这需要基础设施层面的更改(批次不变内核,目前会损失 30-60% 的吞吐量)。相反,它们限制了变异对系统行为的影响。

严格的输出模式(Strict output schemas)。 受限解码——JSON 模式、带有严格 Schema 的函数调用、使用类型化参数的工具调用——通过在每个生成步骤中屏蔽无效 Token 来发挥作用。微小的 Logit 变化不再能将模型推向结构上不同的输出形状。模型在自由文本中可能会产生 “New York City” 而不是 “Queens, New York”,但如果你的 Schema 强制执行 {"borough": string},两者的答案都会收敛到相同的字段结构。Schema 强制执行并不能消除数值上的变异;它消除了形状上的变异。结合有限取值集的枚举(enum)约束,它可以同时消除这两者的变异。

测试和监控中的语义等价层。 在 Eval 流水线、回归测试和输出监控中,用基于嵌入的相似度检查取代字符串精确匹配。这有两个作用。首先,它能防止在输出仅有表面变化而非语义变化时触发误报。其次,它迫使你为你的应用定义什么是“相同”——这是一个有用的强制机制,能让你理解自己对变异的容忍度。经历过这种练习的团队通常会发现,许多他们原本视为失败的表面变异实际上是可以接受的,而少数被他们忽视的语义变异才是真正的问题。

幂等性缓存(Idempotency caching)。 最健壮的应用层模式:将模型输出缓存起来,键值使用 (model_id, prompt_hash, parameters) 的确定性哈希。对于具有相同输入的重复请求,直接提供缓存的响应。这可以通过 Redis 轻松实现,并完全消除了重复请求的模型级变异——这涵盖了生产环境中惊人比例的流量(重试、轮询模式、重新渲染)。特别对于智能体(Agent)的工具调用,幂等键可以防止重试时产生重复的副作用。局限性在于,当你确实需要对新输入获得新鲜响应时,它无法提供帮助,但它消除了由于非确定性导致系统对同一事件做出两种不同决策的那类故障。

更深层的设计原则

这三种模式背后潜藏的思想转变是:将你的 LLM 视为网络调用,而不是函数调用。具有相同输入的函数调用总是返回相同的输出。而网络调用可能会根据你无法控制的条件返回不同的结果。你不会构建一个如果两个连续的 HTTP 请求返回略有不同的响应时间就会失败的支付系统。你会将其构建为能够容忍变化,并尽管存在变化也能做出稳定的决策。

LLM 输出也是如此。强制它们进入类型化的 Schema、测试语义等价性而非字符串相等、以及尽可能进行缓存,这些都与构建幂等的 HTTP 客户端属于同一种准则。底层基础设施是概率性的,但你的应用逻辑不必如此。

提供批次不变内核(batch-invariant kernels)和确定性注意力实现的基础设施团队最终将弥补大部分硬件层面的差距——吞吐量成本正在下降,工具也在趋于成熟。但即使有了确定性内核,跨供应商路由、硬件机群演进和模型版本更新仍会不断在系统层面引入变异。无论基础设施如何演进,为语义稳定性而非字符串可重复性而构建的架构准则都将保持其重要性。

非确定性税是真实存在的,但它也是有限度的。了解它的来源,根据符合你可靠性要求的术语来衡量它,并设计你的应用层来吸收它。

References:Let's stay in touch and Follow me for more thoughts and updates