第11章 构建具备工具调用能力的智能Agent
本项目构建了一个基于ReAct框架的智能Agent,能够理解用户意图并调用外部工具完成任务。核心内容包括: 技术架构:采用ReAct框架(推理-行动-观察循环)和Function Calling技术,实现LLM与外部工具的交互。 核心功能: 定义天气查询和数学计算两种工具 开发Agent执行循环,管理工具调用和结果反馈 实现步骤: 通过JSON Schema定义工具清单 构建工具映射和函数调用机制
1. 项目概述
在第一个项目中,我们构建了一个“知识型”的问答机器人。然而,现实世界中的许多任务不仅需要知识,还需要执行动作(Action),例如查询实时信息、操作数据库、调用服务API等。本项目将带领你构建一个更高级的AI形态——智能Agent (Intelligent Agent)。
核心目标:
开发一个能够理解用户意图,并自主选择、调用外部工具(API)来完成特定任务的AI Agent。我们将以一个“智能助理”为应用场景,它能够回答实时天气和进行数学计算。
你将学习到的核心技术:
- Agentic Thinking (智能体思维):理解Agent的核心工作原理,特别是**ReAct (Reason + Act)**框架。
- Function Calling / Tool Calling:掌握如何让LLM生成结构化的函数调用请求,这是实现工具调用的关键技术。
- API集成与封装:学会如何将真实的外部API(无论是你自己的服务还是第三方服务)封装成LLM可以理解和使用的“工具”。
- Agent执行循环 (Execution Loop):编写代码来管理Agent的“思考-行动”循环,处理工具调用、结果返回和最终回复生成的全过程。
项目整体流程图
2. 核心概念:ReAct框架与Function Calling
2.1 ReAct框架
ReAct是Google提出的一个将LLM的推理 (Reasoning) 能力和行动 (Acting) 能力相结合的强大框架。它模仿人类解决问题的过程:
- Thought (思考):LLM首先分析当前任务和已有信息,思考下一步需要做什么。
- Action (行动):根据思考结果,LLM决定调用哪个工具,并生成调用该工具所需的参数。
- Observation (观察):执行工具后,系统将工具返回的结果(例如API的响应)作为“观察”信息,反馈给LLM。
LLM会重复这个“思考-行动-观察”的循环,直到它认为已经收集到足够的信息来回答用户最初的问题为止,然后生成最终答案。
2.2 Function Calling / Tool Calling
这是让ReAct框架落地的核心技术。现代的LLM(如OpenAI的GPT系列、Google的Gemini、Qwen等)都支持Function Calling功能。其工作流程如下:
- 定义工具:在向LLM发起请求时,我们不仅提供用户的提问,还提供一份详细的“工具清单”。这份清单用JSON Schema的格式描述了每个工具的名称、功能说明、以及所需的参数(参数名、类型、是否必需等)。
- LLM决策:LLM在理解用户问题后,会判断是否需要调用工具。如果需要,它会从清单中选择最合适的工具,并生成一个包含工具名和具体参数的JSON对象。
- 代码执行:我们的后端代码接收到这个JSON后,解析出工具名和参数,然后执行本地对应的函数(例如,调用真实的天气API)。
- 结果返回:将函数执行的结果(如天气信息)再发送给LLM,让它继续下一步的思考或生成最终回复。
3. 项目实战:构建智能助理Agent
3.1 环境准备
我们将使用OpenAI的API作为Agent的核心,因为它具有非常成熟和强大的Function Calling能力。你也可以使用支持此功能的其他模型API。
!pip install -q openai
3.2 定义工具(函数)
我们来定义两个本地函数,一个用于获取天气,一个用于计算。这些函数将作为我们的“工具”。
import json
# 工具1:获取实时天气
def get_current_weather(location: str, unit: str = "celsius"):
"""获取指定地点的实时天气信息"""
if "tokyo" in location.lower():
return json.dumps({"location": "Tokyo", "temperature": "10", "unit": unit})
elif "san francisco" in location.lower():
return json.dumps({"location": "San Francisco", "temperature": "72", "unit": unit})
elif "paris" in location.lower():
return json.dumps({"location": "Paris", "temperature": "22", "unit": unit})
else:
return json.dumps({"location": location, "temperature": "unknown"})
# 工具2:计算器
def calculator(expression: str):
"""计算一个数学表达式的值"""
try:
# 使用eval是简化的做法,在生产环境中需要更安全的数学表达式解析器
result = eval(expression)
return json.dumps({"result": result})
except Exception as e:
return json.dumps({"error": str(e)})
3.3 构建Agent执行循环
这是Agent的核心逻辑。我们将编写一个循环,来处理与LLM的交互、工具调用和结果反馈。
import os
from openai import OpenAI
# 确保你的OpenAI API密钥已设置为环境变量
# os.environ["OPENAI_API_KEY"] = "sk-..."
client = OpenAI()
# 步骤1:定义工具清单,供模型选择
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "获取指定地点的实时天气信息",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,例如:San Francisco",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
},
{
"type": "function",
"function": {
"name": "calculator",
"description": "计算一个数学表达式的值",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "要计算的数学表达式,例如:'5*2+10'",
},
},
"required": ["expression"],
},
},
}
]
# 将本地函数映射到工具名
available_functions = {
"get_current_weather": get_current_weather,
"calculator": calculator,
}
def run_agent(user_prompt):
print(f"\n--- 用户提问: {user_prompt} ---")
messages = [{"role": "user", "content": user_prompt}]
# 第一次调用模型
response = client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=messages,
tools=tools,
tool_choice="auto",
)
response_message = response.choices[0].message
messages.append(response_message) # 将模型的回复加入历史记录
# 步骤2:检查模型是否决定调用工具
tool_calls = response_message.tool_calls
while tool_calls:
print(f"--- 模型决策: 调用工具 {', '.join([tc.function.name for tc in tool_calls])} ---")
# 步骤3:执行工具调用
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
print(f"--- 正在执行: {function_name}({function_args}) ---")
function_response = function_to_call(**function_args)
print(f"--- 工具返回: {function_response} ---")
# 将工具调用的结果加入历史记录
messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
}
)
# 步骤4:再次调用模型,并附上工具返回的结果
print("--- 将工具结果返回给模型,让其继续思考 ---")
second_response = client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=messages,
tools=tools,
tool_choice="auto",
)
response_message = second_response.choices[0].message
messages.append(response_message)
tool_calls = response_message.tool_calls
# 如果模型不再调用工具,则其最后的回复就是最终答案
final_answer = response_message.content
print(f"\n--- Agent最终回复: {final_answer} ---")
return final_answer
# --- 运行Agent ---
run_agent("旧金山现在多少度?")
run_agent("东京10摄氏度,那换算成华氏度是多少?提示:F = C * 9/5 + 32")
3.4 运行结果分析
当你运行run_agent("东京10摄氏度,那换算成华氏度是多少?提示:F = C * 9/5 + 32")
时,你会看到一个清晰的ReAct流程:
- 用户提问:
东京10摄氏度,那换算成华氏度是多少?提示:F = C * 9/5 + 32
- 模型第一次思考:模型发现它需要进行计算,但它自己不会算。它看到
calculator
工具可以帮助它。 - 模型行动:模型决定调用
calculator
工具,并生成调用参数{"expression": "10 * 9/5 + 32"}
。 - 代码执行:我们的Python代码执行
calculator('10 * 9/5 + 32')
,得到结果50.0
。 - 观察:工具返回结果
{"result": 50.0}
。 - 模型第二次思考:模型收到了计算结果,现在它知道了答案。
- 生成最终回复:模型组织语言,生成最终答案:“东京10摄氏度换算成华氏度是50.0度。”
4. 总结与展望
本项目通过一个简单的智能助理,完整地展示了如何构建一个基于ReAct框架和Function Calling的智能Agent。这是通向更高级AI应用(如自主软件工程师、AI游戏角色、自动化流程机器人)的基石。
可以探索的扩展方向:
- 更复杂的工具:集成数据库查询工具、代码执行工具、甚至是发送邮件的工具。
- 多步推理:设计需要多次不同工具调用才能解决的复杂问题,观察Agent的规划能力。
- Agent框架:学习使用
LangChain
或LlamaIndex
等成熟的Agent开发框架,它们封装了Agent的执行循环、工具管理、记忆模块等,能极大提高开发效率。 - Agent的微调:对于特定领域的Agent,可以微调模型以提升其工具选择和使用能力,但这通常需要高质量的Agent轨迹数据(Thought-Action-Observation序列)。
更多推荐
所有评论(0)