AI Agent 工具调用(Tool Use)实战指南
工具调用(Tool Use / Function Calling)是 AI Agent 从"会思考"到"能动手"的关键能力。本文将从原理到实战,全面讲解如何为 Agent 设计、注册和调用工具。
一、什么是工具调用?
工具调用是指 LLM 根据用户输入,主动判断需要调用哪个外部函数/API,并生成结构化参数,由外部系统执行后将结果返回给模型。
用户:"北京今天天气怎么样?" |LLM 分析:需要查询天气 -> 调用 weather_api(city="北京", date="今天") |外部系统执行 API -> 返回 {"temperature": 25, "condition": "晴"} |LLM 生成回复:"北京今天天气晴朗,气温25度。"二、工具的核心结构
一个标准的工具定义包含:
字段 说明 | 示例 ------------|------name工具名称(英文,无空格) |get_weatherdescription功能描述(影响模型决策) | "获取指定城市的天气信息"parameters参数定义(JSON Schema) |{"city": {"type": "string"}}function实际执行函数 |def get_weather(city): ...
三、OpenAI Function Calling 基础
1. 定义工具
import jsontools = [ { "type": "function", "function": { "name": "get_weather", "description": "获取指定城市的当前天气信息", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,如'北京'、'上海'" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位" } }, "required": ["city"] } } }]
2. 调用流程
from openai import OpenAIclient = OpenAI()
第一轮:模型决定是否调用工具
response = client.chat.completions.create( model="gpt-4", messages=[{"role": "user", "content": "北京今天多少度?"}], tools=tools, tool_choice="auto")
message = response.choices[0].message
如果模型决定调用工具
if message.tool_calls: tool_call = message.tool_calls[0] function_name = tool_call.function.name arguments = json.loads(tool_call.function.arguments) print(f"模型决定调用: {function_name}") print(f"参数: {arguments}") # 输出:get_weather, {'city': '北京', 'unit': 'celsius'} # 执行函数(实际业务逻辑) result = {"temperature": 25, "condition": "晴朗", "city": arguments["city"]} # 第二轮:将结果返回给模型 response2 = client.chat.completions.create( model="gpt-4", messages=[ {"role": "user", "content": "北京今天多少度?"}, {"role": "assistant", "content": None, "tool_calls": [tool_call]}, {"role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result)} ], tools=tools ) print(response2.choices[0].message.content) # 输出:北京今天天气晴朗,气温25摄氏度。
四、LangChain 工具封装
LangChain 提供了更高级的工具封装,让开发更简单。
1. 使用 @tool 装饰器
from langchain.tools import tool@tooldef search_web(query: str) -> str: """使用搜索引擎查找互联网上的信息。 Args: query: 搜索关键词 """ # 实际实现:调用搜索API return f"搜索结果:关于 '{query}' 的相关信息..."
@tooldef calculate(expression: str) -> str: """执行数学计算表达式。 Args: expression: 数学表达式,如 '2 + 3 * 4' """ try: return str(eval(expression)) except Exception as e: return f"计算错误: {e}"
工具会自动解析函数名、参数和描述
print(search_web.name) # search_webprint(search_web.description) # 函数docstring
2. 自定义工具类
from langchain.tools import BaseToolfrom pydantic import BaseModel, Fieldclass WeatherInput(BaseModel): city: str = Field(description="城市名称") date: str = Field(description="日期,格式YYYY-MM-DD", default="today")
class WeatherTool(BaseTool): name = "get_weather" description = "获取指定城市的天气信息" args_schema = WeatherInput def _run(self, city: str, date: str = "today") -> str: # 调用天气API return f"{city} {date} 天气:晴,25C" async def _arun(self, city: str, date: str = "today") -> str: # 异步实现 return self._run(city, date)
weather_tool = WeatherTool()
五、实战:构建工具Agent
from langchain_openai import ChatOpenAIfrom langchain.agents import create_tool_calling_agent, AgentExecutorfrom langchain_core.prompts import ChatPromptTemplatefrom langchain.tools import toolimport requests1. 定义工具
@tooldef get_baidu_index(keyword: str) -> str: """获取百度指数搜索趋势数据(模拟)""" return f"关键词 '{keyword}' 近30天搜索指数呈上升趋势,日均搜索量约5000次。"
@tooldef translate(text: str, target_lang: str = "en") -> str: """将文本翻译成目标语言""" return f"[翻译结果] {text} -> {target_lang}: Translated content here"
@tooldef read_file(path: str) -> str: """读取本地文件内容""" try: with open(path, 'r', encoding='utf-8') as f: return f.read()[:1000] # 限制长度 except Exception as e: return f"读取失败: {e}"
tools = [get_baidu_index, translate, read_file]
2. 创建Agent
llm = ChatOpenAI(model="gpt-4", temperature=0)
prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个智能助手,可以使用工具帮助用户解决问题。"), ("placeholder", "{chat_history}"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}")])
agent = create_tool_calling_agent(llm, tools, prompt)executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
3. 运行测试
executor.invoke({"input": "'AI Agent'这个关键词的搜索热度怎么样?顺便把它翻译成英文。"})
六、工具设计最佳实践
1. 描述要清晰
# 不好的描述description = "搜索工具"好的描述
description = "用于在互联网上搜索实时信息,包括新闻、天气、股价、技术文档等。当用户询问需要最新数据的问题时,应该使用此工具。"
2. 参数设计要简洁
# 参数过多过复杂{"name": "api", "params": "{"type":"weather","city":"xxx","date":"xxx"}"}扁平化参数
{"city": "北京", "date": "2025-01-15"}
3. 处理工具执行错误
def safe_tool_execute(tool_func, kwargs): try: result = tool_func(kwargs) return {"status": "success", "result": result} except Exception as e: return {"status": "error", "error": str(e), "hint": "请检查参数是否正确"}4. 工具权限控制
class PermissionedTool: def __init__(self, tool, allowed_users=None): self.tool = tool self.allowed_users = allowed_users or [] def run(self, user_id, kwargs): if user_id not in self.allowed_users: return "错误:您没有权限使用此工具" return self.tool.run(kwargs)七、总结
工具调用是 Agent 的"手",让模型从纯文本推理走向实际操作。掌握工具设计、注册和调用的方法,是构建实用 Agent 的必备技能。记住:好的工具描述胜过复杂的代码,模型的决策质量很大程度上取决于你如何描述工具的能力。
---
下一篇将介绍多Agent协作系统,探索如何让多个Agent分工合作完成复杂任务。