ARTICLE · 1168376
AI 为什么两次回答不一样?真凶可能是服务器太忙了
跟 ChatGPT 问同一个问题,两遍答案不一样,这事大家早就习惯了。采样嘛,本来就要按概率随机挑 token。
但有个更瘆人的事实。
把 temperature 调到 0,理论上模型会沿着概率最高的路径贪婪解码,输出应该被彻底锁死。实际上它照样不稳。你在网页版试是这样,用 vLLM、SGLang 这类开源工具在自己机器上跑,也是这样。
这件事困扰了工程圈很久。直到,Thinking Machines 的 Horace He 团队发了篇博文,把真凶揪了出来。
结论有点反直觉:浮点数是背锅侠,真凶是服务器的忙闲。
Thinking Machines 是 OpenAI 前成员 Mira Murati 参与创立的公司,Horace He 是这篇技术博客的第一作者。
先说清楚,为什么会有误差
要让一组数加出完全一样的结果,有个隐含前提:加法顺序不能变。
浮点数偏偏做不到。受限于显示位数,两个相差好几个数量级的数相加,小的那个会被吃掉几位。
拿十进制打个比方。1230 加 23.4,精确答案是 1253.4。但系统只留 3 位精度,结果只能存成 1250。那个 23.4 在被加上之前,先被舍成了 20。
1230 + 23.4 = 1253.4(精确值)
→ 3 位精度下 = 1250
→ 23.4 先被舍成 20,才参与相加
更极端的例子在这:同一组数,只打乱相加顺序,能跑出 102 种不同的和。
这就是浮点数非结合性,(a+b)+c 和 a+(b+c) 可以不一样。误差的根源确实在这。
但背锅侠这次真没背稳
业内的传统解释是「并发 + 浮点数」。GPU 并行计算,谁先算完谁先加,累加顺序一变,结果就飘。
这个假设解释不了一件事。
同一块 GPU 上,同两个矩阵相乘,跑一千遍,结果位位相同。浮点数在用,并发也在跑,这一次为什么稳如老狗?
那篇被引用的 arXiv 预印本就是这套假设的代表,把非确定性一股脑归给浮点非结合性和执行顺序。眼看圆不回来,真凶必然藏在别的地方。
服务器忙不忙,决定了你的答案
真正的机制叫批处理不变性。先说两个容易混的概念。
从服务器的视角看,它是确定性的。但站在单个用户的视角,系统的输入只有你的请求,其他并发用户带来的只是波动属性。你问什么不重要,那会儿有几个人在跟你抢 GPU,才重要。
想象一个快递分拣站,分拣员是 GPU 核心,原则是把算力榨干。
快递堆成山时,三个分拣员各管一片,各自扫码、各自归类,互不打扰。这对应数据并行。
快递少的时候,一个区的活不够一个人忙,就把这堆货拆开:一个人扫码,一个人归类,最后再把结果汇总。这对应拆分归约。
两种做法都在优化吞吐。麻烦在于汇总方式变了,浮点误差的路径跟着变。
LLM 里到处是这种「汇总」,专业说法叫归约(reduction)。RMSNorm、矩阵乘、注意力,三个核心运算全都要归约。而推理引擎会根据当前 batch 大小,悄悄切换归约策略。
高峰时段你的请求可能和一百个人挤在同一批,闲时可能单独成批。batch 大小变了,归约方式就变,同一个问题于是有了不同的答案。
它不是抽风。它只是那会儿正好有别人在蹭车。
怎么修:让内核变得批处理不变
思路直接摊牌。不管 batch 多大,三个核心运算的归约策略全部锁死。
效果:1000 次生成,一次分叉都没了
实验用的是 Qwen3-235B-A22B-Instruct-2507,temperature=0,同一个 输入「谁是费曼?」生成 1000 次,每次 1000 个 token。
结果先泼一盆冷水。
1000 次跑出 80 种不同的输出,最常见的那个出现了 78 次。前 102 个 token 完全一致,第 103 个开始分叉。
所有输出都写到了「费曼出生于1918年5月11,在......」,然后开始兵分两路。
一个稳如泰山的 235B 大模型,在 1000 次生成里,连费曼的出生地都拿不准。而它抽不抽风,取决于当晚服务器的并发量。
换上批处理不变内核之后,同样的 1000 次生成,输出完全一致。模型没抽风。它那会儿正好有别人在蹭车。
代价:慢了 16 秒
用 Qwen3-8B 单卡压测,1000 个请求各输出约 100 token。
用百分之六十的性能余量,换一份可复现。在强化学习和在线评测这类场景,这笔账划算。
真正该紧张的是 RL 圈子
这篇博客最重的落点其实在这。
做强化学习的都知道一个难言之隐:采样器在跑模型,训练器也在跑同一份模型,两边对同一个 token 算出来的概率永远差一点。你的 on-policy RL,其实是偷偷降级成了 off-policy RL,得靠重要性权重硬掰回来。
而确定性的逻辑链是这样的:如果两次相同的推理请求都拿不到位位相同的结果,训练和推理之间更不可能对上。只有把推理侧也做到位级一致,采样和训练之间才能谈得上真正重合。
KL 散度归零,重要性权重归 1,on-policy 才是字面意义上的 on-policy。
Horace He 团队的实现已经开源在 thinking-machines-lab/batch-invariant-ops。做法是借 vLLM 的 FlexAttention 后端,再用 torch.Library 非侵入式替换掉相关算子。















































































