通义千问2.5工具调用全攻略:Function Calling实战演示
引言
在构建智能代理(Agent)系统时,大语言模型(LLM)不仅需要理解用户意图,还需具备与外部世界交互的能力。Function Calling(函数调用)正是实现这一能力的核心机制——它允许模型根据上下文判断是否需要调用预定义的工具,并以结构化方式输出调用参数。
通义千问2.5-7B-Instruct 模型原生支持 Function Calling 和 JSON 格式强制输出,这使其成为轻量级 Agent 构建的理想选择。本文将围绕该模型,深入讲解 Function Calling 的工作原理、配置方法和工程实践,通过完整代码示例展示如何实现天气查询、数据库检索、代码执行等典型场景的工具集成。
1. Function Calling 技术背景与核心价值
1.1 为何需要 Function Calling?
尽管大模型具备强大的语言理解和生成能力,但其知识受限于训练数据,且无法直接访问实时信息或执行操作。例如:
- “今天北京天气怎么样?” → 需要调用天气 API
- “帮我查一下订单 ID 为 10086 的状态” → 需要连接数据库
- “画一个正弦波图像” → 需要运行 Python 代码
传统做法是让模型自由生成文本描述请求,再由后端解析,这种方式存在格式不稳定、易出错、难以自动化等问题。
Function Calling 提供了一种标准化解决方案:模型不再“描述”动作,而是“声明”要调用的函数及其参数,输出为结构化的 JSON 对象,便于程序自动解析和执行。
1.2 通义千问2.5的Function Calling优势
相比其他7B级别模型,通义千问2.5-7B-Instruct 在工具调用方面具有以下显著优势:
- 原生支持 JSON 输出模式:可通过提示词控制模型输出严格符合 Schema 的 JSON 结构。
- 高精度参数提取:在 HumanEval 和 ToolBench 基准测试中表现优异,能准确识别多参数函数调用。
- 长上下文支持(128K):可在复杂对话历史中保持对工具调用状态的记忆。
- 商用许可开放:可安全用于企业级应用开发。
这些特性使得 Qwen2.5-7B 成为目前最适合部署本地化 Agent 系统的中等规模模型之一。
2. Function Calling 工作机制详解
2.1 调用流程总览
Function Calling 的典型执行流程如下:
- 定义工具集:预先注册一组可用函数及其 JSON Schema 描述
- 构造提示词:将工具描述注入 prompt,引导模型理解何时调用
- 模型推理:模型分析用户输入,决定是否调用函数并生成 JSON 参数
- 解析与执行:系统解析 JSON 并调用对应函数
- 结果反馈:将函数返回结果重新输入模型,生成最终回复
整个过程形成一个“感知→决策→行动→反馈”的闭环。
2.2 函数描述的JSON Schema设计
为了让模型正确理解函数用途和参数要求,必须使用标准 JSON Schema 进行描述。以下是一个天气查询函数的定义示例:
{ "name": "get_weather", "description": "获取指定城市的当前天气信息", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,如'北京'、'上海'" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位,默认为celsius" } }, "required": ["city"] } }关键字段说明: -name:函数名,需与实际代码一致 -description:功能描述,影响模型调用判断 -parameters:参数结构定义,支持嵌套对象 -required:必填参数列表
模型会基于此描述自动生成类似以下的调用请求:
{ "function": "get_weather", "arguments": { "city": "杭州", "unit": "celsius" } }3. 实战项目:基于Qwen2.5-7B的智能助手
本节将演示如何使用vLLM+FastAPI搭建一个支持 Function Calling 的智能助手服务。
3.1 环境准备
确保已安装以下依赖库:
pip install vllm fastapi uvicorn pydantic requests启动 vLLM 推理服务器(假设模型已下载至本地路径):
python -m vllm.entrypoints.api_server \ --host 0.0.0.0 \ --port 8000 \ --model /models/Qwen2.5-7B-Instruct \ --tensor-parallel-size 1 \ --dtype half \ --enable-auto-tool-call注意:
--enable-auto-tool-call是启用函数调用的关键参数
3.2 定义可用工具集
创建tools.py文件,定义三个常用工具:
import requests import subprocess import sqlite3 from typing import Dict, Any def get_weather(city: str, unit: str = "celsius") -> Dict[str, Any]: """获取城市天气""" try: url = f"https://wttr.in/{city}?format=j1" response = requests.get(url, timeout=5) data = response.json() temp_c = data['current_condition'][0]['temp_C'] desc = data['current_condition'][0]['weatherDesc'][0]['value'] return { "city": city, "temperature": float(temp_c), "unit": "°C", "description": desc, "success": True } except Exception as e: return {"error": str(e), "success": False} def execute_python_code(code: str) -> Dict[str, Any]: """执行Python代码并返回结果""" try: result = subprocess.run( ['python', '-c', code], capture_output=True, text=True, timeout=10 ) return { "stdout": result.stdout, "stderr": result.stderr, "returncode": result.returncode, "success": result.returncode == 0 } except Exception as e: return {"error": str(e), "success": False} def query_order_status(order_id: int) -> Dict[str, Any]: """模拟查询订单状态""" # 模拟数据库 orders = { 10086: {"status": "已发货", "tracking_number": "SF123456789CN"}, 10010: {"status": "待付款", "expires_in_hours": 24} } order = orders.get(order_id) if order: return {"order_id": order_id, "info": order, "found": True} else: return {"order_id": order_id, "error": "订单不存在", "found": False}3.3 构造函数调用提示词
向模型发送请求时,需在 prompt 中包含工具描述。以下是构造请求体的 Python 示例:
import requests def build_tool_call_request(user_input: str): tools = [ { "type": "function", "function": { "name": "get_weather", "description": "获取指定城市的当前天气信息", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"}, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位" } }, "required": ["city"] } } }, { "type": "function", "function": { "name": "execute_python_code", "description": "执行提供的Python代码片段", "parameters": { "type": "object", "properties": { "code": {"type": "string", "description": "要执行的Python代码"} }, "required": ["code"] } } }, { "type": "function", "function": { "name": "query_order_status", "description": "查询订单状态", "parameters": { "type": "object", "properties": { "order_id": {"type": "integer", "description": "订单ID"} }, "required": ["order_id"] } } } ] messages = [ {"role": "user", "content": user_input} ] return { "messages": messages, "tools": tools, "tool_choice": "auto", # 自动选择是否调用工具 "max_tokens": 512, "temperature": 0.3 } # 发送请求到vLLM API response = requests.post( "http://localhost:8000/v1/chat/completions", json=build_tool_call_request("杭州现在气温多少?") ) print(response.json())3.4 解析模型输出并执行调用
模型响应示例(成功触发调用):
{ "id": "chat-xxx", "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "call-abc123", "type": "function", "function": { "name": "get_weather", "arguments": {"city": "杭州"} } } ] } } ] }解析逻辑如下:
import json def handle_model_response(response_json, user_input): choice = response_json["choices"][0] message = choice["message"] if hasattr(message, "tool_calls") and message.tool_calls: # 执行第一个工具调用 tool_call = message.tool_calls[0] func_name = tool_call["function"]["name"] args = json.loads(tool_call["function"]["arguments"]) # 映射函数名到实际函数 available_functions = { "get_weather": get_weather, "execute_python_code": execute_python_code, "query_order_status": query_order_status } if func_name in available_functions: result = available_functions[func_name](**args) return { "requires_action": True, "function": func_name, "arguments": args, "result": result } # 否则直接返回文本回复 return { "requires_action": False, "reply": message.content }3.5 完整对话循环实现
结合以上组件,构建完整的 Agent 循环:
def run_conversation(user_input: str): # 第一步:调用模型判断是否需要工具 initial_request = build_tool_call_request(user_input) response = requests.post( "http://localhost:8000/v1/chat/completions", json=initial_request ).json() action_result = handle_model_response(response, user_input) if not action_result["requires_action"]: return action_result["reply"] # 第二步:执行函数并获取结果 func_result = action_result["result"] # 第三步:将结果返回给模型生成自然语言回复 final_messages = [ {"role": "user", "content": user_input}, { "role": "assistant", "tool_calls": [ { "id": "call-123", "type": "function", "function": { "name": action_result["function"], "arguments": json.dumps(action_result["arguments"]) } } ] }, { "role": "tool", "content": json.dumps(func_result), "tool_call_id": "call-123" } ] # 最终请求(不带tools,仅生成回复) final_response = requests.post( "http://localhost:8000/v1/chat/completions", json={ "messages": final_messages, "max_tokens": 256, "temperature": 0.2 } ).json() return final_response["choices"][0]["message"]["content"] # 测试 print(run_conversation("订单号10086现在什么状态?")) # 输出:"您的订单号10086当前状态为‘已发货’,快递单号是SF123456789CN。"4. 最佳实践与常见问题
4.1 提升调用准确率的技巧
- 清晰的功能描述:避免模糊表述,如“处理数据”应改为“计算两个数的加法”
- 合理设置必填参数:使用
required字段明确约束 - 限制枚举值:对固定选项使用
enum,减少拼写错误 - 添加示例说明(可选):部分框架支持提供调用示例
4.2 错误处理与降级策略
- 网络异常:工具调用失败时应返回结构化错误信息
- 无效参数:模型可能生成不符合 schema 的参数,需做校验
- 无匹配工具:当
tool_choice=auto时,模型可能选择不调用,需准备兜底回复
4.3 安全注意事项
- 代码执行隔离:
execute_python_code类功能应在沙箱环境中运行 - 敏感接口保护:避免暴露数据库写入、文件删除等高危操作
- 输入验证:对所有传入参数进行类型和范围检查
5. 总结
Function Calling 是连接大模型与真实世界的桥梁。本文以通义千问2.5-7B-Instruct 为例,系统性地展示了从环境搭建、工具定义、请求构造到结果处理的全流程实现。
通过本次实践,我们验证了该模型在以下方面的突出表现: - ✅ 能准确识别多场景下的工具调用需求 - ✅ 支持复杂参数结构的 JSON 输出 - ✅ 在 128K 上下文中保持稳定的调用一致性 - ✅ 可在消费级 GPU(如 RTX 3060)上高效运行
对于希望构建轻量级、可商用 Agent 系统的开发者而言,Qwen2.5-7B-Instruct 提供了一个性能与成本兼顾的理想选择。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。