Prhub

#25050 Add --model-config-parser registry for pluggable config formats

原始 PR 作者 charlotte12l 合并时间 2026-05-14 16:54 文件变更 5 提交数 2 评论 13 代码增减 +328 / -123

执行摘要

添加 --model-config-parser 注册表,支持自定义配置格式

允许外部包插入自定义配置加载路径(如原生训练检查点、替代 params.json 方言),无需修改 sglang 核心。详见 PR body:'Introduces a named registry so external packages can plug in custom config-loading paths ... without modifying sglang core.'

建议精读。该 PR 展示了良好的扩展点设计(注册表 + 抽象基类),详细的向后兼容性分析(Mistral 检测),以及干净的代码迁移(get_config 拆分为独立解析器)。是 sglang 配置系统架构演进的重要一步。

讨论亮点

PR 无 review 评论,但 PR body 详细记录了 Mistral 检测逻辑的改进理由和决策过程。关键点:将 _is_mistral_native_format 从基于 params.json 存在改为基于 consolidated.safetensors 存在且无 model-.safetensors,保留名称白名单,确保旧有 Mistral 模型不受影响(如 Mistral-7B v0.1 和 mistral-large-3)。

实现拆解

  1. 定义注册表基础设施:新建 python/sglang/srt/configs/model_config_parser_registry.py,定义抽象基类 ModelConfigParserBase、注册函数 register_model_config_parser、查找函数 get_model_config_parser。采用装饰器模式,支持名称到解析器的映射。
  2. 封装内置解析器:在 python/sglang/srt/utils/hf_transformers/config.py 中,将原有 get_config 中 HF 解析逻辑提取到 HfModelConfigParser,Mistral 解析逻辑提取到 MistralModelConfigParser,并分别用 @register_model_config_parser("hf")@register_model_config_parser("mistral") 注册。原有 get_config 改为根据 model_config_parser 参数分派。
  3. 新增 CLI 参数:在 python/sglang/srt/server_args.pyServerArgs 中添加 model_config_parser 字段(默认 "auto"),在 add_cli_args 中添加 --model-config-parser 参数。修改 ModelConfig 以接收并传递该参数。
  4. 精化 Mistral 格式检测:将 _is_mistral_native_format 从简单的 params.json+无 config.json 改为以 consolidated*.safetensors 存在且无 model-*.safetensors 为主要信号,辅以名称白名单(mistral-large-3 等),减少对自定义格式的误判。
  5. 添加单元测试:新建 test/registered/unit/configs/test_model_config_parser_registry.py,覆盖注册、查找、类型校验、错误消息体验等场景,注册为 CPU CI 套件。
文件 模块 状态 重要度
python/sglang/srt/configs/model_config_parser_registry.py 配置注册表 added 8.81
python/sglang/srt/utils/hf_transformers/config.py 配置加载 modified 8.62
python/sglang/srt/server_args.py 服务器参数 modified 7.55
python/sglang/srt/configs/model_config.py 模型配置 modified 5.28
test/registered/unit/configs/test_model_config_parser_registry.py 单元测试 added 7.78

关键符号

ModelConfigParserBase.parse register_model_config_parser get_model_config_parser HfModelConfigParser.parse MistralModelConfigParser.parse get_config _is_mistral_native_format TestModelConfigParserRegistry.test_register_then_get_roundtrip TestModelConfigParserRegistry.test_register_rejects_non_subclass TestModelConfigParserRegistry.test_unknown_name_raises_with_registered_list

关键源码片段

python/sglang/srt/configs/model_config_parser_registry.py data-contract

新增注册表核心文件,定义抽象基类、注册装饰器和查找函数,是可插拔设计的基础。

"""Named registry for model-config parsers.Mirrors the ``LoadFormat.PRIVATE`` escape hatch in
:mod:`sglang.srt.configs.load_config` but registry-shaped, so multiple
plugins can coexist without colliding on a single private import path.
"""from __future__ import annotationsimport logging
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Optionalfrom transformers import PretrainedConfiglogger = logging.getLogger(__name__)
​
​
# 抽象基类:所有解析器必须实现 parse 方法,返回 PretrainedConfig
class ModelConfigParserBase(ABC):
    @abstractmethod
    def parse(
        self,
        model: str | Path,
        trust_remote_code: bool,
        revision: Optional[str] = None,
        **kwargs,
    ) -> PretrainedConfig:
        raise NotImplementedError
​
​
# 全局注册表,名称到类(而非实例),每次 get 时实例化,保证解析器可包含 per-call 状态
_MODEL_CONFIG_PARSER_REGISTRY: dict[str, type[ModelConfigParserBase]] = {}
​
​
def register_model_config_parser(name: str):
    """装饰器:将解析器类注册到注册表。"""
    def _wrapper(cls):
        if not issubclass(cls, ModelConfigParserBase):
            raise ValueError("Model-config parser must subclass ModelConfigParserBase.")
        if name in _MODEL_CONFIG_PARSER_REGISTRY:
            logger.warning(
                "Model-config parser %r already registered; overwriting with %s",
                name,
                cls,
            )
        _MODEL_CONFIG_PARSER_REGISTRY[name] = cls
        logger.debug("Registered model-config parser %r -> %s", name, cls.__name__)
        return cls
    return _wrapper
​
​
def get_model_config_parser(name: str) -> ModelConfigParserBase:
    """根据名称获取解析器实例。调用者需先处理 'auto'。"""
    if name not in _MODEL_CONFIG_PARSER_REGISTRY:
        raise ValueError(
            f"Unknown model-config parser {name!r}. "
            f"Registered: {sorted(_MODEL_CONFIG_PARSER_REGISTRY)}"
        )
    return _MODEL_CONFIG_PARSER_REGISTRY[name]()
python/sglang/srt/server_args.py core-logic

新增 model_config_parser 字段和 CLI 参数,并改进 Mistral 原生格式检测逻辑 _is_mistral_native_format,是用户接口和兼容性的关键文件。

# 在 ServerArgs dataclass 中新增字段
@dataclasses.dataclass
class ServerArgs:
    # ... 其他字段
    model_config_parser: str = "auto" # 新增,默认自动检测# CLI 参数添加(在 add_cli_args 中)
parser.add_argument(
    "--model-config-parser",
    type=str,
    default="auto",
    help="Model config parser name (auto, hf, mistral, or custom registered name).",
)# _is_mistral_native_format 重写为更精确的检测
# 原方法:仅检查 params.json 存在且 config.json 不存在(误判风险)
# 新方法:以 consolidated*.safetensors 存在且无 model-*.safetensors 为主要信号
# 同时保留名称白名单 mistral-large-3 / mistral-small-4 / leanstral_MISTRAL_NATIVE_PATTERNS = (
    "mistral-large-3",
    "mistral-small-4",
    "leanstral",
)def _is_mistral_native_format(self) -> bool:
    name_matches = any(
        p in str(self.model_path).lower() for p in _MISTRAL_NATIVE_PATTERNS
    )
​
    def _check_format(has_params, has_consolidated, has_hf_weights) -> bool:
        # 名称匹配且 params.json 存在时直接返回 True(强制 Mistral 格式)
        if has_params and name_matches:
            return True
        # 主要信号:存在 consolidated*.safetensors 且没有任何 model-*.safetensors
        return has_consolidated and not has_hf_weights
​
    if os.path.isdir(self.model_path):
        return _check_format(
            has_params=os.path.exists(os.path.join(self.model_path, "params.json")),
            has_consolidated=bool(
                glob.glob(os.path.join(self.model_path, "consolidated*.safetensors"))
            ),
            has_hf_weights=bool(
                glob.glob(os.path.join(self.model_path, "model-*.safetensors"))
            ),
        )
​
    # 远程 Hub 模型类似逻辑(通过 HfApi 获取文件列表)
    try:
        from huggingface_hub import HfApi
        files = {s.rfilename for s in HfApi().model_info(self.model_path).siblings}
        return _check_format(
            has_params="params.json" in files,
            has_consolidated=any(f.startswith("consolidated") and f.endswith(".safetensors") for f in files),
            has_hf_weights=any(f.startswith("model-") and f.endswith(".safetensors") for f in files),
        )
    except Exception:
        return False

评论区精华

Mistral 原生格式检测改进 设计

PR body 详细分析了旧 _is_mistral_native_format 的缺陷:仅依赖 params.json 存在且无 config.json,会错误地匹配某些自定义格式(如 params.json + model-*.safetensors)。新设计以 consolidated*.safetensors 存在且无 model-*.safetensors 为主要信号,并保留名称白名单(mistral-large-3 等),确保向后兼容。

结论:新逻辑已实现,并通过表格验证了所有已知 checkpoint 场景行为不变。 · 已解决

风险与影响

  1. 注册表错误使用:若外部解析器未正确实现基类,可能导致配置加载失败;装饰器已有 issubclass 校验。
  2. Mistral 检测变化:虽经详细分析,但仍可能影响罕见 checkpoint 布局,需关注 CI 测试结果。
  3. GGUF 短路逻辑:GGUF 路径强制使用 HF 解析器,若新增解析器需处理 GGUF 则需额外修改。
  4. 测试覆盖局限:测试仅在 CPU 上运行,未覆盖 GPU 端到端加载路径。

对用户:新增 --model-config-parser 参数,高级用户可注册自定义解析器;默认 'auto' 保持完全向后兼容。对系统:配置加载架构更加清晰,get_config 职责分离,便于未来扩展。对团队:维护成本降低,新增解析器不影响核心代码。

核心路径变更 兼容性风险 测试覆盖局限 配置错误风险

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论