Prhub

#39599 fix(tool-parser): preserve "none"/"nil" strings as valid enum values in minimax_m2

原始 PR 作者 ianliuy 合并时间 2026-05-14 08:35 文件变更 2 提交数 4 评论 1 代码增减 +137 / -6

执行摘要

修复 minimax_m2 工具解析器将 none/nil 错误转换为 None

用户报告(issue #39567)指出,当 enum 中包含 none 作为合法值时(例如 classification 任务的 enum: [none, yes, no]),解析器错误地将 none 转换为 Python None,破坏了后端工作流。

值得精读。展示了工具解析器中类型转换与 schema 感知的结合,体现了保守修复与精确修复的设计权衡。测试代码清晰,可作为类似 bugfix 的参考。

讨论亮点

审阅者 sfeng33 评论:'Thanks for the fix! I added a small change on top that makes the null conversion schema-aware.' 对应提交 c49ff96,将 null 检测从无条件判断改为基于 schema 类型优先级,使修复更精确。

实现拆解

  1. 移除无条件 null 检测:删除 _convert_param_value_with_types 开头的 if value.lower() in ('null', 'none', 'nil'): return None 块,该块不感知 schema 且会吞噬合法字符串。
  2. 加入 schema 感知的 null 转换:在类型优先级列表中添加 null 作为最高优先级。仅当参数 schema 包含 null 类型且值恰好为 null(不区分大小写)时才返回 Python None;否则继续尝试后续类型转换。同时更新了注释。
  3. 添加回归测试:新增 TestNoneStringPreservation 测试类,包含 4 个测试:enum 中 none 保留、纯字符串 none 保留、nullable schema 中 null 仍转换为 Nonenil 保留。所有测试使用与现有测试相同的 fixture 和断言模式。
文件 模块 状态 重要度
vllm/tool_parsers/minimax_m2_tool_parser.py 工具解析器 modified 5.83
tests/tool_parsers/test_minimax_m2_tool_parser.py 工具解析器测试 modified 6.94

关键符号

_convert_param_value_with_types

关键源码片段

vllm/tool_parsers/minimax_m2_tool_parser.py core-logic

核心修复文件,修改了参数值类型转换方法,将 null 检测从无条件提前判断改为 schema 感知的优先级类型转换。

def _convert_param_value_with_types(
    self, value: str, param_types: list[str]
) -> Any:
    '''
    根据可能的类型列表将参数值转换为正确的类型。
    按优先级依次尝试,直到成功。
    现在 null 转换由 schema 控制 (null 类型出现在 param_types 中时才触发)。
    同时修复 #39567: 'none'/'nil' 不再被无条件转换为 None。
    '''
    # 将类型列表标准化为小写
    normalized_types = [t.lower() for t in param_types]
​
    # 类型处理优先级 : null > integer > number > boolean > object > array > string
    type_priority = [
        'null',
        'integer',
        'int',
        'number',
        'float',
        'boolean',
        'bool',
        'object',
        'array',
        'string',
        'str',
        'text',
    ]
​
    for param_type in type_priority:
        if param_type not in normalized_types:
            continue
​
        if param_type == 'null':
            # 只有 schema 中明确包含 null 类型且值恰好为 'null'( 大小写不敏感 ) 时才返回 None
            if value.lower() == 'null':
                return None
            continue
        elif param_type in ['string', 'str', 'text']:
            return value
        elif param_type in ['integer', 'int']:
            try:
                return int(value)
            except (ValueError, TypeError):
                continue
        elif param_type in ['number', 'float']:
            try:
                val = float(value)
                # 保持整数字面量 ( 如 '5' -> 5 而不是 5.0)
                return val if val != int(val) else int(val)
            except (ValueError, TypeError):
                continue
        elif param_type in ['boolean', 'bool']:
            lower_val = value.lower().strip()
            if lower_val in ['true', '1', 'yes', 'on']:
                return True
            elif lower_val in ['false', '0', 'no', 'off']:
                return False
            continue
        elif param_type in ['object', 'array']:
            try:
                return json.loads(value)
            except json.JSONDecodeError:
                continue
​
    # 兜底 : 先尝试 JSON 解析,失败则返回原始字符串
    try:
        return json.loads(value)
    except json.JSONDecodeError:
        return value

评论区精华

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

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

风险与影响

风险较低。改动集中在单个方法的控制流,且测试覆盖了 4 种路径(none in enum, none plain string, null in nullable, nil plain string)。潜在风险:如果其他使用此解析器的场景依赖旧版无条件转换(例如期望 nil 也变为 None),需要评估。但根据 schema 定义,null 的唯一合法表达应为 nullnil 不算 JSON null,因此移除转换符合规范。

影响使用 MinimaxM2ToolParser 的所有用户,特别是依赖 enum 包含 none/nil 的分类/标签任务。修复后,这些字符串值将被正确保留,后端工作流恢复正常。对已有正确的 null 转换无影响(因为 null 仍会被转换)。

enum 值误转 schema 感知 null 类型转换边界

关联 Issue

#39567 [Bug]: minimax_m2_tool_parser infers none-like strings as pythonic None

完整报告

参与讨论