当前位置: 首页 > article >正文

深入解析大语言模型的 Function Call 实现—— 以 Qwen2.5为例

GitHub代码仓库

引言

在现代大语言模型(LLM)中,Function Call(函数调用)能力极大地提升了模型的实用性,使其能够调用外部 API、执行复杂计算或获取实时数据。例如,在 OpenAI API 和 Qwen2.5-7B-Instruct 这样的模型中,用户可以向模型提供工具(Tools),并允许模型在适当的时候调用它们。

本文以 Qwen2.5-7B-Instruct 为例,探讨其 Function Call 机制的底层实现。

1. Function Call 机制概述

通常,大语言模型的输入输出都是字符串,但 Function Call 允许模型在对话过程中识别特定的函数调用需求,并以结构化数据格式返回调用参数。

在 Qwen2.5-7B-Instruct 中,Function Call 由以下几部分组成:

  • messages:对话历史,包括用户、系统、助手的消息。

  • tools:可供调用的函数信息,描述了函数名称、参数格式等。

2. Function Call 的 Prompt 生成

在 Qwen2.5-7B-Instruct 后端,所有 messages 和 tools 会被应用到一个固定的模板上,以便模型正确解析和执行 Function Call。

2.1 获取模板

from transformers import Qwen2ForCausalLM, Qwen2TokenizerFast

model_name_or_path = "Qwen/Qwen2.5-7B-Instruct"
tokenizer = Qwen2TokenizerFast.from_pretrained(model_name_or_path)
print(tokenizer.get_chat_template())

此代码返回一个 Prompt 生成模板,该模板会根据 messages 和 tools 生成最终的输入格式。

2.2 模板内容解析

模板的核心部分如下:

{%- if tools %}
    {{- '<|im_start|>system\n' }}
    {%- if messages[0]['role'] == 'system' %}
        {{- messages[0]['content'] }}
    {%- else %}
        {{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }}
    {%- endif %}
    {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
    {%- for tool in tools %}
        {{- "\n" }}
        {{- tool | tojson }}
    {%- endfor %}
    {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
{%- else %}
    {%- if messages[0]['role'] == 'system' %}
        {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }}
    {%- else %}
        {{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }}
    {%- endif %}
{%- endif %}
{%- for message in messages %}
    {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %}
        {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
    {%- elif message.role == "assistant" %}
        {{- '<|im_start|>' + message.role }}
        {%- if message.content %}
            {{- '\n' + message.content }}
        {%- endif %}
        {%- for tool_call in message.tool_calls %}
            {%- if tool_call.function is defined %}
                {%- set tool_call = tool_call.function %}
            {%- endif %}
            {{- '\n<tool_call>\n{"name": "' }}
            {{- tool_call.name }}
            {{- '", "arguments": ' }}
            {{- tool_call.arguments | tojson }}
            {{- '}\n</tool_call>' }}
        {%- endfor %}
        {{- '<|im_end|>\n' }}
    {%- elif message.role == "tool" %}
        {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %}
            {{- '<|im_start|>user' }}
        {%- endif %}
        {{- '\n<tool_response>\n' }}
        {{- message.content }}
        {{- '\n</tool_response>' }}
        {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
            {{- '<|im_end|>\n' }}
        {%- endif %}
    {%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
    {{- '<|im_start|>assistant\n' }}
{%- endif %}
  • 工具(Tools)定义:当提供 tools 时,系统消息(System Message)中会插入一段描述工具的文本,包括工具的 JSON 格式定义。
  • 函数调用返回格式:要求助手在返回函数调用时,使用 <tool_call></tool_call> XML 标签包裹 JSON 格式的调用信息。
  • 消息格式:不同角色的消息采用 <|im_start|>role\nmessage<|im_end|> 的格式,保证模型能够正确解析对话内容。

3. 应用模板并生成 Prompt

当 messages 和 tools 被应用到该模板后,会生成如下格式的输入文本:

text = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, tokenize=False)
print(text)

3.1 示例输入

{
    "model": "Qwen/Qwen2.5-7B-Instruct",
    "messages": [
        {"role": "system", "content": "你是Qwen, 由阿里巴巴创建.\n\nCurrent Date: 2025-03-15"},
        {"role": "user", "content": "北京的气温是多少?"}
    ],
    "tools": [
        {
            "name": "get_current_temperature",
            "description": "Get current temperature at a location.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "The location to get the temperature for."},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "The unit to return the temperature in."}
                },
                "required": ["location"]
            }
        }
    ]
}

3.2 生成的 Prompt

<|im_start|>system
你是Qwen, 由阿里巴巴创建.
Current Date: 2025-03-15
# Tools
You may call one or more functions to assist with the user query.
You are provided with function signatures within <tools></tools> XML tags:
<tools>
{"type": "function", "function": {"name": "get_current_temperature", "description": "Get current temperature at a location.", "parameters": {"type": "object", "properties": {"location": {"type": "string", "description": "The location to get the temperature for, in the format \"City, State, Country\"."}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "The unit to return the temperature in. Defaults to \"celsius\"."}}, "required": ["location"]}}}
</tools>
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call><|im_end|>
<|im_start|>user
北京的气温是多少?<|im_end|>
<|im_start|>assistant

4. 运行模型并解析输出

在生成 text 后,我们需要调用 Qwen2.5-7B-Instruct 进行推理,并解析返回的函数调用。

4.1 加载模型并进行推理

model = Qwen2ForCausalLM.from_pretrained(
    model_name_or_path,
    torch_dtype="auto",
    device_map="auto",
)

inputs = tokenizer(text, return_tensors="pt").to(model.device)

model.eval()
with torch.no_grad():
    outputs = model.generate(**inputs, max_new_tokens=512)
    output_text = tokenizer.batch_decode(outputs)[0][len(text):]
    print(output_text)

4.2 生成的输出

<tool_call>
{"name": "get_current_temperature", "arguments": {"location": "北京, 北京市, 中国", "unit": "celsius"}}
</tool_call><|im_end|>

5. 结论

Qwen2.5-7B-Instruct 通过结构化的模板和XML 格式化的函数调用,让 LLM 能够有效调用外部工具。

  • 模板结构清晰:采用 <|im_start|> 和 <|im_end|> 明确区分对话内容。
  • 工具调用明确:使用 定义可用函数,并在 <tool_call></tool_call> 结构中返回函数调用。
  • 易于扩展:可以轻松添加多个 tools,支持复杂应用场景。

这种 Function Call 机制为 LLM 在实际应用中提供了极大的灵活性,使其能在多种任务中高效执行函数调用并获取外部信息。


http://www.kler.cn/a/589007.html

相关文章:

  • 02-Canvas-fabric.ActiveSelection
  • 浅谈Mysql数据库事务操作 用mybatis操作mysql事务 再在Springboot中使用Spring事务控制mysql事务回滚
  • 数学 :矩阵
  • 【Gitee】删除仓库的详细步骤
  • ArcGIS 水利制图符号库:提升水利工作效率的利器
  • 【QT:控件】
  • 第三百八十节 JavaFX教程 - JavaFX区域图
  • 【商城实战(38)】Spring Boot:从本地事务到分布式事务,商城数据一致性的守护之旅
  • 数据结构——单链表list
  • 【软考-架构】11.3、设计模式-新
  • 从技术创新到全球布局:MOVA割草机器人以尖端科技定义智能园艺
  • windows上清理docker
  • NET进行CAD二次开发之二
  • django 运行时仅显示500 但是不提示其他内容 如何令其显示更多错误信息
  • pycharm环境创建
  • 群体智能优化算法-䲟鱼优化算法 (Remora Optimization Algorithm, ROA,含Matlab源代码)
  • Mysql与ElasticSearch间的数据同步场景模拟
  • MySQL数据库(数据库操作)4
  • Vue.js 中的计算属性、监听器与方法:区别与使用场景
  • 系统架构设计师—论文解析—论文写作技巧