Prhub

#31484 Upgrade llguidance to 1.7.6

原始 PR 作者 merrymercy 合并时间 2026-07-18 07:31 文件变更 10 提交数 1 评论 6 代码增减 +34 / -13

执行摘要

升级 llguidance 依赖至 1.7.6 并适配 API

升级固定的llguidance依赖从0.7.11到1.7.6,并适配llguidance语法后端以使用更新的API。这是为了保持与上游版本的兼容性,并获得新版本的功能与修复。

该 PR 值得精读,尤其是 llguidance_backend.py 中的适配模式:如何应对上游 API 删除单一属性改用集合属性的变化。对于维护依赖升级的开发者有参考价值。

讨论亮点

本PR未产生实质性讨论,仅有自动化CI触发和重跑命令。主要挑战在于适配上游API变化,特别是eos_tokeneos_tokens的变更,已在代码中通过set membership适配。

实现拆解

步骤 1:升级依赖版本约束 - 在所有 pyproject.toml 变体中(python/pyproject.toml、pyproject_cpu.toml、pyproject_npu.toml、pyproject_other.toml、pyproject_xpu.toml 以及 3rdparty/amd/wheel/sglang/pyproject.toml)将 llguidance 版本约束从 >=0.7.11,<0.8.0 更新为 >=1.7.6,<2.0.0

步骤 2:适配 llguidance 后端 API(python/sglang/srt/constrained/llguidance_backend.py) - 新增辅助函数 _normalize_eos_token_ids,用于将 eos_token_ids 参数统一为 int 或 list 类型。GuidanceGrammar 类:初始化时从 self.llguidance_tokenizer.eos_tokens 获取 EOS token 集合,替代已移除的 eos_token 属性。在 accept_token 方法中检查 token in self.eos_tokens 而非 token == self.eos_tokenGuidanceBackend 类:新增 eos_token_ids 参数,并在调用 from_tokenizer 时通过 eos_token 参数传递标准化后的 EOS token 集合。

步骤 3:适配调用方(python/sglang/srt/constrained/base_grammar_backend.py) - 在 create_grammar_backend 函数中,为 GuidanceBackend 构造时传递 n_vocab=vocab_sizeeos_token_ids=eos_token_ids 参数。

步骤 4:更新测试与工具脚本 - test_base_grammar_backend.py:更新测试用例,验证 GuidanceBackend 构造传递了 n_vocabeos_token_idssend_one.py:将 JSON schema 占位符从 $$ANY$$ 替换为 {"type": "object"},因为 llguidance 1.7.6 不再支持 $$ANY$$ 特殊字符串。

文件 模块 状态 重要度
python/sglang/srt/constrained/llguidance_backend.py 约束解码 modified 6.83
python/sglang/srt/constrained/base_grammar_backend.py 约束解码 modified 4.89
test/registered/unit/constrained/test_base_grammar_backend.py 单元测试 modified 4.2
python/sglang/test/send_one.py 测试工具 modified 3.59
python/pyproject.toml 构建配置 modified 2.5
python/pyproject_cpu.toml 构建配置 modified 2.5
python/pyproject_npu.toml 构建配置 modified 2.5
python/pyproject_other.toml 构建配置 modified 2.5
python/pyproject_xpu.toml 构建配置 modified 2.5
3rdparty/amd/wheel/sglang/pyproject.toml 构建配置 modified 2.5

关键符号

_normalize_eos_token_ids GuidanceGrammar.accept_token GuidanceGrammar.__init__ GuidanceBackend.__init__

关键源码片段

python/sglang/srt/constrained/llguidance_backend.py core-logic

核心逻辑,适配 llguidance 1.7.6 API 变更,包含 EOS token 属性替换和新参数传递。

# 辅助函数:统一 EOS token ID 格式,接受单个 int 或可迭代 int
def _normalize_eos_token_ids(
    eos_token_ids: Optional[Union[int, Iterable[int]]],
) -> Optional[Union[int, List[int]]]:
    if eos_token_ids is None or isinstance(eos_token_ids, int):
        return eos_token_ids
    return list(eos_token_ids)class GuidanceGrammar(BaseGrammarObject):
    def __init__(self, llguidance_tokenizer: LLTokenizer, serialized_grammar: str):
        super().__init__()
        self.llguidance_tokenizer = llguidance_tokenizer
        self.serialized_grammar = serialized_grammar
        self.ll_matcher = LLMatcher(
            self.llguidance_tokenizer,
            self.serialized_grammar,
            log_level=int(os.environ.get("LLGUIDANCE_LOG_LEVEL", "1")),
        )
        self._check_err()
        # 使用新 API 的 eos_tokens 属性(返回 set)
        self.eos_tokens = set(self.llguidance_tokenizer.eos_tokens)
​
    def accept_token(self, token: int):
        if self.finished:
            return
        # 检查 token 是否在 EOS token 集合中
        if self.ll_matcher.is_stopped() and token in self.eos_tokens:
            self.finished = True
            return
        self.ll_matcher.consume_token(token)
        self._check_err()class GuidanceBackend(BaseGrammarBackend):
    def __init__(
        self,
        tokenizer,
        any_whitespace: bool = True,
        whitespace_pattern: Optional[str] = None,
        n_vocab: Optional[int] = None,
        eos_token_ids: Optional[Union[int, Iterable[int]]] = None,
    ):
        super().__init__()
        self.tokenizer = tokenizer
        self.any_whitespace = any_whitespace
        self.whitespace_pattern = whitespace_pattern
        # 将 eos_token_ids 标准化后传给 from_tokenizer
        self.llguidance_tokenizer = from_tokenizer(
            self.tokenizer,
            n_vocab,
            eos_token=_normalize_eos_token_ids(eos_token_ids),
        )

评论区精华

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

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

风险与影响

  1. 兼容性风险:llguidance 从 0.7.11 升级到 1.7.6 是跨越主版本升级,可能引入行为变化。虽已适配 eos_tokens 属性,但仍可能存在其他未暴露的 API 变更。
  2. 回归风险:constrained decoding 功能可能因 API 误用而失效,尤其是多 EOS token 的场景。已有单元测试覆盖基本逻辑,但未覆盖所有边界情况。
  3. 依赖冲突:新版本可能与项目中的其他依赖存在版本冲突,但已通过版本约束 <2.0.0 缓解。

对用户而言,使用 llguidance 后端的约束解码功能将正常工作,且可能获得上游的 bug 修复和性能改进。安装时需要 llguidance >=1.7.6,否则会因版本约束报错。对开发者,该 PR 提供了一个清晰的依赖升级适配模式,可作为后续库升级的参考。对系统无性能或安全风险。

依赖大版本升级 约束解码核心路径

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论