系统层不确定性
定义
系统层不确定性 是指: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% 的推理减速;
- 主流后端平均损失在三成出头;
- 官方说明更偏向“调试和复现”用途;