确定性推理#
为什么确定性推理很重要#
确定性推理确保在不同运行中 LLM 输出的一致性,这对于以下场景至关重要:
强化学习:确保各次运行中的日志概率一致,减少随机噪声,使 RL 训练更加稳定、可重现且易于调试。
测试与调试:实现可重现的验证
生产环境:提高可靠性和用户体验
即使设置了 temperature=0,标准的 LLM 推理也可能由于动态批处理和 GPU 内核中不同的归约顺序而产生不同的输出。
非确定性的根本原因#
主要来源是变化的批处理大小。不同的批处理大小会导致 GPU 内核以不同方式分割归约操作,从而导致不同的加法顺序。由于浮点数不满足结合律((a + b) + c ≠ a + (b + c)),即使对于相同的输入,这也会产生不同的结果。
SGLang 的解决方案#
基于Thinking Machines Lab 的批处理不变算子,SGLang 实现了完全确定性的推理,同时保持了与分块预填充、CUDA 图、基数缓存和非贪婪采样的兼容性。确定性推理功能的发展路线图可以在此问题中找到。
支持的后端#
确定性推理仅支持以下三种注意力后端:FlashInfer、FlashAttention 3 (FA3) 和 Triton。
下表显示了不同注意力后端之间确定性推理的功能兼容性:
注意力后端 |
CUDA 图 |
分块预填充 |
基数缓存 |
非贪婪采样 (Temp > 0) |
|---|---|---|---|---|
FlashInfer |
✅ 支持 |
✅ 支持 |
❌ 不支持 |
✅ 支持 |
FlashAttention 3 (FA3) |
✅ 支持 |
✅ 支持 |
✅ 支持 |
✅ 支持 |
Triton |
✅ 支持 |
✅ 支持 |
✅ 支持 |
✅ 支持 |
使用方法#
基本用法#
通过添加 --enable-deterministic-inference 标志启用确定性推理:
python3 -m sglang.launch_server \
--model-path Qwen/Qwen3-8B \
--attention-backend fa3 \
--enable-deterministic-inference
服务器参数#
参数 |
类型/默认值 |
描述 |
|---|---|---|
|
标志;默认:禁用 |
使用批处理不变操作启用确定性推理 |
|
字符串;默认:fa3 |
选择注意力后端(flashinfer、fa3 或 triton) |
示例配置#
Qwen3-8B#
python3 -m sglang.launch_server \
--model-path Qwen/Qwen3-8B \
--attention-backend flashinfer \
--enable-deterministic-inference
Llama 模型#
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--attention-backend fa3 \
--enable-deterministic-inference
Qwen3-30B-A3B (MoE 模型)#
python3 -m sglang.launch_server \
--model-path Qwen/Qwen3-30B-A3B \
--attention-backend fa3 \
--enable-deterministic-inference
结合非贪婪采样的确定性推理 (Temperature > 0)#
SGLang 通过使用采样种子,即使在非贪婪采样下也支持确定性推理。这对于像 GRPO(组相对策略优化)这样的强化学习场景特别有用,在这些场景中,您需要多个多样但可重现的响应。
默认行为#
默认情况下,SGLang 使用采样种子 42 进行可重现的采样:
import requests
response = requests.post(
"http://localhost:30000/generate",
json={
"text": "给我讲个笑话",
"sampling_params": {
"temperature": 0.8, # 非贪婪采样
"max_new_tokens": 128,
},
},
)
print(response.json())
# 这将在不同运行中始终产生相同的响应
生成多个可重现的响应#
从同一提示词中采样不同的响应,同时保持可重现性(例如,用于 GRPO 训练),请在请求中提供不同的采样种子:
import requests
# 为不同响应准备采样种子列表
sampling_seeds = [42, 43, 44, 45, 46]
responses = []
for seed in sampling_seeds:
response = requests.post(
"http://localhost:30000/generate",
json={
"text": "给我讲个笑话",
"sampling_params": {
"temperature": 0.8,
"max_new_tokens": 128,
"sampling_seed": seed, # 指定采样种子
},
},
)
responses.append(response.json())
# 每个种子将产生不同的但可重现的响应
# 使用相同的种子将始终产生相同的响应
这种方法确保:
不同的种子产生多样的响应
相同的种子在不同运行中始终产生相同的响应
结果对于调试和评估是可重现的
验证#
运行确定性测试以验证输出的一致性:
# 单次测试:相同的提示词,变化的批处理大小
python3 -m sglang.test.test_deterministic --test-mode single --n-trials 50
# 前缀测试:具有不同前缀长度的提示词
python3 -m sglang.test.test_deterministic --test-mode prefix --n-trials 50
# 基数缓存一致性模式:测试基数缓存确定性(缓存与未缓存的预填充)
python3 -m sglang.test.test_deterministic --test-mode radix_cache
预期结果:所有测试都应显示 Unique samples: 1(完全确定性)。