跳到正文
Hacker News· coffeemug·· 4 小时前AI 评分47

vLLM 如何修复工具调用准确率问题

Fixing Tool-Call Accuracy in vLLM

AI 导读

vLLM 0.31 新增服务端 flag 支持约束解码,可将 Kimi、DeepSeek 新模型的工具调用 schema 准确率提升至 100%。此前用 vLLM 0.28 部署 Kimi K2.6 时,仅 92% 的工具调用符合预期 schema,即每 25 次调用有 2 次失败。schema 不准确会污染上下文窗口并增加重试成本,对多轮智能体负载影响尤甚。

正文 · AI 翻译

所有博客文章

2026年10月20日 · 8 分钟阅读

Burak Yucesoy

Jesse Donkervliet 和 Junhao Li

高级软件工程师

当我使用开放权重模型时,看到的结果与质量基准所显示的水平相差甚远。

软件开发人员,如今与 AI 模型打交道

工具调用准确率是服务开放权重模型的重要一环。当你的工具调用不准确时,模型会基于无意义的上下文不断累积。这会导致结果质量低下,对于多轮会话常见的智能体工作负载尤其如此。

遗憾的是,许多提供商和广泛使用的推理引擎并未完全通过工具调用准确率测试。例如,当我们用 vLLM 0.28 版本服务 Kimi K2.6 时,只有 92% 的情况下得到了预期的工具调用 schema。换句话说,每 25 次尝试的工具调用中就有 2 次失败。

幸运的是,vLLM 最近新增了对约束解码的支持,这是一种保证 schema 遵循性的技术。该功能随后在 vLLM 0.31 中作为服务端标志发布。启用它后,配合较新的 Kimi 和 DeepSeek 模型,你可以达到 100% 的 schema 准确率。

在这篇博客文章中,我们首先介绍工具调用 schema 准确率,以及它在服务智能体工作负载时为何重要。然后我们讨论约束解码,以及它如何解决 schema 准确率问题。

工具调用 Schema

你可以通过两个步骤让 LLM 调用外部工具:(1) 告知 AI 模型存在可用的外部工具调用,(2) 向模型提供如何输出结构化工具调用的指令。例如,当把 OpenCode 连接到 Kimi 时,OpenCode 会向 Kimi 发送一个描述可用工具的 JSON 数组。该列表中的一个工具是 webfetch,用于获取网页内容:

[{
  "type": "function",
  "function": {
    "name": "webfetch",
    "description": "- Fetches content from a specified URL\n- Takes a URL and optional format as input\n- Fetches the URL content, converts to requested format (markdown by default)\n- Returns the content in the specified format\n- Use this tool when you need to retrieve and analyze web content\n\nUsage notes:\n  [content redacted for brevity]\n",
    "parameters": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "type": "object",
      "properties": {
        "url": {
          "type": "string",
          "description": "The URL to fetch content from"
        },
        "format": {
          "type": "string",
          "enum": [
            "text",
            "markdown",
            "html"
          ],
          "description": "The format to return the content in (text, markdown, or html). Defaults to markdown.",
          "default": "markdown"
        },
        "timeout": {
          "type": "number",
          "description": "Optional timeout in seconds (max 120)"
        }
      },
      "required": [
        "url"
      ]
    }
  }
}, ...]

随后,推理引擎会将这个 JSON 描述包装在 LLM 专用的 token 中,再传入 LLM,以匹配 LLM 训练时识别工具声明的方式。在服务 Kimi 时,这看起来大致如下:

<|im_system|>tool_declare<|im_middle|>[{"type":"function","function":{...}, ...]<|im_end|>

描述工具的 JSON 对象(在上面的 JSON 中称为函数)包含工具的参数、参数类型、哪些参数是必需的等。这被称为工具的schema。为了让智能体框架(例如 OpenCode)成功执行 LLM 生成的工具调用,该调用必须遵循其 schema 中指定的规则。

然后,当用户通过其智能体框架请求获取网页时,LLM 可能会输出以下 token:

I'll fetch that page. <|tool_calls_section_begin|><|tool_call_begin|>functions.webfetch:0<|tool_call_argument_begin|>{"url": "https://ubicloud.com", "format": "markdown"}<|tool_call_end|><|tool_calls_section_end|>

这些 token 由推理服务器的解析器解析,提取出 LLM 专用的 token,并将该调用转换为如下 JSON 对象:

{
  "role": "assistant",
  "content": "I'll fetch that page.",
  "tool_calls": [
    {
      "id": "functions.webfetch:0",
      "type": "function",
      "function": {
        "name": "webfetch",
        "arguments": "{\"url\": \"https://example.com\", \"format\": \"markdown\"}"
      }
    }
  ]
}

随后,它会被发送回你的框架(在我们的示例中是 OpenCode),由框架运行其 webfetch 工具,并将输出发送回模型。

Schema 准确率的重要性

工具调用要成功,调用必须遵循工具的 schema。

工具调用的简单做法是让模型自由生成工具调用,并相信模型的训练足以生成正确的调用。这类似于我们信任模型生成语法正确的文本。

这种简单做法在大多数情况下都有效,因为现代模型擅长遵循结构化模式。但“大多数情况下”成功意味着仍有许多工具调用可能失败,从而导致错误消息污染上下文窗口、模型性能下降,以及因智能体不得不重试一次或多次调用而增加成本。

为了避免在使用 Kimi 时遇到这类体验,Moonshot AI 发布了 K2VV ToolCall 基准测试。该基准让服务提供商能够验证其提供的 Kimi 服务质量与原始版本一致,包括其仅生成有效工具调用的默认行为。

K2VV ToolCall 的工作负载由 2000 个请求组成,这些请求用于评估 LLM 何时生成工具调用,以及生成的工具调用在语法上是否正确(即是否符合所提供的 schema)。该基准通过量化两个指标来分析模型质量:触发相似度和 schema 准确率。触发相似度考察服务决定触发工具调用的时机,以及其决策与 Moonshot AI 自身服务的相似程度。Schema 准确率量化的是符合工具 schema、因而能够成功调用的工具调用所占比例。例如,当工具调用准确率为 50% 时,模型生成的工具调用中有一半是格式错误的。

Schema 准确率通常因语言模型的概率特性而偏低。模型基于似然生成 token,它并不是在运行编译器或类型检查器。即使提示词清晰明确,它仍可能生成格式错误的工具调用。其原因可能包括模型训练数据与当前推理框架之间的不匹配。模型在许多工具调用数据集上训练,每个数据集都有自己的工具、schema 和约定。因此,模型可能生成它在训练期间见过的工具名或字段名,即使该名称在当前生产环境中并不存在。例如,当可用工具是 web_search 时,它可能生成 search_web;或者当当前 schema 期望 location 时,它却使用 city_name。

约束解码

LLM 会计算每个 token 作为序列中下一个 token 的概率,然后通过加权采样选择下一个 token。约束解码通过阻止模型采样那些会导致工具调用在语法上无效的 token,来避免格式错误的工具调用。使用约束解码时,推理引擎不会让模型自由采样 token 并在事后验证结果,而是逐步引导生成过程。每一步只允许有效的 token。

哪些 token 被允许由所提供的工具 schema 决定。vLLM 使用 XGrammar 库中的结构标签来实现这一点。下面的代码片段展示了 XGrammar 在 Kimi K2.6 中实现约束解码的部分内容。它定义了工具调用的有效结构,包括调用从何处开始、索引出现在何处、参数从何处开始,以及必须在何处生成受 schema 约束的 JSON。

# Kimi K2.6 tool call syntax:
# <|tool_call_begin|>{function.name}:{index}
# <|tool_call_argument_begin|>{arguments}
# <|tool_call_end|>
TagFormat(
    begin=f"{TOOL_CALL_BEGIN_PREFIX}{name}{TOOL_CALL_SUFFIX}",
    content=SequenceFormat(
        elements=[
            RegexFormat(pattern=r"\d+"),
            ConstStringFormat(value=TOOL_CALL_ARGUMENT_BEGIN),
            JSONSchemaFormat(
                json_schema=parameters,
                any_order=any_order,
                max_whitespace_cnt=max_whitespace_cnt,
            ),
        ]
    ),
    end=TOOL_CALL_END,
)

你可以在此处找到完整实现。

根据这一定义,生成必须遵循有效路径:

开始工具调用 → 工具名 → 工具调用索引 → 开始参数 → 受 schema 约束的 JSON → 结束工具调用

无效路径在生成过程中会被阻止。例如,当生成进入工具调用索引阶段时,引擎会将采样限制为整数 token,并屏蔽其他所有内容。下图转载自 XGrammar 的文章,很好地展示了无效 token 是如何被屏蔽的。

来源:Dong, Yixin, et al. "XGrammar: Flexible and efficient structured generation engine for large language models." Proceedings of Machine Learning and Systems 7 (2025). [链接]

这将 schema 准确率从尽力而为的方式转变为运行时保证。模型仍然决定生成哪个 token,但现在该 token 是从一个受限且语法正确的集合中选择的。

值得注意的是,这种运行时强制执行带来的性能开销可以忽略不计。通过为每个阶段预先计算 token 掩码,并在生成过程中于 GPU 上高效应用这些掩码,XGrammar 在保证工具调用正确的同时,不会牺牲显著的性能。

约束解码行为的差异

Moonshot AI 建议开启约束解码,其自有 API 也是如此。因此我们最初在 vLLM 的分支中加入了约束解码。在 vLLM 于 v0.25 加入该功能后,我们改为对 Kimi 和 DeepSeek 使用上游的这一功能。不幸的是,没过多久我们就发现工具调用准确率分数回落到了 91%!

在分析问题后,我们确认 vLLM 的约束解码实现仍然是正确的。相反,我们发现 vLLM 改变了对于未显式开启约束解码的请求的默认行为。这主要是因为 vLLM 旨在支持广泛的模型。支持约束解码是逐模型的任务,而问题分为三类:

  • 通用模型问题:对于某些模型,其无约束输出与工具的 schema 或模型的工具调用格式存在显著偏差。这会迫使模型选择原本不会选择的 token,从而使其偏离正轨 [1]。例如,gpt-oss-20b、Qwen 3.6 和 GLM 5.1 的用户报告称,在默认启用该功能后出现了问题。
  • 语法转换缺陷:vLLM 在将模型的工具 schema 或工具调用格式转换为模型特定语法时可能存在缺陷。这可能导致工具调用无效、请求失败、静默丢弃约束解码以及工具调用准确率下降等问题 [1, 2]。
  • 功能交互缺陷:约束解码与其他服务引擎功能之间的交互存在缺陷。例如,约束解码与推测解码之间的交互缺陷可能导致推测 token 被语法错误地拒绝,从而导致请求失败 [1, 2]。

由于这些问题,vLLM 维护者报告称在启用约束解码后,多个模型出现了问题。这使得对于像 vLLM 这样与模型无关的服务引擎来说,默认禁用约束解码成为更安全的选择。后来,vLLM 添加了 --tool-strict-level 标志,以便用户为其部署启用工具调用严格性。

然而,Ubicloud 的关注点与 vLLM 不同。我们专注于以用户期望从第一方提供商处获得的质量来服务 Kimi 和 DeepSeek 模型。为此,我们启用了约束解码并重新运行了 K2VV ToolCall 基准测试。在验证了所有所服务模型版本的 100% 工具调用 schema 准确率后,我们将该更改部署到了生产环境。随后我们撰写了这篇博客文章来分享我们的经验。

结论

使用 LLM 时,你观察到的质量并非仅取决于模型本身。推理引擎也扮演着重要角色。改变推理引擎及其设置,就会改变模型的输出质量。

在服务 Kimi K2.6 和 DeepSeek V4 Flash 时,我们观察到由于工具调用 schema 不准确而导致的明显质量下降。我们通过先维护自己的 vLLM fork,然后启用 vLLM 中新的约束解码功能解决了这个问题。这帮助我们将 K2VV ToolCall 基准测试中的工具调用准确率从 92% 提升到了 100%。

在这篇博客文章中,我们分享了在工具调用和约束解码方面的经验。如果这很有趣,或者你想分享关于模型服务的实战故事,请通过我们的支持邮箱联系我们。

来源:Hacker News · ubicloud.com