# PR #2002 完整报告

- 仓库：`radixark/miles`
- 标题：Stop passing a random seed and let each sglang engine pick its own
- 合并时间：2026-09-04 13:46
- 原文链接：http://prhub.com.cn/radixark/miles/pull/2002

---

# 执行摘要

- 一句话：移除 SGLang 引擎的固定随机种子配置，改为由 SGLang 自行生成，简化启动参数并验证其随机性。
- 推荐动作：该 PR 代码变更简单，但讨论揭示了一个重要的技术权衡。**值得精读**，特别是 `guapisolo` 的评论，它深入分析了 SGLang 随机数生成的内部机制，并指出了一个具体的、生产级别的可复现性风险场景。对于理解 SGLang 集成细节和随机数管理策略非常有价值。团队应确认风险是否已在内部闭环解决（如与 SGLang 团队协调推进种子化全覆盖）。

# 功能与动机

此变更旨在简化 SGLang 引擎启动接口，将随机种子的管理责任从 `miles` 转移到 SGLang 内部。这减少了配置的耦合度，是更广泛的重构和简化引擎启动逻辑的一部分（关联 Issue #1837）。PR 标题明确表达了“停止传递随机种子，让每个引擎自行选择”的意图。

# 实现拆解

1. **核心逻辑变更（`miles/backends/sglang_utils/sglang_engine.py`）**：在 `_compute_server_args` 函数中，从构建 `kwargs` 字典的步骤中，移除了显式设置 `"random_seed": args.seed + rank` 这一行。改为添加一条注释（`# NOTE: do not pass random seed and let SGLang pick random ones`），表明该参数由 SGLang 内部处理。这是配置键层面的精简，旨在将种子生成的责任下放。
2. **测试覆盖（`tests/fast/backends/sglang_utils/test_sglang_engine.py`）**：在 `TestComputeEngineLaunchPlan` 测试类中新增 `test_every_plan_picks_a_fresh_random_seed` 测试用例。该测试通过创建一个引擎参数集并多次调用 `_cmd` 辅助函数（进而调用 `compute_engine_launch_plan`），解析生成的命令行参数以获取 `random_seed` 值，并断言：(a) 多次生成的结果不完全相同，证明了 SGLang 会生成不同的种子；(b) `miles` 传入的 `args.seed` 不在这些生成的种子集合中，证明了原有的传递逻辑已被有效绕过。
3. **影响范围**：变更仅影响 SGLang 推理引擎的启动参数构建，不涉及 `miles` 的训练、调度或核心执行逻辑。配套的测试直接验证了修改后的源码行为。

关键文件：
- `miles/backends/sglang_utils/sglang_engine.py`（模块 引擎配置；类别 source；类型 core-logic；符号 _compute_server_args）: 核心变更文件，包含移除显式随机种子传递的逻辑，是本次重构的实施点。
- `tests/fast/backends/sglang_utils/test_sglang_engine.py`（模块 引擎配置；类别 test；类型 test-coverage；符号 test_every_plan_picks_a_fresh_random_seed）: 配套测试文件，新增测试用例直接验证本次重构的核心行为变更——引擎随机种子不再由外部传递。

关键符号：_compute_server_args

## 关键源码片段

### `miles/backends/sglang_utils/sglang_engine.py`

核心变更文件，包含移除显式随机种子传递的逻辑，是本次重构的实施点。

```python
# 在 miles/backends/sglang_utils/sglang_engine.py 的 _compute_server_args 函数中：
    kwargs = {
        "model_path": args.hf_checkpoint,
        "trust_remote_code": True,
        # NOTE: do not pass random seed and let SGLang pick random ones
        # "random_seed": args.seed + rank, # 旧代码：由 Miles 计算并传递固定种子
        # memory
        "enable_memory_saver": args.offload_rollout,
        # distributed
        "host": host,
        "port": port,
        # ... 其他分布式参数 ...
        # parallel
        "tp_size": _gpus_per_engine,
        # ... 其他并行参数 ...
        "skip_server_warmup": True,
        "enable_draft_weights_cpu_backup": True,
        "enable_metrics": True,
    }
    # 关键变更：移除了 `random_seed` 键值对，使 SGLang 引擎在启动时自行生成
    # 随机种子。这减少了 Miles 对引擎内部随机数生成的干预，简化了配置。

```

### `tests/fast/backends/sglang_utils/test_sglang_engine.py`

配套测试文件，新增测试用例直接验证本次重构的核心行为变更——引擎随机种子不再由外部传递。

```python
# 在 tests/fast/backends/sglang_utils/test_sglang_engine.py 的 TestComputeEngineLaunchPlan 类中：
    def test_every_plan_picks_a_fresh_random_seed(self):
        """Each launch leaves the seed to sglang, so two plans never share one."""
        args = make_engine_args()
        # 通过多次调用 _cmd 生成启动命令，解析其中的 random_seed 参数
        # 注意：_cmd 内部调用了 compute_engine_launch_plan，最终构建命令行
        seeds: set[int] = {
            parse_server_args_argv(shlex.split(_cmd(args=args))[3:]).random_seed
            for _ in range(5)
        }
        # 断言 1：生成的种子集合大小大于 1，证明 SGLang 生成了不同的种子
        assert len(seeds) > 1
        # 断言 2：Miles 原始传入的种子不在这些生成的种子中，证明传递已被绕过
        assert args.seed not in seeds

```

# 评论区精华

Review 者 `guapisolo` 提出了一个 **[P1] 级别的阻塞性可复现性问题**。其核心观点是：移除固定种子可能破坏非贪婪推测解码（如 EAGLE）场景下的可复现性。因为 SGLang 引擎内部并非所有随机数生成路径（RNG consumers）都受请求级种子（`sampling_seed`）控制。具体指出，在 `sglang-miles` 分支中，EAGLE 的验证币（verification coins）仍然使用引擎全局的 `torch.rand`，且相关的上游 PR (#30822) 尚未合入。因此，让 SGLang 选择一个全新的引擎种子，会导致相同的请求集在相同请求种子下，由于引擎内部 RNG 初始状态不同，最终生成的输出（尤其是推测解码路径）存在差异。**决策结论**：该评论被标记为 P1 阻塞性问题，但 PR 仍被合并，表明可能在内部已评估风险或计划在后续 PR 中解决（例如，推动上游 PR 合入或在 Miles 侧进行适配）。**未解决疑虑**：对于依赖特定 SGLang 分支进行推测解码的用户，此变更可能引入意外的行为变更，需要他们自行确保 SGLang 引擎内部所有关键 RNG 路径已实现请求级种子化。

- 移除固定引擎种子可能破坏非贪婪推测解码的可复现性 (correctness): 此问题被标记为 P1 阻塞性问题，但 PR 仍被合并。结论可能是团队评估了风险（例如，认为生产环境主要使用确定性采样器，或计划在后续推动 SGLang 侧完成种子化全覆盖），或者在其他沟通渠道已达成共识。

# 风险与影响

- 风险：
 1. **可复现性风险**：这是被明确提出的核心风险。变更可能破坏现有工作流中对推理结果的精确可复现性要求，尤其是在使用了非标准或未完全支持请求级种子化的 SGLang 分支进行推测解码（如 EAGLE）时。风险点具体在 `sglang_engine.py` 的 `kwargs` 构建逻辑，影响所有通过 `compute_engine_launch_plan` 启动的 SGLang 引擎。
 2. **行为变更风险**：此变更修改了引擎启动的确定性。对于依赖固定种子进行调试或基准测试的流程，结果可能发生变化。
 3. **测试验证局限性**：新增的测试验证了 `miles` 侧不再传递种子，且 SGLang 会生成不同的种子。然而，它并未验证所有 SGLang 分支在移除此种子后，在所有使用场景下（特别是推测解码）仍能保持必要的随机性或可复现性，这是一个覆盖范围上的局限性。
 - 影响：**对用户 / 下游影响**：主要影响那些依赖固定推理引擎随机种子以确保精确输出复现性的用户。如果用户使用的 SGLang 分支尚未实现全路径的请求级种子化，其非贪婪推理结果的可复现性可能会降低。**对系统 / 团队影响**：简化了引擎启动参数，减少了 `miles` 与 SGLang 之间的一个配置耦合点，符合重构方向。需要团队意识到此变更的潜在影响，并在文档或发布说明中提示用户关于推测解码场景下的可复现性注意事项。**影响范围**：中等。变更集中在一个配置点，但触及了推理引擎的随机数生成这一基础行为，可能影响所有使用 SGLang 推理后端的功能。
 - 风险标记：可复现性风险 , 核心配置变更

# 关联脉络

- PR #2004 Extract compute_inference_engine_env_vars and forbid compute_server_args defaults: 同属 Issue #1837 重构链，重构了引擎启动参数的计算方式（提取环境变量函数、禁止默认值），与本 PR 移除一项参数同属简化接口的范畴。
- PR #2005 Derive the engine api key from the model config: 同属 Issue #1837 重构链，重构了引擎 API 密钥的获取逻辑，也是简化引擎启动配置的一部分。
- PR #2006 Launch inference engines through the inference engine worker spec: 同属 Issue #1837 重构链，引入了推理引擎工作器规范（Worker Spec）来统一启动逻辑，本 PR 的随机种子参数移除是该规范化过程中的一个具体调整。
- PR #2003 Pass node_rank instead of rank when computing the engine launch command: 同属 Issue #1837 重构链，调整了引擎启动命令计算函数的参数语义（从 rank 到 node_rank），与本 PR 同在 `sglang_engine.py` 的 `_compute_server_args` 函数及相关测试中进行修改。