深入解析大语言模型的-Function-Call-实现-以-Qwen2.5为例
深入解析大语言模型的 Function Call 实现—— 以 Qwen2.5为例
引言
在现代大语言模型(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 XML tags:\n” }} {%- for tool in tools %} {{- “\n” }} {{- tool | tojson }} {%- endfor %} {{- “\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{"name": , "arguments": }\n<|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\n{“name”: “’ }} {{- tool_call.name }} {{- ‘”, “arguments”: ’ }} {{- tool_call.arguments | tojson }} {{- ‘}\n’ }} {%- endfor %} {{- ‘<|im_end|>\n’ }} {%- elif message.role == “tool” %} {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != “tool”) %} {{- ‘<|im_start|>user’ }} {%- endif %} {{- ‘\n\n’ }} {{- message.content }} {{- ‘\n’ }} {%- 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 格式定义。
- 函数调用返回格式:要求助手在返回函数调用时,使用 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 XML tags: {“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”]}}} For each function call, return a json object with function name and arguments within XML tags: {“name”: , “arguments”: } <|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 生成的输出
{“name”: “get_current_temperature”, “arguments”: {“location”: “北京, 北京市, 中国”, “unit”: “celsius”}} <|im_end|>
5 结论
Qwen2.5-7B-Instruct 通过结构化的模板和XML 格式化的函数调用,让 LLM 能够有效调用外部工具。
- 模板结构清晰:采用 <|im_start|> 和 <|im_end|> 明确区分对话内容。
- 工具调用明确:使用 定义可用函数,并在 结构中返回函数调用。
- 易于扩展:可以轻松添加多个 tools,支持复杂应用场景。 这种 Function Call 机制为 LLM 在实际应用中提供了极大的灵活性,使其能在多种任务中高效执行函数调用并获取外部信息。