# PR #36905 完整报告

- 仓库：`sgl-project/sglang`
- 标题：[Diffusion] Honor explicit offload in resident requirements
- 合并时间：2026-08-29 22:48
- 原文链接：http://prhub.com.cn/sgl-project/sglang/pull/36905

---

# 执行摘要

- 一句话：驻留要求尊重显式卸载配置，修复冲突未报错
- 推荐动作：此 PR 值得精读，因为修复了一个配置静默覆盖的隐患，并引入了通用化校验逻辑。核心设计决策：使用 `explicit_residency_mode` 统一检查所有显式驻留面，可推广到其他组件要求。建议后续在文档中说明冲突报错行为。

# 功能与动机

PR 描述明确指出，需要让仅驻留的组件功能尊重所有显式驻留面，包括兼容性卸载标志。原先逻辑仅检查 `--component-residency`，导致用户通过 `--cpu-offload-components` 或旧版 `text_encoder_cpu_offload` 等标志配置卸载时，`require_component_resident` 会静默忽略并强行将组件置于驻留，造成配置冲突但无提示。此变更旨在拒绝这些显式卸载配置，避免静默覆盖。

# 实现拆解

1. **入口变更**：修改 `python/sglang/multimodal_gen/runtime/server_args/server_args.py` 中 `require_component_resident` 方法，将内部检查调用从 `canonical_residency_mode` 改为 `explicit_residency_mode`。
2. **核心逻辑**：`explicit_residency_mode` 会汇总所有显式驻留面（`component_residency`、`cpu_offload_components`、`text_encoder_cpu_offload`、`image_encoder_cpu_offload`、`vae_cpu_offload`、`dit_cpu_offload`、`layerwise_offload_components`），若任一返回非 RESIDENT 模式，则抛出 ValueError，提示“explicit residency option”。这样确保任何显式卸载配置都会被拒绝。
3. **测试配套**：在 `python/sglang/multimodal_gen/test/unit/test_server_args.py` 中新增两个测试用例：`test_resident_requirement_rejects_every_explicit_offload_surface` 覆盖五种显式卸载面，均断言抛出 ValueError；`test_resident_requirement_can_override_automatic_placement` 验证自动放置（如 memory 模式下 text_encoder 默认非驻留）会被正确提升为驻留。

关键文件：
- `python/sglang/multimodal_gen/runtime/server_args/server_args.py`（模块 服务端参数；类别 source；类型 core-logic；符号 require_component_resident）: 核心逻辑变更，`require_component_resident` 改为检查 `explicit_residency_mode`，并更新错误消息。
- `python/sglang/multimodal_gen/test/unit/test_server_args.py`（模块 测试；类别 test；类型 test-coverage；符号 test_resident_requirement_rejects_every_explicit_offload_surface, test_resident_requirement_can_override_automatic_placement）: 新增测试覆盖所有显式卸载面及自动放置提升场景，确保行为正确。

关键符号：require_component_resident

## 关键源码片段

### `python/sglang/multimodal_gen/runtime/server_args/server_args.py`

核心逻辑变更，`require_component_resident` 改为检查 `explicit_residency_mode`，并更新错误消息。

```python
# python/sglang/multimodal_gen/runtime/server_args/server_args.py

def require_component_resident(
    self, component_name: str, *, feature_name: str
) -> None:
    # 改为使用 explicit_residency_mode，覆盖所有显式驻留面（component_residency、
    # cpu_offload_components、各组件卸载标志、旧版逐层卸载选择）
    configured_mode = self.explicit_residency_mode(component_name)
    if configured_mode is not None and configured_mode != RESIDENT:
        # 任何显式卸载配置都与驻留要求冲突，直接报错，避免静默覆盖
        raise ValueError(
            f"{feature_name} requires {component_name!r} to be resident; "
            f"got {configured_mode!r} from an explicit residency option"
        )
    # 记录为必需驻留组件，供后续调度使用
    self._required_resident_components.add(component_name)

```

### `python/sglang/multimodal_gen/test/unit/test_server_args.py`

新增测试覆盖所有显式卸载面及自动放置提升场景，确保行为正确。

```python
# python/sglang/multimodal_gen/test/unit/test_server_args.py

def test_resident_requirement_rejects_every_explicit_offload_surface(self):
    # 构造所有显式卸载面：component_residency、cpu_offload_components、
    # 组件卸载标志、旧版逐层卸载选择
    cases = (
        {"component_residency": ["text_encoder=component-offload"]},
        {"component_residency": ["text_encoder=layerwise-offload"]},
        {"cpu_offload_components": ["text_encoder"]},
        {"text_encoder_cpu_offload": True},
        {"layerwise_offload_components": ["text_encoder"]},
    )
    for kwargs in cases:
        with self.subTest(kwargs=kwargs):
            args = self._from_dict_with_task_type(
                ModelTaskType.T2V,
                kwargs={"performance_mode": "manual", **kwargs},
            )
            # 必须抛出 ValueError，错误消息包含 "explicit residency option"
            with self.assertRaisesRegex(ValueError, "explicit residency option"):
                args.require_component_resident(
                    "text_encoder", feature_name="test backend"
                )

def test_resident_requirement_can_override_automatic_placement(self):
    # 默认 memory 模式下 text_encoder 非驻留
    args = self._from_dict_with_task_type(ModelTaskType.T2V, memory_gb=16)
    self.assertIsNone(args.explicit_residency_mode("text_encoder"))
    self.assertNotEqual(args.residency_mode("text_encoder"), RESIDENT)

    # 显式要求驻留后，应提升为 RESIDENT
    args.require_component_resident("text_encoder", feature_name="test backend")
    self.assertEqual(args.residency_mode("text_encoder"), RESIDENT)

```

# 评论区精华

此 PR 无 review 评论和讨论线程。

- 暂无高价值评论线程

# 风险与影响

- 风险：此变更是对 `require_component_resident` 的严格化，可能导致之前静默覆盖的配置现在显式报错，从而中断服务启动。但这是预期行为，能提前暴露配置冲突。风险点：若某些旧配置依赖静默覆盖，升级后可能启动失败，需用户调整配置。影响文件仅两处，逻辑简单，回归风险低。
- 影响：影响范围：`sglang/multimodal_gen` 扩散流水线服务端参数解析。对用户而言，显式配置了卸载但组件要求驻留时，会得到清晰错误提示，避免运行时异常；对系统而言，增强配置一致性，防止静默覆盖。对团队而言，该修复提升参数校验的严谨性，为后续仅驻留后端提供可靠基础，影响程度中等（配置报错但功能路径不变）。
- 风险标记：配置冲突报错可能中断启动 , 未运行完整 GPU CI

# 关联脉络

- PR #36931 [diffusion] Honor explicit component offload: 同属 diffusion 组件卸载与驻留逻辑，且标题几乎一致，很可能直接相关或收尾。