跳到内容

工具调用

vLLM 目前支持命名函数调用,以及聊天补全 API 中 tool_choice 字段的 autorequired (自 vllm>=0.8.3 起) 和 none 选项。

快速入门

启动服务器并启用工具调用。此示例使用 Meta 的 Llama 3.1 8B 模型,因此我们需要使用 vLLM 示例目录中的 llama3 工具调用聊天模板。

vllm serve meta-llama/Llama-3.1-8B-Instruct \
    --enable-auto-tool-choice \
    --tool-call-parser llama3_json \
    --chat-template examples/tool_chat_template_llama3.1_json.jinja

接下来,向模型发出请求,这应会使其使用可用的工具。

from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")

def get_weather(location: str, unit: str):
    return f"Getting the weather for {location} in {unit}..."
tool_functions = {"get_weather": get_weather}

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City and state, e.g., 'San Francisco, CA'"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["location", "unit"]
        }
    }
}]

response = client.chat.completions.create(
    model=client.models.list().data[0].id,
    messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
    tools=tools,
    tool_choice="auto"
)

tool_call = response.choices[0].message.tool_calls[0].function
print(f"Function called: {tool_call.name}")
print(f"Arguments: {tool_call.arguments}")
print(f"Result: {get_weather(**json.loads(tool_call.arguments))}")

示例输出

Function called: get_weather
Arguments: {"location": "San Francisco, CA", "unit": "fahrenheit"}
Result: Getting the weather for San Francisco, CA in fahrenheit...

此示例展示了

  • 设置启用工具调用的服务器
  • 定义一个实际函数来处理工具调用
  • 使用 tool_choice="auto" 发出请求
  • 处理结构化响应并执行相应函数

您还可以通过设置 tool_choice={"type": "function", "function": {"name": "get_weather"}} 来使用命名函数调用指定特定函数。请注意,这将使用 guided decoding 后端 - 因此首次使用时,由于 FSM 首次编译,将会有几秒甚至更长时间的延迟,之后会缓存以用于后续请求。

请记住,调用者有责任

  1. 在请求中定义合适的工具
  2. 在聊天消息中包含相关上下文
  3. 在应用程序逻辑中处理工具调用

有关更高级的用法,包括并行工具调用和不同的模型专用解析器,请参阅以下章节。

命名函数调用

vLLM 默认支持聊天补全 API 中的命名函数调用。它通过 guided decoding 使用 Outlines 实现,因此默认启用,并适用于任何受支持的模型。您将获得一个可有效解析的函数调用 - 而非高质量的调用。

vLLM 将使用 guided decoding 确保响应匹配 tools 参数中 JSON schema 定义的工具参数对象。为了获得最佳结果,我们建议确保在 prompt 中指定预期的输出格式/schema,以确保模型预期的生成与 guided decoding 后端强制生成的 schema 对齐。

要使用命名函数,您需要在聊天补全请求的 tools 参数中定义函数,并在聊天补全请求的 tool_choice 参数中指定其中一个工具的 name

必需函数调用

vLLM 支持聊天补全 API 中的 tool_choice='required' 选项。与命名函数调用类似,它也使用 guided decoding,因此默认启用并适用于任何受支持的模型。必需的 guided decoding 功能 (带 anyOf 的 JSON schema) 目前仅在 V0 引擎且使用 guided decoding 后端 outlines 时受支持。然而,对 V1 引擎中替代解码后端的支持已列入 路线图

当设置 tool_choice='required' 时,模型保证会根据 tools 参数中指定的工具列表生成一个或多个工具调用。工具调用的数量取决于用户的查询。输出格式严格遵循 tools 参数中定义的 schema。

自动函数调用

要启用此功能,您应设置以下标志

  • --enable-auto-tool-choice -- **必需** 自动工具选择。告诉 vLLM 您希望模型在认为合适时能够生成自己的工具调用。
  • --tool-call-parser -- 选择要使用的工具解析器(列于下方)。将来会继续添加更多工具解析器,您也可以在 --tool-parser-plugin 中注册自己的工具解析器。
  • --tool-parser-plugin -- **可选** 工具解析器插件,用于在 vllm 中注册用户定义的工具解析器,注册的工具解析器名称可以在 --tool-call-parser 中指定。
  • --chat-template -- **可选** 针对自动工具选择。指向聊天模板的路径,该模板处理 tool 角色消息和包含先前生成的工具调用的 assistant 角色消息。Hermes、Mistral 和 Llama 模型在其 tokenizer_config.json 文件中包含工具兼容的聊天模板,但您可以指定自定义模板。如果您的模型在 tokenizer_config.json 中配置了工具使用特定的聊天模板,则此参数可以设置为 tool_use。在这种情况下,将按照 transformers 的规范使用该模板。有关更多信息,请参阅 HuggingFace 的此处;您可以在此处找到 tokenizer_config.json 中的示例。

如果您喜欢的工具调用模型不受支持,欢迎贡献解析器和工具使用聊天模板!

Hermes 模型 (hermes)

所有 Nous Research Hermes 系列中比 Hermes 2 Pro 新的模型都应受支持。

  • NousResearch/Hermes-2-Pro-*
  • NousResearch/Hermes-2-Theta-*
  • NousResearch/Hermes-3-*

请注意,Hermes 2 Theta 模型由于创建过程中的合并步骤,已知其工具调用质量和能力有所下降。.

标志:--tool-call-parser hermes

Mistral 模型 (mistral)

支持的模型

  • mistralai/Mistral-7B-Instruct-v0.3 (已确认)
  • 其他 Mistral 函数调用模型也兼容。

已知问题

  1. Mistral 7B 在正确生成并行工具调用方面存在困难。
  2. Mistral 的 tokenizer_config.json 聊天模板要求工具调用 ID 恰好是 9 位数字,这比 vLLM 生成的 ID 短得多。由于不满足此条件时会抛出异常,因此提供了以下附加聊天模板:

  3. examples/tool_chat_template_mistral.jinja - 这是“官方”的 Mistral 聊天模板,但经过调整,使其可与 vLLM 的工具调用 ID 一起使用(提供的 tool_call_id 字段被截断为最后 9 位数字)

  4. examples/tool_chat_template_mistral_parallel.jinja - 这是“更好”的版本,在提供工具时添加了工具使用的系统提示,这使得并行工具调用更可靠。

推荐标志:--tool-call-parser mistral --chat-template examples/tool_chat_template_mistral_parallel.jinja

Llama 模型 (llama3_json)

支持的模型

所有 Llama 3.1、3.2 和 4 模型都应受支持。

  • meta-llama/Llama-3.1-*
  • meta-llama/Llama-3.2-*
  • meta-llama/Llama-4-*

支持的工具调用是 JSON 格式的工具调用。对于 Llama-3.2 模型引入的 Pythonic 工具调用,请参阅下面的 pythonic 工具解析器。至于 Llama 4 模型,建议使用 llama4_pythonic 工具解析器。

不支持内置的 Python 工具调用或自定义工具调用等其他工具调用格式。

已知问题

  1. Llama 3 不支持并行工具调用,但 Llama 4 模型支持。
  2. 模型可能会生成格式错误的参数,例如将数组序列化为字符串而不是生成一个数组。

VLLM 为 Llama 3.1 和 3.2 提供了两个基于 JSON 的聊天模板

推荐标志:--tool-call-parser llama3_json --chat-template {见上方}

VLLM 还为 Llama 4 提供了一个 Pythonic 和基于 JSON 的聊天模板,但推荐使用 Pythonic 工具调用:* examples/tool_chat_template_llama4_pythonic.jinja - 这是基于 Llama 4 模型的官方聊天模板

对于 Llama 4 模型,使用 --tool-call-parser llama4_pythonic --chat-template examples/tool_chat_template_llama4_pythonic.jinja

IBM Granite

支持的模型

  • ibm-granite/granite-3.0-8b-instruct

推荐标志:--tool-call-parser granite --chat-template examples/tool_chat_template_granite.jinja

examples/tool_chat_template_granite.jinja:这是在 Huggingface 上的原始聊天模板基础上修改的。支持并行函数调用。

  • ibm-granite/granite-3.1-8b-instruct

推荐标志:--tool-call-parser granite

可以直接使用 Huggingface 提供的聊天模板。支持并行函数调用。

  • ibm-granite/granite-20b-functioncalling

推荐标志:--tool-call-parser granite-20b-fc --chat-template examples/tool_chat_template_granite_20b_fc.jinja

examples/tool_chat_template_granite_20b_fc.jinja:这是在 Huggingface 上的原始聊天模板基础上修改的,与 vLLM 不兼容。它融合了来自 Hermes 模板的函数描述元素,并遵循论文中“响应生成”模式的相同系统提示。支持并行函数调用。

InternLM 模型 (internlm)

支持的模型

  • internlm/internlm2_5-7b-chat (已确认)
  • 其他 internlm2.5 函数调用模型也兼容

已知问题

  • 尽管此实现也支持 InternLM2,但在使用 internlm/internlm2-chat-7b 模型进行测试时,工具调用结果不稳定。

推荐标志:--tool-call-parser internlm --chat-template examples/tool_chat_template_internlm2_tool.jinja

Jamba 模型 (jamba)

支持 AI21 的 Jamba-1.5 模型。

  • ai21labs/AI21-Jamba-1.5-Mini
  • ai21labs/AI21-Jamba-1.5-Large

标志:--tool-call-parser jamba

Qwen 模型

对于 Qwen2.5,tokenizer_config.json 中的聊天模板已包含对 Hermes 风格工具使用的支持。因此,您可以使用 hermes 解析器为 Qwen 模型启用工具调用。更多详细信息,请参阅官方 Qwen 文档

  • Qwen/Qwen2.5-*
  • Qwen/QwQ-32B

标志:--tool-call-parser hermes

DeepSeek-V3 模型 (deepseek_v3)

支持的模型:* deepseek-ai/DeepSeek-V3-0324

标志:--tool-call-parser deepseek_v3 --chat-template examples/tool_chat_template_deepseekv3.jinja

具备 Pythonic 工具调用的模型 (pythonic)

越来越多的模型输出 Python 列表来表示工具调用,而不是使用 JSON。这固有地支持并行工具调用,并消除了工具调用所需 JSON schema 的模糊性。pythonic 工具解析器可以支持此类模型。

例如,这些模型可以通过生成如下内容来查找旧金山和西雅图的天气:

[get_weather(city='San Francisco', metric='celsius'), get_weather(city='Seattle', metric='celsius')]

限制

  • 模型在同一生成中不能同时生成文本和工具调用。这对于特定模型来说可能不难改变,但社区目前对于何时开始和结束工具调用时应发出哪些 token 尚未达成共识。(特别是 Llama 3.2 模型不发出此类 token。)
  • Llama 的小型模型难以有效使用工具。

示例支持的模型

标志:--tool-call-parser pythonic --chat-template {见上方}


**警告** Llama 的小型模型经常无法以正确的格式发出工具调用。效果可能因情况而异。


如何编写工具解析器插件

工具解析器插件是一个 Python 文件,包含一个或多个 ToolParser 实现。您可以编写一个类似于 vllm/entrypoints/openai/tool_parsers/hermes_tool_parser.py 中的 Hermes2ProToolParser 的 ToolParser。

以下是插件文件的摘要

# import the required packages

# define a tool parser and register it to vllm
# the name list in register_module can be used
# in --tool-call-parser. you can define as many
# tool parsers as you want here.
@ToolParserManager.register_module(["example"])
class ExampleToolParser(ToolParser):
    def __init__(self, tokenizer: AnyTokenizer):
        super().__init__(tokenizer)

    # adjust request. e.g.: set skip special tokens
    # to False for tool call output.
    def adjust_request(
            self, request: ChatCompletionRequest) -> ChatCompletionRequest:
        return request

    # implement the tool call parse for stream call
    def extract_tool_calls_streaming(
        self,
        previous_text: str,
        current_text: str,
        delta_text: str,
        previous_token_ids: Sequence[int],
        current_token_ids: Sequence[int],
        delta_token_ids: Sequence[int],
        request: ChatCompletionRequest,
    ) -> Union[DeltaMessage, None]:
        return delta

    # implement the tool parse for non-stream call
    def extract_tool_calls(
        self,
        model_output: str,
        request: ChatCompletionRequest,
    ) -> ExtractedToolCallInformation:
        return ExtractedToolCallInformation(tools_called=False,
                                            tool_calls=[],
                                            content=text)

然后您可以在命令行中这样使用此插件。

    --enable-auto-tool-choice \
    --tool-parser-plugin <absolute path of the plugin file>
    --tool-call-parser example \
    --chat-template <your chat template> \