修复vLLM中的工具调用准确率

Hacker News Top 工具

摘要

Ubicloud介绍了vLLM新增的受限解码支持(vLLM 0.31中的服务端标志)如何修复工具调用schema准确率问题,将较新的Kimi和DeepSeek模型的合规率从vLLM 0.28时的92%提升至100%。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/10/27 02:08

# 修复 vLLM 中的工具调用准确性 来源:https://www.ubicloud.com/blog/fixing-tool-call-accuracy-in-vllm 全部博客文章 2026年10月20日 · 8分钟阅读 Burak Yucesoy、Jesse Donkervliet 和 Junhao Li 资深软件工程师 > 当我使用开放权重模型时,我看到的结果与质量基准所显示的相差甚远。 > > ——如今与AI模型打交道的软件开发者 工具调用准确性是服务开放权重模型的重要环节。当工具调用不准确时,模型会在无意义的上下文上不断叠加。这会导致低质量的结果,尤其是在多轮会话常见的智能体(agentic)工作负载中。 遗憾的是,许多提供商和广泛使用的推理引擎并未完全通过工具调用准确性测试(https://github.com/MoonshotAI/K2-Vendor-Verifier)。例如,当我们使用 vLLM 0.28 版本服务 Kimi K2.6 时,只有 92% 的情况下能得到预期的工具调用 schema。换句话说,每 25 次工具调用尝试中就有 2 次失败。 幸运的是,vLLM 最近添加了对**受限解码(constrained decoding)**的支持——一种保证 schema 一致性的技术。该功能随后在 vLLM 0.31 中作为服务端标志发布。启用它后,对于较新的 Kimi 和 DeepSeek 模型,你可以达到 100% 的 schema 准确率。 在本文中,我们首先介绍工具调用 schema 准确率,以及它在服务智能体工作负载中的重要性。然后我们讨论受限解码,以及它如何解决 schema 准确率问题。 ### 工具调用 Schema 你可以通过两步让 LLM 调用外部工具:(1)告知 AI 模型存在可外部调用的工具;(2)指导模型如何输出结构化的工具调用。例如,当 OpenCode 连接 Kimi 时,OpenCode 会向 Kimi 发送一个 JSON 数组来描述可用的工具。列表中的一个工具是 `webfetch`,用于获取网页内容: ```json [{ "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" ] } } }, ...] ``` 推理引擎随后会用 LLM 专属的 token 将此 JSON 描述包装起来,再传入 LLM,以匹配 LLM 训练时识别工具声明的方式。在服务 Kimi 时,看起来大致如下: ``` <|im_system|>tool_declare<|im_middle|>[{"type":"function","function":{...}, ...] ``` 描述工具(即上面 JSON 中的*function*)的 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 对象: ```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 是允许的由所提供的工具 schema 决定。vLLM 使用 XGrammar 库(https://xgrammar.mlc.ai/docs/structural_tag/structural_tag_api.html)中的*结构化标签(structural tags)*来实现这一点。下面的代码片段展示了 XGrammar 在 Kimi K2.6 中实现受限解码的摘录。它定义了工具调用的有效结构,包括调用从哪里开始、索引出现在哪里、参数从哪里开始,以及必须在哪里生成符合 schema 的 JSON。 ```python # 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, ) ``` 你可以在[这里](https://github.com/mlc-ai/xgrammar/blob/d02ad2b155a5f0c3eaa711950d154218d982ae7e/python/xgrammar/builtin_structural_tag.py#L757)找到完整实现。 有了这个定义,生成必须遵循一条有效路径: 开始工具调用 → 工具名称 → 工具调用索引 → 参数开始 → 符合 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). [链接](https://proceedings.mlsys.org/paper_files/paper/2025/hash/5c20ca4b0b20b0bd2f1d839dc605e70f-Abstract-Conference.html) 这将 schema 准确率从尽力而为的方式转变为运行时保证。模型仍然决定生成哪个 token,但现在 token 是从受限且语法正确的集合中选择的。 值得注意的是,这种运行时强制执行带来的性能开销可以忽略不计。通过为每个阶段预计算 token 掩码,并在生成过程中高效地在 GPU 上应用,XGrammar 在不牺牲显著性能的前提下保证了正确的工具调用。 ### 受限解码行为的差异 Moonshot AI 建议开启受限解码(https://github.com/MoonshotAI/K2-Vendor-Verifier#suggestions-to-vendors),其自有 API 也是如此表现的。因此我们最初在 vLLM 的分支中添加了受限解码。在 vLLM 于 v0.25 中添加了该功能后,我们为 Kimi 和 DeepSeek 切换到了使用上游的该功能。不幸的是,不久之后我们发现工具调用准确性分数又跌回了 91%! 在分析问题后,我们确认 vLLM 对受限解码的实现仍然是正确的。相反,我们发现 vLLM 修改了对于未显式开启受限解码的请求的默认行为。这主要是因为 vLLM 被设计为支持广泛的模型。支持受限解码是逐模型的任务,问题可以分为三类: - **通用模型问题**:对于某些模型,其无约束输出与工具 schema 或模型的工具调用格式相差甚远。这迫使模型选择它原本不会选择的 token,导致偏离轨道 [1](https://papers.nips.cc/paper_files/paper/2024/hash/2bdc2267c3d7d01523e2e17ac0a754f3-Abstract-Conference.html)。例如,gpt-oss-20b、Qwen 3.6 和 GLM 5.1 的用户在默认启用该功能后报告了问题。 - **语法转换 Bug**:vLLM 在将模型的工具 schema 或工具调用格式转换为模型特定语法时可能存在 Bug。这可能导致的问题包括无效的工具调用、请求失败、静默跳过受限解码,以及更低的工具调用准确性 [1](https://github.com/vllm-project/vllm/pull/45600)、[2](https://github.com/vllm-project/vllm/issues/58930)。 - **功能交互 Bug**:受限解码与其他服务引擎功能之间的交互存在 Bug。例如,受限解码与投机解码(speculative decoding)之间的交互 Bug 可能导致投机 token 被语法错误地拒绝,从而导致请求失败 [1](https://github.com/vllm-project/vllm/issues/44006)、[2](https://github.com/vllm-project/vllm/issues/55152)。 由于这些问题,vLLM 维护者[报告称](https://github.com/vllm-project/vllm/pull/45600)在开启受限解码后多个模型出现了问题。这使得默认关闭受限解码成为像 vLLM 这样的模型无关服务引擎更安全的选择。后来,vLLM [添加了](https://github.com/vllm-project/vllm/pull/56268)`--tool-strict-level` 标志,让用户可以为其部署启用工具调用严格模式。 然而,Ubicloud 的关注点与 vLLM 不同。我们专注于以用户期望的一方提供商级别的质量来服务 Kimi 和 DeepSeek 模型。为此,我们启用了受限解码并重新运行了 K2VV ToolCall 基准测试。在验证了所有服务模型版本均达到 100% 的工具调用 schema 准确率后,我们将该更改部署到了生产环境。随后我们撰写了这篇博客文章来分享我们的经验。 ### 结论 使用 LLM 时,你观察到的质量并不仅仅取决于模型本身。推理引擎也起着重要作用。更换推理引擎及其设置,就会改变模型的输出质量。 在服务 Kimi K2.6 和 DeepSeek V4 Flash 时,我们观察到由于工具调用 schema 不准确导致的明显质量下降。我们通过首先维护自己的 vLLM 分支、然后启用 vLLM 中新的受限解码功能解决了这个问题。这帮助我们在 K2VV ToolCall 基准测试中将工具调用准确性从 92% 提升到了 100%。 在本文中,我们分享了我们在工具调用和受限解码方面的经验。如果这对你有价值,或者你想分享服务模型的实战故事,请通过我们的[支持邮箱](https://www.ubicloud.com/docs/about/support)联系我们。

相似文章

vLLM v0.28.0

Hacker News Top

vLLM v0.28.0 是用于快速高效 LLM 推理和服务的开源库的更新版本,具有 PagedAttention 等增强功能和广泛的硬件支持。