W
AI-Wiki
CONCEPT

系统层不确定性

定义

系统层不确定性 是指:LLM 的输出不稳定,并不只来自采样式生成的随机性,还来自生产级推理服务内部的并发调度、动态批处理、底层计算 kernel 以及浮点数运算顺序变化。

核心判断:同一个输入在不同时间得到不同输出,未必是 prompt 写坏了,也未必只是采样温度造成的;它可能是系统本身在不同运行状态下走了不同的数值路径。

在本文语境里,这个概念专门用来解释一个常见误解:很多人以为把 temperature 调成 0,就能让模型彻底“确定”;但真实的 ToB 部署里,哪怕 temperature=0,也仍然可能出现输出不一致。

在本文档中的语境

本文讨论的是 ToB AI 场景里的“确定性”问题,尤其是企业客户关心的那种:

  • 同一个问题,反复询问,能否给出同样结果;
  • 结果是否正确;
  • 出了争议之后,能否回溯依据。

其中,系统层不确定性 解释的是第一层门槛为什么天然难:企业看到的是“同样一句问询,今天和明天对不上”,而根因未必在业务规则,而可能在推理服务底层。

这也是 确定性笼子 这一思路成立的前提:既然不确定性深到内核层,就不要把主要工程赌注押在“彻底消灭模型内核抖动”上,而应在系统外层用确定性流程包住模型。

关键机制

1. 不确定性不只来自采样

最容易想到的不确定性来源是采样。人们通常会把输出波动归因于:

  • temperature 较高;
  • top-k、top-p 等采样策略;
  • 解码时的随机选择。

但本文明确指出,这只是来源之一,不是全部。即便把 temperature 拉到 0,系统仍然可能不稳定。

也就是说,系统层不确定性 的重点不在“模型愿不愿意随机”,而在“服务系统是否让同一输入每次都经过完全相同的计算路径”。

2. 并发负载会改变 batch size

生产环境里的 LLM 服务通常不会只为一个请求单独运行,而是会把同一时刻到达的多个请求合批处理。

问题在于,生产负载是波动的:

  • 这一秒可能只有 10 个请求一起算;
  • 下一秒可能有 100 个请求一起算。

请求数变化会直接改变动态 batch size。而 batch size 一变,底层算子在实际执行时的分块方式、并行安排、归约过程就可能变化。

从单个用户视角看,这些与自己一起进入批处理的并发请求,并不是自己显式提供的输入,却实实在在影响了本次计算结果。

因此,文中给出了一个很关键的表述:并发负载对单个用户而言,是系统的一个非确定属性。

换句话说:

  • 你提交的 prompt 没变;
  • 采样温度也没变;
  • 但系统所处的并发状态变了。

而这就足以让结果发生变化。

3. 浮点累加顺序会影响结果

底层的 matmul、attention 等 kernel 并不是在数学黑板上用实数精确计算,而是在有限精度的浮点系统里执行。

浮点数运算有一个工程上非常重要的性质:浮点累加不满足结合律

这意味着:

  • 理论上等价的 ((a + b) + c)(a + (b + c))
  • 在浮点环境下,实际结果最后几位可能不同。

当 batch size、线程调度、kernel 实现路径改变时,累加顺序也可能随之改变;累加顺序一变,数值末位就可能变化。

这些差异一开始可能只体现在最后几位,但在深层网络和离散 token 选择中,微小差异可能继续放大,最终让解码路径分叉,表现为输出文本不同。

因此,系统层不确定性 并不是抽象地说“系统有波动”,而是有非常具体的数值计算根源:浮点归约顺序变化会改写中间结果,而中间结果的细小差异足以影响最终 token。

4. 不确定性深到推理内核

本文特别强调,不确定性“深到了内核”。这里的“内核”不是操作系统内核,而是推理时实际运行的底层计算 kernel。

这句话的含义是:

  • 不确定性不只是提示词层的问题;
  • 不只是采样层的问题;
  • 甚至不只是模型参数层的问题;
  • 它可以出现在更深的数值执行层。

所以很多人第一反应“那我把 temperature 设成 0 就行了”,在这里是不成立的。temperature=0 只能约束解码策略,不能保证底层每次都走完全相同的数值轨迹。

为什么 temperature=0 也无法根除

在本文语境里,temperature=0 只意味着:在给定 logits 的条件下,解码阶段尽量走贪心或固定选择,而不是主动引入更强的采样随机性。

但它并不能解决以下问题:

  • 同一输入在不同并发负载下被分配到不同 batch;
  • 不同 batch 触发不同的底层并行与归约路径;
  • 浮点累加顺序变化导致 logits 或中间激活出现细微差异;
  • 这些细微差异最终让贪心选择本身也不同。

因此,temperature=0 不能被理解为“彻底确定化开关”。它顶多是压低一部分采样层波动,而无法根除系统层和内核层的不确定性。

这也是本文最需要记住的结论之一:把 temperature 设为 0,不等于把 LLM 变成一个严格的确定函数。

细节与边界

1. 这里说的是生产服务,不是理想化单机实验

系统层不确定性 的讨论重点是生产环境,尤其是在线推理服务。

在理想化实验条件下,如果你:

  • 固定硬件;
  • 固定驱动和库版本;
  • 固定 batch;
  • 固定执行路径;
  • 排除并发请求干扰;
  • 使用专门的确定性配置;

那么可复现性可以显著提高。

但本文要指出的是:企业实际买到和使用的不是这种隔离实验,而是一个带并发、讲吞吐、要控成本的服务系统。真正的难点恰恰出现在这里。

2. 它解释的是“为什么会抖”,不自动等于“结果错误”

系统层不确定性 关注的是输出波动的来源,它本身并不直接判定结果对错。

同一个问题今天和明天输出不同,可能是:

  • 一个对一个错;
  • 两个都对但表述不同;
  • 两个都错;
  • 一个更符合业务口径。

所以它和正确性不是同一个概念。本文后续专门区分了“可复现”“正确”“可审计”三件事,正是为了避免把“输出稳定”误当成“业务正确”。

3. 内核层可做缓解,但常常不是 ToB 的主解

文中提到 SGLang 基于 Thinking Machines 的工作提出过 batch-invariant kernel,目标是让结果不再依赖 batch 中有多少请求,使同一输入走相同的累加顺序,从而实现更强的逐字可复现。

但本文同时指出,这条路在 ToB 查询场景里通常不是首选,原因包括:

  • 开启 batch-invariant 会带来约 25% 到 45% 的推理减速;
  • 主流后端平均损失在三成出头;
  • 官方说明更偏向“调试和复现”用途;