大模型 Function Calling 与工具使用:从对话到行动的工程实践

发布时间:2026/6/12 21:14:27

大模型 Function Calling 与工具使用:从对话到行动的工程实践 大模型 Function Calling 与工具使用从对话到行动的工程实践一、大模型的知行鸿沟能说不能做的困境大语言模型拥有丰富的知识储备但本质上只是一个文本生成器——它无法执行操作、无法查询实时数据、无法调用外部 API。用户问北京今天天气如何模型只能基于训练数据猜测无法获取实时天气信息。用户问帮我查一下订单 #12345 的状态模型无法连接数据库。Function Calling函数调用是打通知与行的桥梁模型不再直接回答问题而是生成结构化的函数调用指令由外部执行器调用真实 API 获取结果再将结果返回模型生成最终回答。这一机制让大模型从百科全书进化为智能助手。二、Function Calling 的执行流程Function Calling 的核心流程是用户提问 → 模型生成函数调用 → 外部执行 → 结果回注 → 模型生成回答。sequenceDiagram participant User as 用户 participant LLM as 大模型 participant Executor as 函数执行器 participant API as 外部 API User-LLM: 北京今天天气如何 LLM-LLM: 判断需要调用 get_weather LLM--Executor: get_weather(city北京) Executor-API: HTTP GET /weather?city北京 API--Executor: {temp: 28, condition: 晴} Executor--LLM: 函数返回结果 LLM-LLM: 基于结果生成自然语言回答 LLM--User: 北京今天晴天气温 28°C关键机制模型不直接执行函数只生成调用意图和参数。执行器负责实际调用和错误处理。这种分离确保了安全性——模型无法绕过权限限制直接访问外部系统。三、工程化实现3.1 工具定义与注册# tool_registry.py from dataclasses import dataclass from typing import Callable, Any import json dataclass class ToolDefinition: name: str description: str parameters: dict # JSON Schema function: Callable class ToolRegistry: def __init__(self): self.tools: dict[str, ToolDefinition] {} def register(self, name: str, description: str, parameters: dict): 装饰器注册工具函数 def decorator(func: Callable): self.tools[name] ToolDefinition( namename, descriptiondescription, parametersparameters, functionfunc, ) return func return decorator def get_tool_definitions(self) - list[dict]: 生成 OpenAI Function Calling 格式的工具定义 return [ { type: function, function: { name: tool.name, description: tool.description, parameters: tool.parameters, } } for tool in self.tools.values() ] def execute(self, name: str, arguments: dict) - Any: 执行工具函数 tool self.tools.get(name) if not tool: raise ValueError(f未知工具{name}) return tool.function(**arguments) # 注册具体工具 registry ToolRegistry() registry.register( nameget_weather, description获取指定城市的当前天气信息, parameters{ type: object, properties: { city: { type: string, description: 城市名称如北京、上海, }, }, required: [city], }, ) def get_weather(city: str) - dict: import requests # 调用天气 API response requests.get( fhttps://api.weather.com/current, params{city: city}, timeout10, ) if response.status_code ! 200: return {error: f天气 API 请求失败HTTP {response.status_code}} return response.json() registry.register( namesearch_database, description查询数据库中的订单信息, parameters{ type: object, properties: { order_id: { type: string, description: 订单编号, }, fields: { type: array, items: {type: string}, description: 需要查询的字段列表, }, }, required: [order_id], }, ) def search_database(order_id: str, fields: list[str] None) - dict: # 模拟数据库查询 return { order_id: order_id, status: 已发货, amount: 299.00, tracking_number: SF1234567890, }3.2 Function Calling 执行器# function_calling_executor.py import json from openai import OpenAI class FunctionCallingExecutor: def __init__(self, registry: ToolRegistry, model: str gpt-4o): self.client OpenAI() self.registry registry self.model model def run(self, user_message: str, max_rounds: int 5) - str: 执行 Function Calling 循环 messages [ {role: system, content: 你是一个智能助手可以调用工具帮助用户。}, {role: user, content: user_message}, ] tools self.registry.get_tool_definitions() for round_num in range(max_rounds): # 调用 LLM response self.client.chat.completions.create( modelself.model, messagesmessages, toolstools if tools else None, tool_choiceauto, ) choice response.choices[0] message choice.message # 如果没有工具调用直接返回回答 if not message.tool_calls: return message.content # 将助手消息含工具调用加入历史 messages.append(message) # 执行每个工具调用 for tool_call in message.tool_calls: function_name tool_call.function.name try: arguments json.loads(tool_call.function.arguments) except json.JSONDecodeError: arguments {} try: # 执行工具函数 result self.registry.execute(function_name, arguments) result_str json.dumps(result, ensure_asciiFalse) except Exception as e: result_str json.dumps( {error: f工具执行失败{str(e)}}, ensure_asciiFalse, ) # 将工具结果加入消息历史 messages.append({ role: tool, tool_call_id: tool_call.id, content: result_str, }) return 抱歉工具调用轮次已达上限请简化您的问题。3.3 多轮工具调用与错误恢复# advanced_executor.py class AdvancedExecutor(FunctionCallingExecutor): def run_with_retry(self, user_message: str, max_rounds: int 10) - str: 支持重试和错误恢复的执行器 messages [ {role: system, content: ( 你是一个智能助手。调用工具时请注意\n 1. 参数必须符合 Schema 定义\n 2. 如果工具返回错误分析原因并重试\n 3. 不要编造工具返回的数据 )}, {role: user, content: user_message}, ] tools self.registry.get_tool_definitions() failed_calls set() # 记录失败的调用避免无限重试 for _ in range(max_rounds): response self.client.chat.completions.create( modelself.model, messagesmessages, toolstools, tool_choiceauto, ) choice response.choices[0] message choice.message if not message.tool_calls: return message.content messages.append(message) for tool_call in message.tool_calls: call_key f{tool_call.function.name}:{tool_call.function.arguments} # 避免重复调用同一个失败的工具 if call_key in failed_calls: messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps({ error: 此调用之前已失败请尝试不同的参数或工具 }), }) continue try: arguments json.loads(tool_call.function.arguments) result self.registry.execute( tool_call.function.name, arguments ) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) except Exception as e: failed_calls.add(call_key) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps({ error: str(e), hint: 请检查参数格式是否正确, }), }) return 工具调用轮次已达上限。四、Function Calling 的 Trade-offs参数生成的准确性模型可能生成不符合 Schema 的参数如字符串传给了数字字段、缺少必填参数。建议在执行器中加入参数校验层对不符合 Schema 的参数返回错误信息让模型重新生成。工具选择的准确性模型可能选择错误的工具如用 search_database 查天气。优化工具描述description是提高选择准确性的关键——描述必须清晰区分工具的适用场景。延迟的累积效应每轮 Function Calling 包含一次 LLM 调用 一次工具执行总延迟 LLM 延迟 × 轮数 工具延迟。3 轮调用可能需要 5-10 秒。建议对简单查询无需工具跳过工具调用对复杂查询设置最大轮数限制。安全性风险工具函数可能执行危险操作如删除数据、发送邮件。建议对写操作工具设置确认机制——执行前向用户展示操作意图获得确认后再执行。五、总结Function Calling 是大模型从对话走向行动的关键机制通过模型生成调用意图、外部执行器实际调用的分离架构兼顾了能力和安全性。落地路线上建议先定义核心工具集查询类再逐步扩展到操作类工具写入类需加确认。关键原则工具描述决定选择准确性参数校验防止格式错误错误恢复提升鲁棒性安全确认守住底线。

相关新闻