ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

大模型工具调用实战:从原理到安全实践,构建智能AI助手

大模型工具调用实战:从原理到安全实践,构建智能AI助手 在AI应用开发中大模型本身就像一个知识渊博但“手无寸铁”的思考者。它能理解你的问题也能给出精彩的推理但当任务涉及查询实时天气、执行计算、操作数据库或调用外部API时它就无能为力了。这正是“工具调用”技术要解决的核心痛点——让大模型学会“使用工具”从而将强大的认知能力与丰富的现实世界操作能力结合起来构建出真正智能的AI智能体。本文将深入探讨大模型工具调用的完整技术栈。无论你是希望为聊天机器人添加查天气、订机票功能的开发者还是正在构建复杂自动化工作流的技术负责人亦或是对AI安全AI红队中工具滥用风险感兴趣的研究者本文都将为你提供从核心概念、主流框架实现到安全实践的全套指南。我们将从零开始手把手实现一个能调用外部工具的AI助手并深入分析其背后的机制、潜在风险及防护策略。1. 工具调用的核心概念与价值在深入代码之前我们必须厘清几个关键概念理解为什么工具调用是构建实用AI应用的关键一跃。1.1 什么是工具调用工具调用在技术语境下常被称为Function Calling或Tool Calling是指大语言模型根据用户请求识别出需要调用某个外部函数或工具来完成任务的意图并以结构化格式通常是JSON输出调用该工具所需的参数。随后应用程序解析这个输出实际执行对应的函数并将执行结果返回给大模型由大模型整合信息后生成最终回复给用户。一个简单的类比想象大模型是一个经验丰富的指挥官大脑它知道要完成“轰炸目标”这个任务需要调用“空军”工具。指挥官不会自己去开飞机而是下达一份包含坐标、弹药类型等详细参数的指令结构化调用。地勤人员应用程序接收指令指挥真正的飞机执行函数完成任务并将战果报告执行结果反馈给指挥官由指挥官向总部用户汇报最终情况。1.2 为什么需要工具调用——突破大模型的固有局限突破知识时效性大模型的训练数据有截止日期无法获知实时信息如股票价格、新闻、天气。弥补计算与逻辑能力大模型不擅长精确计算如(3.14 * 15.2^2) / 2、逻辑推理如复杂数据库查询或执行确定性算法。连接外部系统与服务大模型无法直接操作数据库、发送邮件、调用企业内部的CRM/ERP系统API。降低幻觉与错误对于需要精确数据的任务如查询账户余额让大模型“编造”不如让它调用一个返回真实数据的工具更可靠。1.3 核心参与角色与工作流程一次完整的工具调用涉及三个核心角色大模型理解意图规划步骤生成工具调用请求。应用程序提供工具定义解析模型请求安全执行工具管理上下文。工具执行具体操作的函数、API或服务。其标准工作流程如下图所示以OpenAI格式为例用户: “旧金山现在的天气怎么样” ↓ 应用程序将[用户消息 工具定义列表]发送给大模型。 ↓ 大模型返回结构化响应: { “role”: “assistant” “content”: null “tool_calls”: [{ “id”: “call_123” “type”: “function” “function”: { “name”: “get_current_weather” “arguments”: “{ \”location\”: \”San Francisco\” \”unit\”: \”celsius\” }” } }] } ↓ 应用程序解析tool_calls执行本地函数 get_current_weather(“San Francisco” “celsius”) 获得结果 {“temperature”: 22 “condition”: “Sunny”}。 ↓ 应用程序将[工具执行结果]作为新消息附加到对话历史再次发送给大模型。 ↓ 大模型整合信息生成最终回复: “旧金山现在天气晴朗气温22摄氏度。” ↓ 应用程序将最终回复返回给用户。2. 环境准备与主流框架选择在开始实战前我们需要搭建开发环境。本文将以Python生态为主因为其拥有最丰富的大模型工具调用库和社区支持。2.1 基础环境配置操作系统Windows 10/11 macOS 或 Linux (Ubuntu 20.04)。本文示例在Linux/macOS的终端环境下演示。Python版本推荐使用Python 3.10或3.11。避免使用Python 3.12等较新版本可能遇到某些库的兼容性问题。包管理工具使用pip或更推荐的uv、poetry。首先创建一个干净的虚拟环境并安装核心库# 创建项目目录并进入 mkdir ai-tool-calling-demo cd ai-tool-calling-demo # 创建虚拟环境 (以venv为例) python -m venv venv # 激活虚拟环境 # Linux/macOS: source venv/bin/activate # Windows: # venv\Scripts\activate # 升级pip pip install --upgrade pip2.2 选择你的“武器库”主流框架对比实现工具调用有多种路径选择取决于你的需求原生API如OpenAI最直接功能强大但需付费且依赖网络。库:openai优点官方支持功能最全性能稳定。缺点产生API费用数据出境需合规考量。本地大模型适配框架数据私密可控性强适合企业内部部署。库:ollamalangchain/litellm优点数据完全本地无网络延迟成本固定硬件。缺点模型能力可能弱于顶级闭源模型需要一定的运维知识。高级抽象框架如LangChain提供一站式解决方案简化开发但抽象度高。库:langchainlangchain-community优点封装复杂流程支持多种模型和工具生态丰富。缺点学习曲线较陡有时为了灵活性需要深入底层。本文策略为了透彻理解原理我们将先从OpenAI原生API开始实现最基础的工具调用。然后再使用LangChain框架重构展示其如何提升开发效率。最后会简要介绍如何接入本地Ollama模型。安装核心依赖# 安装OpenAI Python SDK和LangChain pip install openai langchain langchain-openai langchain-community # 安装requests用于示例中的工具函数 pip install requests2.3 获取API密钥如使用OpenAI如果你选择使用OpenAI的模型需要准备API密钥。访问 OpenAI平台 。登录后点击右上角个人头像选择 “View API keys”。点击 “Create new secret key” 创建一个新的密钥并妥善保存。安全提示切勿将API密钥直接硬编码在代码中或提交到版本控制系统如Git。应使用环境变量管理。# 在终端中设置环境变量 (临时) export OPENAI_API_KEY你的-api-key-here # Windows (PowerShell): $env:OPENAI_API_KEY你的-api-key-here3. 核心原理与API拆解OpenAI Function CallingOpenAI的Chat Completions API在2023年6月左右引入了function calling功能后续更新中与tools调用合并这是工具调用普及的关键推动力。我们来详细拆解其核心组件。3.1 工具定义如何告诉模型“你有什么工具”你必须以JSON Schema格式清晰地定义每个工具函数。模型依靠这个定义来理解何时以及如何调用它。一个完整的工具定义包含type: 固定为function。function: 一个对象包含name: 函数名是模型在输出中引用的标识符。description:至关重要用自然语言描述这个函数的作用。模型主要靠这个描述来判断是否需要调用它。parameters: 遵循JSON Schema格式定义函数需要的参数包括类型、描述、是否必需等。# 这是一个工具定义的Python字典示例 weather_tool { “type”: “function” “function”: { “name”: “get_current_weather” “description”: “获取指定城市的当前天气情况” # 清晰的描述是关键 “parameters”: { “type”: “object” “properties”: { “location”: { “type”: “string” “description”: “城市名称例如北京 San Francisco” }, “unit”: { “type”: “string” “enum”: [“celsius” “fahrenheit”] “description”: “温度单位” } }, “required”: [“location”] # 指定必需参数 }, }, }3.2 模型响应模型如何表达“我要用这个工具”当模型决定调用工具时它不会在常规的content字段中输出文本而是会在tool_calls字段中返回一个或多个结构化的调用请求。关键响应字段解析role:“assistant”content: 通常为null因为回复内容由工具调用结果决定。tool_calls: 一个列表包含每个调用请求。id: 本次调用的唯一ID用于后续将执行结果关联回此次调用。type:“function”function: 包含name(函数名) 和arguments(参数字符串是合法的JSON)。3.3 对话历史管理多轮交互的关键工具调用通常是多轮对话的一部分。应用程序需要维护一个“消息列表”其中不仅包含用户和助理的对话还要包含“工具”角色的消息。消息类型{“role”: “user” “content”: “用户输入”}{“role”: “assistant” “content”: null “tool_calls”: […]}(模型请求调用工具){“role”: “tool” “content”: “工具执行结果JSON字符串” “tool_call_id”: “对应调用的ID”}(应用程序返回结果){“role”: “assistant” “content”: “基于工具结果的最终回答”}应用程序的责任是维护这个列表并在每次API调用时将其作为messages参数传入。4. 完整实战案例构建一个多功能AI助手现在我们将综合以上知识构建一个能处理天气查询、计算和百科搜索的AI助手。4.1 项目结构设计ai-tool-calling-demo/ ├── main_openai.py # 使用OpenAI原生API的实现 ├── main_langchain.py # 使用LangChain框架的实现 ├── tools.py # 所有工具函数的定义 ├── requirements.txt # 项目依赖 └── .env # 环境变量文件需自行创建不要提交4.2 定义工具函数 (tools.py)首先我们实现三个具体的工具函数。这些函数就是模型将要调用的“手”和“脚”。# tools.py import json import math import requests from datetime import datetime def get_current_weather(location: str unit: str “celsius”) - str: “”” 模拟获取天气的函数。 在实际应用中这里应该调用如OpenWeatherMap、和风天气等第三方API。 “”” # 模拟API返回数据 weather_data { “location”: location “temperature”: 22 if unit “celsius” else 72 “unit”: unit “condition”: “Sunny” “humidity”: 65 “wind_speed”: 15 “feels_like”: 24 if unit “celsius” else 75 “observation_time”: datetime.now().strftime(“%Y-%m-%d %H:%M:%S”) } print(f”[工具调用] 执行 get_current_weather 参数: location{location} unit{unit}”) return json.dumps(weather_data ensure_asciiFalse) def calculator(expression: str) - str: “”” 计算数学表达式。 警告在生产环境中直接使用eval是极度危险的容易导致代码注入。 此处仅用于演示实际应使用安全的表达式解析库如asteval。 “”” print(f”[工具调用] 执行 calculator 参数: expression{expression}”) try: # 安全限制移除危险的内置函数和属性访问 allowed_names {‘__builtins__’: None} result eval(expression {“__builtins__”: None} {“math”: math}) return json.dumps({“result”: result “expression”: expression}) except Exception as e: return json.dumps({“error”: str(e) “expression”: expression}) def search_wikipedia(query: str sentences: int 3) - str: “”” 使用Wikipedia API进行搜索。 这是一个真实的工具调用示例。 “”” print(f”[工具调用] 执行 search_wikipedia 参数: query{query} sentences{sentences}”) url “https://en.wikipedia.org/w/api.php” params { “action”: “query” “format”: “json” “list”: “search” “srsearch”: query “utf8”: 1 “srlimit”: 3 } try: response requests.get(url paramsparams timeout10) data response.json() search_results data.get(“query” {}).get(“search” []) if not search_results: return json.dumps({“results”: [] “message”: “No results found.”}) # 获取第一个结果的摘要 page_id search_results[0][“pageid”] params_detail { “action”: “query” “format”: “json” “pageids”: page_id “prop”: “extracts” “exintro”: True “explaintext”: True “exsentences”: sentences } response_detail requests.get(url paramsparams_detail timeout10) data_detail response_detail.json() pages data_detail.get(“query” {}).get(“pages” {}) extract pages.get(str(page_id) {}).get(“extract” “No extract available.”) return json.dumps({ “query”: query “title”: search_results[0][“title”] “summary”: extract.strip() } ensure_asciiFalse) except requests.exceptions.RequestException as e: return json.dumps({“error”: f“Network error: {e}”})4.3 使用OpenAI原生API实现 (main_openai.py)这是最基础、最透明的实现方式帮助你理解底层机制。# main_openai.py import os import json from openai import OpenAI from tools import get_current_weather calculator search_wikipedia from dotenv import load_dotenv # 加载环境变量从.env文件读取OPENAI_API_KEY load_dotenv() # 初始化OpenAI客户端 client OpenAI(api_keyos.getenv(“OPENAI_API_KEY”)) # 1. 定义工具列表 (对应tools.py中的函数) tools [ { “type”: “function” “function”: { “name”: “get_current_weather” “description”: “获取指定城市的当前天气信息” “parameters”: { “type”: “object” “properties”: { “location”: { “type”: “string” “description”: “城市或地区名称例如北京 纽约” }, “unit”: { “type”: “string” “enum”: [“celsius” “fahrenheit”] “description”: “温度单位默认为摄氏度(celsius)” } }, “required”: [“location”] }, }, }, { “type”: “function” “function”: { “name”: “calculator” “description”: “计算一个数学表达式的结果支持加减乘除、乘方和常见数学函数。表达式需为字符串格式。” “parameters”: { “type”: “object” “properties”: { “expression”: { “type”: “string” “description”: “数学表达式例如’3 5 * 2′ ‘math.sqrt(16)’” } }, “required”: [“expression”] }, }, }, { “type”: “function” “function”: { “name”: “search_wikipedia” “description”: “搜索维基百科并返回相关条目的摘要” “parameters”: { “type”: “object” “properties”: { “query”: { “type”: “string” “description”: “搜索关键词” }, “sentences”: { “type”: “number” “description”: “返回摘要的句子数量默认为3” “default”: 3 } }, “required”: [“query”] }, }, } ] # 工具名称到实际函数的映射 available_functions { “get_current_weather”: get_current_weather “calculator”: calculator “search_wikipedia”: search_wikipedia } def run_conversation(user_input: str model“gpt-3.5-turbo” max_turns5): “”” 运行一个支持工具调用的对话。 “”” messages [{“role”: “user” “content”: user_input}] # 初始化对话历史 turn_count 0 while turn_count max_turns: turn_count 1 print(f“\n[对话轮次 {turn_count}] 发送给模型的消息:”) # print(json.dumps(messages indent2 ensure_asciiFalse)) # 调试用 # 2. 调用Chat Completions API传入消息和工具定义 response client.chat.completions.create( modelmodel messagesmessages toolstools tool_choice“auto” # 让模型自行决定是否调用工具 ) response_message response.choices[0].message # print(f“模型原始响应: {response_message}”) # 调试用 # 3. 检查模型是否要求调用工具 tool_calls response_message.tool_calls if tool_calls: # 4. 模型要求调用工具 print(f“模型请求调用 {len(tool_calls)} 个工具。”) # 将模型的响应包含tool_calls添加到对话历史 messages.append(response_message) # 5. 遍历并执行每个被请求的工具 for tool_call in tool_calls: function_name tool_call.function.name function_to_call available_functions.get(function_name) if not function_to_call: # 如果请求的工具不存在返回错误信息 tool_response json.dumps({“error”: f“Function {function_name} not found”}) else: # 解析工具参数 function_args json.loads(tool_call.function.arguments) # 执行工具函数 function_response function_to_call(**function_args) tool_response function_response # 6. 将工具执行结果作为新消息添加到对话历史 messages.append({ “role”: “tool” “tool_call_id”: tool_call.id “content”: tool_response }) # 循环继续将包含工具结果的新历史再次发送给模型 else: # 7. 模型没有调用工具直接生成最终回复 print(“模型生成最终回复。”) final_response response_message.content messages.append({“role”: “assistant” “content”: final_response}) return final_response return “对话轮次过多已终止。” if __name__ “__main__”: # 测试不同的用户查询 test_queries [ “北京和上海的天气怎么样用摄氏度告诉我。” “计算一下圆周率乘以10的平方再加上15。” “搜索一下人工智能的发展历史。” “先查一下伦敦的天气用华氏度然后告诉我爱因斯坦的主要贡献是什么。” # 多工具调用测试 ] for query in test_queries: print(f“\n{‘’*50}”) print(f“用户查询: {query}”) print(f“{‘-‘*50}”) result run_conversation(query) print(f“\n助手回复: {result}”) print(f“{‘’*50}\n”)运行与观察在项目根目录创建.env文件写入OPENAI_API_KEYsk-你的密钥。在终端执行python main_openai.py。观察控制台输出你会清晰地看到“对话轮次”、“工具调用”和模型最终回复的完整流程。对于多工具请求如最后一个测试查询模型会规划顺序依次调用。4.4 使用LangChain框架重构 (main_langchain.py)LangChain将上述繁琐的对话历史管理、工具执行循环封装成了更简洁的接口。我们使用最新的LangChain版本0.1.0的LCELLangChain Expression Language语法。# main_langchain.py import os from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor create_tool_calling_agent from langchain_core.prompts import ChatPromptTemplate MessagesPlaceholder from langchain.tools import Tool from tools import get_current_weather calculator search_wikipedia from dotenv import load_dotenv load_dotenv() # 1. 将Python函数包装成LangChain Tool对象 tools [ Tool( name“Weather”, funcget_current_weather description“获取指定城市的当前天气信息。输入应包含’location’城市名和可选的’unit’’celsius’或’fahrenheit’。” ), Tool( name“Calculator”, funccalculator description“计算一个数学表达式。输入应为包含表达式的字符串例如 ‘3 5’ 或 ‘math.sqrt(9)’。” ), Tool( name“Wikipedia”, funcsearch_wikipedia description“搜索维基百科。输入应包含’query’搜索词和可选的’sentences’摘要句子数。” ), ] # 2. 初始化大模型 llm ChatOpenAI(model“gpt-3.5-turbo” temperature0 api_keyos.getenv(“OPENAI_API_KEY”)) # 3. 构建提示词模板 prompt ChatPromptTemplate.from_messages([ (“system” “你是一个乐于助人的助手可以调用工具来回答问题。请根据用户问题决定是否需要以及调用哪个工具。如果不需要工具请直接回答。”) MessagesPlaceholder(variable_name“chat_history”) # 预留位置存放历史消息 (“user” “{input}”) MessagesPlaceholder(variable_name“agent_scratchpad”) # 预留位置存放Agent的思考过程工具调用和结果 ]) # 4. 创建Agent agent create_tool_calling_agent(llm tools prompt) # 5. 创建Agent执行器 agent_executor AgentExecutor(agentagent toolstools verboseTrue handle_parsing_errorsTrue) # 6. 运行对话 if __name__ “__main__”: from langchain_core.messages import HumanMessage AIMessage chat_history [] # 用于存储多轮对话历史 def chat_with_agent(user_input: str): global chat_history print(f“\n用户: {user_input}”) # 调用执行器 result agent_executor.invoke({“input”: user_input “chat_history”: chat_history}) response result[“output”] print(f“助手: {response}”) # 更新对话历史 (简化处理实际生产环境需更精细管理) chat_history.append(HumanMessage(contentuser_input)) chat_history.append(AIMessage(contentresponse)) # 防止历史过长可在此处截断 if len(chat_history) 10: chat_history chat_history[-6:] # 保留最近3轮对话 return response # 测试 test_inputs [ “今天杭州的天气如何” “123乘以456等于多少” “告诉我Python编程语言是谁发明的。” ] for inp in test_inputs: chat_with_agent(inp)运行与对比 执行python main_langchain.py。你会看到LangChain以更结构化的方式输出每一步的思考verboseTrue时包括“Action”决定调用哪个工具、“Action Input”参数、“Observation”工具结果和“Final Answer”。代码量更少且更容易扩展到更复杂的Agent工作流。5. 进阶话题安全、本地模型与工程化掌握了基础用法后我们需要关注更实际的问题。5.1 AI红队视角工具调用的安全风险与防护赋予大模型调用工具的能力也打开了新的攻击面。从“AI红队”专注于AI系统安全的团队角度看主要风险包括工具滥用与越权风险模型被诱导调用高权限或危险工具如delete_databasesend_email。防护最小权限原则只为模型提供完成当前任务所必需的工具。工具沙箱化在隔离环境如Docker容器、无网络沙箱中执行不可信的工具调用。运行时鉴权在执行工具前增加一层基于用户身份、会话上下文的权限检查。敏感操作确认对于删除、发送、修改等操作要求人工确认或二次验证。提示注入与参数操纵风险攻击者通过精心设计的用户输入让模型将恶意参数传递给工具如SQL注入、命令注入。防护输入净化与验证在工具函数内部对所有输入参数进行严格的类型检查、长度限制、内容过滤如防止SQL特殊字符。使用参数化查询/安全API对于数据库、系统命令调用务必使用参数化查询如SQL的?占位符或安全的子进程调用库如subprocesswithshellFalse。避免eval如我们示例中的calculator函数生产环境必须替换为安全的表达式解析库。信息泄露风险工具返回的结果可能包含敏感信息如数据库错误信息、内部文件路径被模型泄露给用户。防护结果过滤在将工具结果返回给模型前过滤掉错误详情、堆栈跟踪、内部标识等敏感信息。统一错误处理返回给模型的错误信息应为用户友好的通用提示。资源耗尽与拒绝服务风险模型被诱导反复调用计算密集型或网络IO密集型工具耗尽系统资源。防护调用频率限制对每个用户/会话的工具调用次数、频率进行限制。超时控制为每个工具执行设置严格的超时时间。预算控制对涉及费用的工具如发送短信、调用付费API设置每日预算。安全增强的Tool Wrapper示例# secure_tools.py import time from functools import wraps from typing import Callable Any class ToolSecurityManager: def __init__(self): self.call_count {} self.last_call_time {} def rate_limit(self tool_name: str max_calls_per_minute: int 10): “””装饰器限制工具调用频率””” def decorator(func: Callable) - Callable: wraps(func) def wrapper(*args **kwargs): current_time time.time() key f“{tool_name}_{kwargs.get(‘user_id’ ‘default’)}” # 初始化或清理过期记录 if key not in self.call_count: self.call_count[key] [] # 移除一分钟前的记录 self.call_count[key] [t for t in self.call_count[key] if current_time - t 60] if len(self.call_count[key]) max_calls_per_minute: raise PermissionError(f“工具 {tool_name} 调用过于频繁请稍后再试。”) # 记录本次调用 self.call_count[key].append(current_time) return func(*args **kwargs) return wrapper return decorator def require_auth(self required_role: str): “””装饰器检查调用权限””” def decorator(func: Callable) - Callable: wraps(func) def wrapper(*args **kwargs): user_role kwargs.get(‘user_role’ ‘guest’) if user_role ! required_role: raise PermissionError(f“需要 {required_role} 权限才能执行此操作。”) # 移除装饰器添加的参数避免传递给原函数 kwargs.pop(‘user_role’ None) return func(*args **kwargs) return wrapper return decorator security_mgr ToolSecurityManager() security_mgr.rate_limit(tool_name“weather” max_calls_per_minute5) def secure_get_weather(location: str unit: str “celsius” user_id: str “unknown” **kwargs) - str: # 参数验证 if not location or len(location) 100: raise ValueError(“地点名称无效或过长。”) if unit not in [“celsius” “fahrenheit”]: raise ValueError(“温度单位必须是 ‘celsius’ 或 ‘fahrenheit’。”) # … 调用真实的天气API … return json.dumps({“temperature”: 22 “condition”: “Sunny”}) # 在定义给模型的工具时使用安全版本并通过描述告知模型需要的参数 secure_tools_for_model [ { “type”: “function” “function”: { “name”: “secure_get_weather” “description”: “获取天气。需要参数: location(字符串) unit(可选 ‘celsius’或’fahrenheit’)。调用时需提供user_id。” # … } } ]5.2 接入本地大模型Ollama LiteLLM对于数据敏感或希望控制成本的场景可以使用本地部署的模型。Ollama是一个流行的本地大模型运行工具而LiteLLM是一个统一的模型调用抽象层。# 首先安装Ollama并拉取一个模型例如Llama 3.1 # 访问 https://ollama.com/ 下载安装 # 在终端运行 ollama pull llama3.1 # 安装litellm它可以将Ollama的API模拟成OpenAI格式 pip install litellm# main_ollama.py import os from langchain_community.chat_models import ChatOllama from langchain.agents import create_tool_calling_agent AgentExecutor from langchain.tools import Tool from tools import calculator # 使用之前定义的工具 # 1. 使用LangChain的ChatOllama包装器 # 确保Ollama服务正在运行 (默认 http://localhost:11434) llm ChatOllama( model“llama3.1” # 你拉取的模型名称 temperature0 base_url“http://localhost:11434” # Ollama API地址 ) # 2. 定义工具同上 tools [ Tool( name“Calculator”, funccalculator description“计算数学表达式。” ), # 可以添加更多工具但注意本地模型可能对复杂工具调用的支持不如GPT-4 ] # 3. 创建Agent和执行器与OpenAI版本几乎相同 from langchain_core.prompts import ChatPromptTemplate MessagesPlaceholder prompt ChatPromptTemplate.from_messages([ (“system” “你是一个助手。请使用工具来帮助用户。如果不需要工具请直接回答。”) MessagesPlaceholder(variable_name“chat_history”) (“user” “{input}”) MessagesPlaceholder(variable_name“agent_scratchpad”) ]) agent create_tool_calling_agent(llm tools prompt) agent_executor AgentExecutor(agentagent toolstools verboseTrue handle_parsing_errorsTrue) # 4. 运行测试 result agent_executor.invoke({“input”: “计算一下 (15 27) * 3 等于多少”}) print(result[“output”])注意本地模型的工具调用能力特别是函数参数解析的准确性因模型而异。Llama 3.1、Qwen等较新模型支持较好但可能仍需更精确的提示词或微调。5.3 工程化最佳实践工具设计单一职责每个工具只做一件事。描述清晰工具的描述是模型理解的唯一依据务必准确、无歧义。强类型参数在JSON Schema中明确定义参数类型、枚举值和默认值。健壮性工具函数内部要有完善的错误处理和日志记录。系统架构状态管理对于多轮对话妥善管理对话历史、用户会话和工具调用状态。考虑使用数据库或Redis。异步处理对于耗时的工具调用如网络请求使用异步框架如asyncio FastAPI避免阻塞。可观测性记录所有工具调用的输入、输出、耗时和错误便于监控和调试。提示工程系统提示词在system消息中明确告知模型可用的工具及其用途并设定行为规范如“未经确认不得执行删除操作”。少样本学习在对话历史中提供几个正确使用工具的示例Few-Shot能显著提升模型调用工具的准确性。6. 常见问题与排查思路在开发过程中你可能会遇到以下典型问题问题现象可能原因排查步骤与解决方案模型不调用工具直接回答1. 工具描述不清晰或与问题不匹配。2. 模型能力不足如使用gpt-3.5-turbo处理复杂任务。3. 系统提示词未引导模型使用工具。1. 优化工具description使其更贴近自然语言查询。2. 升级到更强的模型如gpt-4-turbo。3. 在system提示中明确指令如“请优先使用工具来获取准确信息”。模型调用了错误的工具或参数1. 工具间描述相似导致混淆。2. 参数description不明确。3. 用户查询存在歧义。1. 区分工具描述突出其独特用途。2. 在参数描述中提供示例值。3. 考虑让模型与用户进行澄清性对话多轮交互。解析工具参数时JSON解码错误1. 模型生成的arguments字符串不是合法JSON。2. 字符串中包含未转义的特殊字符。1. 使用json.loads()时增加strictFalse参数或进行try-catch。2. 在调用模型时可以尝试设置response_format{ “type”: “json_object” }部分模型支持来约束输出格式。工具执行超时或失败1. 工具函数本身有bug或依赖服务不可用。2. 网络问题。3. 资源不足。1. 为工具调用添加超时和重试机制。2. 记录详细的错误日志包括输入参数和异常堆栈。3. 实现熔断器模式避免连续失败拖垮系统。对话历史过长导致API令牌超限或性能下降1. 未对历史消息进行摘要或截断。2. 工具调用轮次过多。1. 实现历史消息的摘要功能将过去的对话压缩成一段总结性文字。2. 设置最大历史轮次保留最近的N条消息。3. 使用支持更长上下文的模型。使用本地模型时工具调用格式错误1. 本地模型未对齐OpenAI的tool_calls格式。2. 提示词未针对本地模型优化。1. 使用litellm这类兼容层来标准化API格式。2. 查阅该本地模型关于工具调用的特定文档调整提示词和输出解析逻辑。7. 总结与展望工具调用技术是大模型从“对话者”迈向“执行者”的核心桥梁。通过本文的梳理你应该已经掌握了核心原理理解了工具调用的基本流程——定义、识别、执行、整合。动手能力能够使用OpenAI原生API和LangChain框架构建一个具备多工具调用能力的AI助手。安全意识从AI红队视角认识了工具调用可能带来的风险并学习了基础的防护策略如权限控制、输入验证和频率限制。扩展思路了解了如何接入本地大模型以及工程化开发中需要考虑的状态管理、异步处理和可观测性。下一步的学习方向深入Agent框架探索更复杂的Agent架构如ReAct、Plan-and-Execute、Multi-Agent系统。LangGraph是构建有状态、多分支工作流的强大工具。工具学习研究如何让大模型自动学习使用新工具的文档甚至通过少量示例生成工具的描述和参数模式。评估与测试建立对工具调用系统的评估体系包括工具选择准确率、参数填充正确率、任务完成度等。与RAG结合将工具调用与检索增强生成结合让模型既能利用外部知识库又能执行具体操作构建更强大的应用。工具调用正在快速演进从简单的函数调用走向复杂的工作流编排。掌握这项技术意味着你能让大模型真正融入现有的软件生态系统自动化处理那些需要认知判断与实际行动相结合的任务。
返回列表