vLLM 如何通过约束解码修复 Kimi K2.6 与 DeepSeek V4 Flash 的工具调用准确率问题
Fixing Tool-Call Accuracy in vLLM
Ubicloud 在 vLLM 中启用约束解码后,Kimi K2.6 与 DeepSeek V4 Flash 的工具调用 schema 准确率从 92% 提升至 100%。
文章拆解了 vLLM 约束解码的接入方式与多模型兼容风险,并给出工具调用 schema 准确率从 92% 提升至 100% 的实测结果。
所有博客文章
October 20, 2026 · 阅读时长 8 min

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 之前,先用特定于 LLM 的词元对其进行包装,以匹配 LLM 在训练中识别工具声明的方式。服务 Kimi 时,大致如下:
<|im_system|>tool_declare<|im_middle|>[{"type":"function","function":{...}, ...]<|im_end|>描述工具的 JSON 对象(或上例 JSON 中的 function)包含工具的参数、参数类型、哪些参数为必填项等。这称为工具的 schema。智能体框架(例如 OpenCode)要成功执行 LLM 生成的工具调用,该调用必须遵循其 schema 中规定的规则。
随后,当用户要求通过其智能体框架获取某个网页时,LLM 可能会输出以下词元:
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|>推理服务器的解析器会解析这些词元,提取出特定于 LLM 的词元,并将调用转换为如下 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 等。“XGrammar:面向大型语言模型的灵活高效结构化生成引擎。”《机器学习与系统论文集》7 (2025)。[链接]
这将模式准确性从尽力而为的做法转变为运行时保障。模型仍然决定要生成哪个词元,但现在该词元会从一个受限且符合语法的集合中选择。
值得注意的是,这种运行时强制机制带来的性能开销微乎其微。通过为每个阶段预先计算词元掩码,并在生成期间高效地将其应用于 GPU,XGrammar 可保证正确的工具调用,而不会以显著性能为代价。
约束解码行为的差异
Moonshot AI 建议开启约束解码,其自有 API 的行为也是如此。因此,我们最初在 vLLM 的分支中添加了约束解码。vLLM 在 v0.25 中加入此功能后,我们便转而使用上游为 Kimi 和 DeepSeek 提供的这项功能。不幸的是,没过多久,我们发现工具调用准确率得分又降回了 91%!
分析问题后,我们确认 vLLM 的约束解码实现仍然是正确的。相反,我们发现 vLLM 改变了未明确开启约束解码的请求的默认行为。这主要是因为 vLLM 的设计目标是支持种类广泛的模型。支持约束解码需要针对每种模型分别处理,相关问题可分为三类:
- 一般模型问题:对于某些模型,其无约束输出会显著偏离工具的模式或模型的工具调用格式。这会迫使模型选择原本不会选择的词元,使其偏离正轨 [1]。例如,在默认启用此功能后,gpt-oss-20b、Qwen 3.6 和 GLM 5.1 的用户报告了问题。
- 语法转换缺陷:vLLM 在将模型的工具模式或工具调用格式转换为该模型特定的语法时,可能会存在缺陷。这可能导致无效的工具调用、请求失败、静默丢弃约束解码以及工具调用准确率降低 [1, 2]。
- 功能交互缺陷:约束解码与服务引擎其他功能之间的交互存在缺陷。例如,约束解码与投机解码之间的交互缺陷可能导致投机词元被语法规则错误地拒绝,从而造成请求失败 [1, 2]。
由于这些问题,vLLM 维护者报告称,在启用约束解码后,有几个模型出现了问题。这使得默认禁用约束解码成为 vLLM 这类模型无关型服务引擎更安全的选择。后来,vLLM 添加了 --tool-strict-level 标志,使用户能够为自己的部署启用工具调用严格性。
不过,Ubicloud 的关注重点与 vLLM 不同。我们专注于提供 Kimi 和 DeepSeek 模型,并达到用户对第一方提供商所期望的质量。为此,我们启用了约束解码,并重新运行了 K2VV ToolCall 基准测试。在确认所有提供服务的模型版本均达到 100% 的工具调用模式准确率后,我们将这项更改部署到了生产环境。随后,我们撰写了这篇博客文章,以分享我们的经验。
结论
使用 LLM 时,你观察到的质量并非仅取决于模型。推理引擎也起着重要作用。改变推理引擎及其设置,就会改变模型的输出质量。
在提供 Kimi K2.6 和 DeepSeek V4 Flash 服务时,我们观察到工具调用 schema 不准确导致质量明显下降。我们先维护自己的 vLLM fork,然后启用 vLLM 新增的约束解码功能,解决了这个问题。这使我们在 K2VV ToolCall 基准测试中的工具调用准确率从 92% 提升至 100%。
在这篇博文中,我们分享了工具调用和约束解码方面的经验。如果你对此感兴趣,或者想分享部署模型时的实战故事,请通过我们的支持邮箱。联系我们。
来源:Hacker News · ubicloud.com

