Python AI Agent 零基础教程 | 第8篇:工具调用——扩展AI Agent的能力
前言
前面的教程中,我们的 AI Agent 只能"聊天"。但真正强大的 AI Agent 应该能像人一样使用工具:查天气、搜信息、执行代码、读写文件等。
今天我们就来学习如何给 AI Agent 装上"双手",让它能够调用各种工具!
一、什么是工具调用?
1.1 生活中的工具调用
想象你要搬家,你会怎么做?
没有工具的 AI:
Python 代码
你:帮我搬家
AI:我很想帮你,但我搬不了...
有工具的 AI:
Python 代码
你:帮我搬家
AI:好的!我来帮你:
- 📦 预约搬家公司
- 📋 打包行李
- 🚚 安排运输
- ✅ 验收完成
搬家任务已完成!
1.2 工具调用的原理
Python 代码
┌─────────────────────────────────────────────────────────────┐
│ 工具调用流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户 ──▶ "北京今天天气怎么样" │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 理解意图 │ ← AI 判断需要调用工具 │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 调用工具 │ ← 调用天气 API │
│ │ get_weather() │ │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 获取结果 │ ← "晴,25°C" │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ 返回给用户:"北京今天晴,25°C" │
│ │
└─────────────────────────────────────────────────────────────┘
1.3 工具调用的优势
| 能力 | 没有工具 | 有工具 |
|---|
| 查天气 | ❌ 不能 | ✅ 可以 |
| 搜信息 | ❌ 不能 | ✅ 可以 |
| 执行代码 | ❌ 不能 | ✅ 可以 |
| 读写文件 | ❌ 不能 | ✅ 可以 |
| 发邮件 | ❌ 不能 | ✅ 可以 |
---
二、简单工具调用实现
2.1 定义工具函数
Python 代码
import requests
#定义工具函数
def get_weather(city):
"""获取天气信息"""
# 这里简化处理,实际需要调用天气 API
weather_data = {
"北京": {"weather": "晴", "temp": 25, "humidity": 50},
"上海": {"weather": "多云", "temp": 23, "humidity": 65},
"广州": {"weather": "雨", "temp": 20, "humidity": 80},
}
return weather_data.get(city, {"weather": "未知", "temp": 0, "humidity": 0})
def search_web(query):
"""搜索网络"""
# 这里简化处理,实际需要调用搜索引擎
return f"关于「{query}」的搜索结果:...\n1. 相关链接1\n2. 相关链接2\n3. 相关链接3"
def calculate(expression):
"""计算器"""
try:
result = eval(expression)
return f"计算结果:{expression} = {result}"
except:
return "计算表达式无效"
#工具注册表
TOOLS = {
"get_weather": {
"function": get_weather,
"description": "获取指定城市的天气信息",
"parameters": {
"city": "城市名称(必填)"
}
},
"search_web": {
"function": search_web,
"description": "搜索网络获取信息",
"parameters": {
"query": "搜索关键词(必填)"
}
},
"calculate": {
"function": calculate,
"description": "执行数学计算",
"parameters": {
"expression": "计算表达式(必填)"
}
}
}
2.2 工具调用 Agent
Python 代码
class ToolAgent:
"""工具调用 Agent"""
def __init__(self, api_key):
self.api_key = api_key
self.tools = {}
self.messages = []
# 系统提示词
self.messages.append({
"role": "system",
"content": """你是一个智能助手,可以通过工具来完成任务。
可用的工具:
- get_weather(city) - 获取城市天气
- search_web(query) - 搜索网络
- calculate(expression) - 数学计算
当用户的问题需要使用工具时,你应该调用相应的工具。
格式:调用工具时,在回复中说明要使用的工具和参数。"""
})
def register_tool(self, name, func, description):
"""注册工具"""
self.tools[name] = {
"function": func,
"description": description
}
print(f"✅ 工具已注册:{name}")
def think(self, user_input):
"""思考"""
self.messages.append({"role": "user", "content": user_input})
# 调用 API
response = self._call_api()
# 检查是否需要调用工具
ai_message = response["choices"][0]["message"]
content = ai_message["content"]
# 检查回复中是否包含工具调用
if "get_weather" in content or "search_web" in content or "calculate" in content:
# 解析并执行工具
result = self._execute_tool_from_response(content)
content = result
self.messages.append({"role": "assistant", "content": content})
return content
def _call_api(self):
url = "https://api.openai.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
data = {
"model": "gpt-3.5-turbo",
"messages": self.messages
}
response = requests.post(url, headers=headers, json=data)
return response.json()
def _execute_tool_from_response(self, response):
"""从响应中解析并执行工具"""
# 简化版:检测关键词
if "get_weather" in response and "北京" in response:
city = self._extract_param(response, "北京", "上海", "广州")
if city:
result = self.tools["get_weather"]["function"](city)
return f"【工具调用结果】\n{city}的天气:{result}"
if "search_web" in response:
query = self._extract_query(response)
if query:
result = self.tools["search_web"]["function"](query)
return f"【搜索结果】\n{result}"
if "calculate" in response:
expr = self._extract_expression(response)
if expr:
result = self.tools["calculate"]["function"](expr)
return f"【计算结果】\n{result}"
return response
def _extract_param(self, text, *keywords):
"""提取关键词"""
for kw in keywords:
if kw in text:
return kw
return None
def _extract_query(self, text):
"""提取搜索词"""
# 简化处理
return "相关信息"
def _extract_expression(self, text):
"""提取计算表达式"""
# 简化处理
return "2+3*5"
三、使用 OpenAI Function Calling
3.1 什么是 Function Calling?
OpenAI 提供了原生的函数调用功能,可以更规范地实现工具调用。
Python 代码
import openai
#配置
openai.api_key = "sk-xxxxxx"
#定义工具(函数)
functions = [
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如:北京、上海、广州"
}
},
"required": ["city"]
}
},
{
"name": "search_information",
"description": "搜索网络获取信息",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
}
},
"required": ["query"]
}
},
{
"name": "calculate",
"description": "执行数学计算",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如:2+3*5"
}
},
"required": ["expression"]
}
}
]
3.2 Function Calling Agent
Python 代码
class FunctionCallingAgent:
"""使用 Function Calling 的 Agent"""
def __init__(self, api_key):
self.client = openai.OpenAI(api_key=api_key)
self.messages = []
self.functions = functions
# 工具实现
self.tools_impl = {
"get_weather": self._get_weather,
"search_information": self._search_information,
"calculate": self._calculate
}
def _get_weather(self, city):
"""天气查询实现"""
weather_data = {
"北京": {"weather": "晴☀️", "temp": 25, "humidity": 45},
"上海": {"weather": "多云⛅", "temp": 23, "humidity": 65},
"广州": {"weather": "雨🌧️", "temp": 20, "humidity": 80},
"深圳": {"weather": "晴☀️", "temp": 28, "humidity": 55},
"杭州": {"weather": "阴🌤️", "temp": 22, "humidity": 60},
}
info = weather_data.get(city, {"weather": "未知", "temp": 0, "humidity": 0})
return f"{city}今天天气{info['weather']},温度{info['temp']}°C,湿度{info['humidity']}%"
def _search_information(self, query):
"""搜索实现"""
return f"关于「{query}」的搜索结果:\n1. 相关链接1\n2. 相关链接2\n3. 相关链接3\n\n(这是模拟数据)"
def _calculate(self, expression):
"""计算实现"""
try:
result = eval(expression)
return f"计算结果:{expression} = {result}"
except Exception as e:
return f"计算错误:{str(e)}"
def think(self, user_input, max_turns=5):
"""思考(支持多轮工具调用)"""
self.messages.append({"role": "user", "content": user_input})
for turn in range(max_turns):
# 调用 API
response = self.client.chat.completions.create(
model="gpt-3.5-turbo",
messages=self.messages,
tools=[{"type": "function", "function": f} for f in self.functions],
tool_choice="auto"
)
message = response.choices[0].message
# 检查是否有工具调用
if message.tool_calls:
# 添加 AI 的工具调用消息
self.messages.append({
"role": "assistant",
"content": message.content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments
}
}
for tc in message.tool_calls
]
})
# 执行工具
for tool_call in message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"🔧 调用工具:{func_name}({func_args})")
# 执行工具
result = self.tools_impl[func_name](**func_args)
# 添加工具结果
self.messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
# 继续下一轮
continue
# 没有工具调用,返回结果
if message.content:
self.messages.append({"role": "assistant", "content": message.content})
return message.content
return "抱歉,处理超时"
3.3 使用示例
Python 代码
#创建 Agent
agent = FunctionCallingAgent("sk-xxxxxx")
#对话
print("🤖 Agent: 你好!有什么我可以帮你的?\n")
#天气查询
response = agent.think("北京今天天气怎么样?")
print(f"\n🤖 Agent: {response}\n")
#计算
response = agent.think("帮我计算 (25 + 15) * 2 等于多少?")
print(f"\n🤖 Agent: {response}\n")
#搜索
response = agent.think("帮我搜索一下 Python 入门教程")
print(f"\n🤖 Agent: {response}\n")
四、实战:多功能助手
4.1 完整工具助手代码
Python 代码
import requests
import json
from datetime import datetime
class ToolAssistant:
"""多功能工具助手"""
def __init__(self, api_key):
self.client = openai.OpenAI(api_key=api_key)
self.messages = []
self.tools = self._define_tools()
def _define_tools(self):
"""定义工具"""
return [
{
"name": "get_weather",
"description": "获取城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
},
{
"name": "get_time",
"description": "获取当前时间",
"parameters": {
"type": "object",
"properties": {}
}
},
{
"name": "calculate",
"description": "执行数学计算",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如 2+3*5"
}
},
"required": ["expression"]
}
},
{
"name": "send_email",
"description": "发送邮件",
"parameters": {
"type": "object",
"properties": {
"to": {"type": "string", "description": "收件人邮箱"},
"subject": {"type": "string", "description": "邮件主题"},
"body": {"type": "string", "description": "邮件内容"}
},
"required": ["to", "subject", "body"]
}
},
{
"name": "create_reminder",
"description": "创建提醒事项",
"parameters": {
"type": "object",
"properties": {
"content": {"type": "string", "description": "提醒内容"},
"time": {"type": "string", "description": "提醒时间"}
},
"required": ["content", "time"]
}
}
]
def _execute_tool(self, name, args):
"""执行工具"""
if name == "get_weather":
return self._get_weather(args.get("city"))
elif name == "get_time":
return self._get_time()
elif name == "calculate":
return self._calculate(args.get("expression"))
elif name == "send_email":
return self._send_email(args.get("to"), args.get("subject"), args.get("body"))
elif name == "create_reminder":
return self._create_reminder(args.get("content"), args.get("time"))
else:
return f"未知工具:{name}"
def _get_weather(self, city):
"""天气查询"""
# 简化实现
weather_db = {
"北京": {"weather": "晴", "temp": 26, "feel": 28},
"上海": {"weather": "多云", "temp": 24, "feel": 26},
"广州": {"weather": "雷阵雨", "temp": 27, "feel": 30},
"深圳": {"weather": "晴", "temp": 29, "feel": 32}
}
if city in weather_db:
info = weather_db[city]
return f"{city}天气{info['weather']},气温{info['temp']}°C,体感温度{info['feel']}°C"
return f"抱歉,暂不支持查询{city}的天气"
def _get_time(self):
"""获取时间"""
now = datetime.now()
return f"现在是{now.strftime('%Y年%m月%d日 %H:%M:%S')}"
def _calculate(self, expression):
"""计算器"""
try:
result = eval(expression)
return f"{expression} = {result}"
except:
return f"无法计算:{expression}"
def _send_email(self, to, subject, body):
"""发送邮件(模拟)"""
return f"📧 邮件已发送!\n收件人:{to}\n主题:{subject}\n内容:{body[:50]}..."
def _create_reminder(self, content, time):
"""创建提醒(模拟)"""
return f"✅ 提醒已创建!\n内容:{content}\n时间:{time}"
def think(self, user_input, max_turns=5):
"""思考"""
self.messages.append({"role": "user", "content": user_input})
for turn in range(max_turns):
response = self.client.chat.completions.create(
model="gpt-3.5-turbo",
messages=self.messages,
tools=[{"type": "function", "function": f} for f in self.tools],
tool_choice="auto"
)
message = response.choices[0].message
# 有工具调用
if message.tool_calls:
self.messages.append({
"role": "assistant",
"content": message.content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments
}
}
for tc in message.tool_calls
]
})
for tool_call in message.tool_calls:
name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
print(f"🔧 调用工具:{name}")
result = self._execute_tool(name, args)
self.messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
continue
# 返回结果
if message.content:
self.messages.append({"role": "assistant", "content": message.content})
return message.content
return "处理超时"
def reset(self):
"""重置对话"""
self.messages = [{
"role": "system",
"content": "你是一个智能助手,可以通过调用工具来帮助用户完成任务。"
}]
print("✅ 对话已重置")
4.2 运行效果
Python 代码
#创建助手
assistant = ToolAssistant("sk-xxxxxx")
#测试各种工具调用
print("="*60)
print("🔧 多功能助手测试")
print("="*60)
#测试天气
print("\n📌 测试天气查询:")
response = assistant.think("北京今天天气怎么样?需要带伞吗?")
print(f"🤖: {response}")
#测试时间
print("\n📌 测试时间查询:")
response = assistant.think("现在几点了?")
print(f"🤖: {response}")
#测试计算
print("\n📌 测试计算:")
response = assistant.think("帮我计算一下 365 * 24 小时等于多少天?")
print(f"🤖: {response}")
#测试提醒
print("\n📌 测试提醒:")
response = assistant.think("明天下午3点提醒我开会")
print(f"🤖: {response}")
五、常用工具模板
5.1 文件操作工具
Python 代码
class FileTools:
"""文件操作工具集"""
@staticmethod
def read_file(path):
"""读取文件"""
try:
with open(path, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
return f"读取失败:{str(e)}"
@staticmethod
def write_file(path, content):
"""写入文件"""
try:
with open(path, 'w', encoding='utf-8') as f:
f.write(content)
return f"文件已保存:{path}"
except Exception as e:
return f"写入失败:{str(e)}"
@staticmethod
def list_files(directory):
"""列出目录文件"""
import os
try:
files = os.listdir(directory)
return "文件列表:\n" + "\n".join(files)
except Exception as e:
return f"列出失败:{str(e)}"
5.2 API 请求工具
Python 代码
class WebTools:
"""网络工具集"""
@staticmethod
def http_get(url, params=None):
"""GET 请求"""
try:
response = requests.get(url, params=params, timeout=10)
return response.text[:500] # 限制返回长度
except Exception as e:
return f"请求失败:{str(e)}"
@staticmethod
def http_post(url, data=None):
"""POST 请求"""
try:
response = requests.post(url, json=data, timeout=10)
return response.text[:500]
except Exception as e:
return f"请求失败:{str(e)}"
@staticmethod
def search_baidu(query):
"""百度搜索"""
url = "https://www.baidu.com/s"
params = {"wd": query}
return WebTools.http_get(url, params)
六、本章小结
今天我们学习了:
| 内容 | 说明 |
|---|
| ✅ 工具调用原理 | AI 理解意图 → 调用工具 → 返回结果 |
| ✅ 简单工具实现 | 关键词检测 + 函数调用 |
| ✅ Function Calling | OpenAI 原生工具调用 API |
| ✅ 多功能助手 | 集成多种工具的完整 Agent |
| ✅ 工具模板 | 文件操作、网络请求等常用工具 |
---
下期预告
第9篇:实战项目——构建智能客服 Agent
下一期我们将综合运用所学知识,构建一个完整的智能客服系统!
👨💻 作者:鹏鹏 | 专注于 AI + 编程教育
📱 关注公众号「跟着鹏鹏学技术」
💬 动手练习:给你的 Agent 添加天气查询工具!
往期精选
- 📖 [第7篇:记忆系统]
- 📖 [第6篇:提示词工程]
- 📖 [第5篇:构建第一个AI Agent]
👨💻 作者:鹏鹏
📱 关注公众号「跟着鹏鹏学技术」
🔔 点赞 + 在看,让更多人看到!