Prhub

#34781 fix(muse-glimmer): parse required/named tool calls natively

原始 PR 作者 sid-rp 合并时间 2026-08-15 04:43 文件变更 1 提交数 2 评论 3 代码增减 +5 / -0

执行摘要

MuseGlimmer required/named 工具调用改走原生 ATEM 解析

PR body 明确指出:Muse Glimmer 只产出 ATEM()工具调用,当 tool_choice="required" 或指定命名工具时,默认路径路由到 JsonArrayParser 并用 JSON-array grammar 约束生成;模型不产出该 JSON 格式,导致调用泄漏为 content、finish_reason="stop" 且零 tool_calls。该问题在多轮对话(历史已含 assistant tool_calls 轮次)下可稳定复现,影响 required/named 工具调用的核心功能。

值得快速阅读:PR 体量小但清晰解释了 SGLang 工具调用解析器的路由机制(JsonArrayParser 与 detector 原生解析的切换条件)。重点关注 parses_required_natively 这一行为开关的设计:它以方法形式暴露「模型是否原生产出工具调用格式」的语义,比在路由层硬编码模型名更易扩展。建议后续补一个多轮 required/named 的回归测试,并在代码注释或文档中说明该开关与 JSON-array grammar 路径的关系。

讨论亮点

review 过程简洁:JustinTong0323 审阅后直接批准("LGTM"),未提出代码层面的修改意见。第二个 commit 由 JustinTong0323 将 parses_required_natively 的多行 docstring 修剪为更精炼的版本,说明评审关注注释简洁性。合并前维护者通过 /tag-and-rerun-ci 与 /rerun-failed-ci 重跑 CI,其中 base 常规运行失败、extra 运行通过。

实现拆解

  1. 问题定位:在 python/sglang/srt/function_call/muse_glimmer_detector.py 中确认 MuseGlimmerDetector 已具备原生 ATEM 解析能力(tool_choice=auto 路径可用),但 required/named 路径被框架路由到 JsonArrayParser,解析器与模型输出格式不匹配。
  2. 核心改动:在 MuseGlimmerDetector 中新增方法 parses_required_natively() 并返回 True。该方法是一个行为开关,框架据此将 required/named tool_choice 从 JSON-array grammar 路径切换到 detector 的原生 ATEM 解析路径,与 auto 行为对齐。
  3. 配套验证:PR body 给出 Muse-Glimmer-30B(BF16 单卡)在 main 上的前后对比,required/named 多轮对话场景从「0 tool calls、ATEM 泄漏为 content」修复为正常返回工具调用;现有 test/registered/unit/function_call/ 测试套件通过;未新增回归测试,无配置、文档或部署配套改动。
文件 模块 状态 重要度
python/sglang/srt/function_call/muse_glimmer_detector.py 函数调用 modified 5.36

关键符号

parses_required_natively

关键源码片段

python/sglang/srt/function_call/muse_glimmer_detector.py core-logic

核心修复文件:为 MuseGlimmerDetector 新增 parses_required_natively() 并返回 True,使 required/named tool_choice 跳过 JsonArrayParser 的 JSON-array grammar,改走原生 ATEM 解析路径,修复多轮对话下工具调用丢失问题。

# python/sglang/srt/function_call/muse_glimmer_detector.py
# 关键约定:Muse Glimmer 只通过 ATEM(<atem:function_calls>)区块表达工具调用,
# 不产出 JSON 数组格式;以下方法共同定义 parser 的行为边界。def supports_structural_tag(self) -> bool:
    # ATEM 块不使用结构化 tag 注入,因此固定返回 False
    return Falsedef parses_required_natively(self) -> bool:
    """声明 required/named tool_choice 可由本 detector 原生解析。    默认路径在 required 或命名工具时会通过 JsonArrayParser 强制
    JSON-array grammar,但模型实际输出原生 ATEM 块,JSON 路径无法
    解析,导致调用泄漏为 content 且 tool_calls 为空。返回 True 后,
    required/named 与 auto 共用同一原生 ATEM 解析路径。
    """
    return Truedef structure_info(self) -> _GetInfoFunc:
    # 为解码器提供 ATEM 结构的拼接信息,begin/end 分别对应 open/close 标签
    return lambda name: StructureInfo(
        begin=f'{FUNCTION_CALLS_OPEN}\n{INVOKE_OPEN} name="{name}">',
        end=f"{INVOKE_CLOSE}\n{FUNCTION_CALLS_CLOSE}",
        trigger=FUNCTION_CALLS_OPEN,
    )

评论区精华

整体评审结论 other

Reviewer JustinTong0323 审阅后直接批准,回复 "LGTM",未提出代码层面的修改意见。

结论:APPROVED,改动可直接合并。 · 已解决

docstring 精简 style

第二个 commit 由 JustinTong0323 将 parses_required_natively 的 docstring 从较长的多行说明修剪为更精炼的版本,体现评审对注释简洁性的要求。

结论:已通过后续 commit 修正。 · 已解决

CI 重跑与结果不一致 other

维护者通过 /tag-and-rerun-ci 与 /rerun-failed-ci 触发常规及额外 CI 重跑;最终 base 常规运行失败、extra 运行通过。

结论:extra CI 通过,base 失败原因未在讨论中明确澄清。 · 已解决

风险与影响

  1. 行为开关风险:parses_required_natively() 返回 True 后,Muse Glimmer 的 required/named 路径整体切换解析器。若未来模型更新开始产出 JSON-array 格式,该开关将导致此类输出无法被解析;目前模型仅产出 ATEM,风险低,但缺少对开关语义的显式约束。
  2. 测试覆盖缺口:PR 未新增回归测试,多轮 required/named 场景的回归保护完全依赖现有 function_call 套件,后续重构 JsonArrayParser 路由时可能重新引入该 bug 而无法被及时发现。
  3. CI 不一致:base 常规 CI 运行失败而 extra 运行通过,虽未发现与改动相关的失败证据,但合并前未明确澄清失败原因,存在轻微不确定性。

影响范围集中在 Muse-Glimmer 模型的工具调用解析:使用 tool_choice=required 或命名工具的用户,尤其是多轮对话场景,工具调用不再丢失,修复前功能完全不可用、修复后与 auto 行为一致。系统层面无推理性能影响,仅改变已有输出的解析路径选择;单文件 5 行改动,对其他模型和解析器无影响。团队层面评审成本低,但建议后续补齐回归测试。

缺少新增回归测试 required/named 解析行为整体切换 CI base 运行失败未明确归因

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论