Prhub

#31211 Fix processor config loading for object-storage model paths

原始 PR 作者 sshleifer 合并时间 2026-07-15 15:21 文件变更 2 提交数 3 评论 3 代码增减 +43 / -1

执行摘要

修复 object-storage 模型路径的 processor 加载

PR body 指出,get_processor() 已对 tokenizer_name 调用 resolve_runai_obj_uri(),但当 model_name 单独指定时,AutoConfig.from_pretrained(model_name) 会使用未解析的 URI,绕过为 RunAI 后端(S3/GCS/Azure)准备好的本地缓存,导致 processor 初始化失败。

值得快速合入,变更微小且逻辑清晰。推荐了解 object-storage 缓存机制的读者留意 resolve_runai_obj_uri 的实现;其他读者可直接合并。

讨论亮点

无 review 评论,仅 alexnails 批准(LGTM)。社区未报告争议点。

实现拆解

  1. 源码变更:在 python/sglang/srt/utils/hf_transformers/processor.pyget_processor() 函数中,第 156-157 行新增对 model_name 的 URI 解析:if model_name is not None: model_name = resolve_runai_obj_uri(model_name)。这样后续 AutoConfig.from_pretrained(model_name) 使用本地缓存路径而非原始远程 URI。
  2. 测试新增:在 test/registered/unit/utils/test_hf_transformers.py 中新增 TestGetProcessor 测试类和 test_resolves_model_name_before_loading_config 方法,模拟 tokenizer 为本地路径、model_name 为 s3://bucket/model 的场景,通过 mock 验证 resolve_runai_obj_uri 被正确调用,并且 AutoConfig.from_pretrained 接收的是解析后的本地路径。
  3. 配套调整:测试文件中新增导入 sglang.srt.utils.hf_transformers.processor as processor_utilsMagicMock,利用 patch.multiple 完成 mock。
文件 模块 状态 重要度
python/sglang/srt/utils/hf_transformers/processor.py 工具函数 modified 6.04
test/registered/unit/utils/test_hf_transformers.py 测试 modified 6.59

关键符号

get_processor resolve_runai_obj_uri test_resolves_model_name_before_loading_config

关键源码片段

python/sglang/srt/utils/hf_transformers/processor.py core-logic

核心修复:在 get_processor() 中对 model_name 调用 resolve_runai_obj_uri,确保 AutoConfig 使用本地缓存路径。仅 +2 行。

# python/sglang/srt/utils/hf_transformers/processor.py (lines 138-178)def get_processor(
    tokenizer_name: str,
    *args,
    tokenizer_mode: str = "auto",
    trust_remote_code: bool = False,
    tokenizer_revision: Optional[str] = None,
    use_fast: Optional[bool] = True,
    tokenizer_backend: str = "huggingface",
    model_name: Optional[str] = None,
    **kwargs,
):
    if tokenizer_backend == "fastokens":
        from .tokenizer import _ensure_fastokens_patched
        _ensure_fastokens_patched()
​
    revision = kwargs.pop("revision", tokenizer_revision)
    # tokenizer 路径已在处理
    tokenizer_name = resolve_runai_obj_uri(tokenizer_name)
​
    # 新增:对 model_name 做同样处理,确保后续 AutoConfig 使用本地缓存路径
    if model_name is not None:
        model_name = resolve_runai_obj_uri(model_name)
​
    if is_mistral_model(tokenizer_name):
        config = load_mistral_config(...)
    elif model_name is not None:
        # 这里现在接收本地路径,而非原始 S3/GCS/Azure URI
        config = AutoConfig.from_pretrained(
            model_name,
            trust_remote_code=trust_remote_code,
            revision=revision,
            **kwargs,
        )
    else:
        config = AutoConfig.from_pretrained(
            tokenizer_name,
            trust_remote_code=trust_remote_code,
            revision=revision,
            **kwargs,
        )
    # 后续处理不变 ...
test/registered/unit/utils/test_hf_transformers.py test-coverage

新增 CPU 回归测试,模拟 local tokenizer + remote model_name 场景,验证修复正确性。

# test/registered/unit/utils/test_hf_transformers.py ( 新增 get_processor 小节 )import sglang.srt.utils.hf_transformers.processor as processor_utils
from unittest.mock import MagicMock, patchclass TestGetProcessor(unittest.TestCase):
    def test_resolves_model_name_before_loading_config(self):
        # 模拟:tokenizer 本地,model_name 为远程 S3 路径
        remote_model = "s3://bucket/model"
        local_model = "/cache/model"
        config = SimpleNamespace(model_type="clip", auto_map={})
        loaded_processor = MagicMock()
        loaded_processor.tokenizer.chat_template = "template"
        auto_config = MagicMock()
        auto_config.from_pretrained.return_value = config
        auto_processor = MagicMock()
        auto_processor.from_pretrained.return_value = loaded_processor
​
        def resolve_uri(path):
            return local_model if path == remote_model else path
​
        with patch.multiple(
            processor_utils,
            resolve_runai_obj_uri=MagicMock(side_effect=resolve_uri),
            AutoConfig=auto_config,
            AutoProcessor=auto_processor,
        ):
            processor = processor_utils.get_processor(
                "local-tokenizer",
                model_name=remote_model,
            )
​
        self.assertIs(processor, loaded_processor)
        # 验证 AutoConfig 使用的是解析后的本地路径
        auto_config.from_pretrained.assert_called_once_with(
            local_model,
            trust_remote_code=False,
            revision=None,
        )

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险极低。源码仅增加 2 行,且 URI 解析是幂等操作(已解析的路径再次调用 resolve_runai_obj_uri 会直接返回原值)。测试覆盖了关键分支。唯一需要注意:若 model_name 本是本地路径且包含特殊字符,resolve_runai_obj_uri 不应改变其值,从已有实现看该函数对非远程路径直接返回,安全。

直接影响使用 object-storage(S3/GCS/Azure)模型路径的用户。修复前 processor 初始化(用于多模态模型)可能失败,修复后可正常加载。对其他用户无影响。受影响的模型类型包括 CLIP、DeepSeek-OCR、Qwen2-VL 等使用 get_processor 的多模态模型。

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论