本篇属于「AI Agent 开发实战系列」第 4 篇
前言
前三篇我们学习了 AI Agent 的核心概念、ReAct 模式原理,以及 MCP 协议的基础。现在是时候动手了------本篇将从零开始,一步步构建一个完整的、可工作的 AI Agent 应用。
这个 Agent 会具备以下能力:
- 理解用户意图
- 调用外部工具(天气查询、计算器、网络搜索)
- 进行推理和规划
- 返回有意义的结果
我们会使用 Python + LangChain + Claude API 来实现,代码简洁易懂,适合初学者。
核心概念回顾
Agent 的三个关键组件
- LLM(大语言模型):大脑,负责理解和推理
- Tools(工具集):手臂,执行具体操作
- Memory(记忆):神经,保存上下文和历史
ReAct 循环
scss
用户输入 → 思考(Thought) → 行动(Action) → 观察(Observation) → 循环
环境准备
1. 安装依赖
bash
# 创建虚拟环境
python3 -m venv agent-env
source agent-env/bin/activate
# 安装必要的包
pip install langchain langchain-anthropic python-dotenv requests
2. 配置 API Key
创建 .env 文件:
env
ANTHROPIC_API_KEY=your_api_key_here
3. 验证环境
python
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
response = llm.invoke("Hello, are you ready to be an agent?")
print(response.content)
第一步:定义工具集
Agent 需要一套工具来与外部世界交互。我们定义三个基础工具:
python
import json
import requests
from typing import Any
from langchain_core.tools import tool
# 工具1:计算器
@tool
def calculator(expression: str) -> str:
"""
执行数学计算。
Args:
expression: 数学表达式,如 "2 + 2" 或 "sqrt(16)"
Returns:
计算结果
"""
try:
# 使用 eval 需要谨慎,生产环境应使用更安全的方式
result = eval(expression)
return f"计算结果:{result}"
except Exception as e:
return f"计算错误:{str(e)}"
# 工具2:天气查询(模拟)
@tool
def get_weather(city: str) -> str:
"""
查询指定城市的天气。
Args:
city: 城市名称
Returns:
天气信息
"""
# 这里使用模拟数据,实际应调用真实 API
weather_data = {
"北京": "晴天,温度 15°C,风力 3 级",
"上海": "多云,温度 18°C,风力 2 级",
"深圳": "晴天,温度 22°C,风力 2 级",
"杭州": "阴天,温度 16°C,风力 4 级"
}
return weather_data.get(city, f"暂无 {city} 的天气数据")
# 工具3:网络搜索(模拟)
@tool
def search_web(query: str) -> str:
"""
搜索网络信息。
Args:
query: 搜索关键词
Returns:
搜索结果摘要
"""
# 模拟搜索结果
search_results = {
"Python": "Python 是一种高级编程语言,以其简洁易学而著称。",
"AI": "人工智能是计算机科学的一个分支,致力于创建能够执行通常需要人类智能的任务的系统。",
"Agent": "AI Agent 是能够感知环境、做出决策并采取行动的自主系统。"
}
return search_results.get(query, f"未找到关于 '{query}' 的信息")
# 将工具收集到列表
tools = [calculator, get_weather, search_web]
第二步:创建 Agent
使用 LangChain 的 Agent 框架:
python
from langchain_anthropic import ChatAnthropic
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# 初始化 LLM
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
# 定义 Agent 的系统提示
system_prompt = """你是一个有用的 AI 助手。你可以使用以下工具来帮助用户:
1. calculator - 执行数学计算
2. get_weather - 查询天气信息
3. search_web - 搜索网络信息
当用户提出问题时,你应该:
1. 理解用户的意图
2. 选择合适的工具来解决问题
3. 基于工具的结果进行推理
4. 给出清晰的答案
如果你不确定是否需要使用工具,可以直接回答。
"""
# 创建提示模板
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
# 创建 Agent
agent = create_tool_calling_agent(llm, tools, prompt)
# 创建 Agent 执行器
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 打印详细的执行过程
max_iterations=10, # 最多执行 10 次迭代
)
第三步:运行 Agent
python
# 测试用例 1:数学计算
print("=" * 50)
print("测试 1:数学计算")
print("=" * 50)
result = agent_executor.invoke({
"input": "请计算 (100 + 50) * 2 的结果"
})
print(f"最终答案:{result['output']}\n")
# 测试用例 2:天气查询
print("=" * 50)
print("测试 2:天气查询")
print("=" * 50)
result = agent_executor.invoke({
"input": "北京今天天气怎么样?"
})
print(f"最终答案:{result['output']}\n")
# 测试用例 3:复合问题
print("=" * 50)
print("测试 3:复合问题")
print("=" * 50)
result = agent_executor.invoke({
"input": "北京天气怎么样?如果温度低于 20°C,建议穿什么衣服?"
})
print(f"最终答案:{result['output']}\n")
# 测试用例 4:知识查询
print("=" * 50)
print("测试 4:知识查询")
print("=" * 50)
result = agent_executor.invoke({
"input": "什么是 AI Agent?"
})
print(f"最终答案:{result['output']}\n")
完整代码示例
将上述所有代码整合到一个文件 my_first_agent.py:
python
import os
from dotenv import load_dotenv
from langchain_anthropic import ChatAnthropic
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
# 加载环境变量
load_dotenv()
# ============ 定义工具 ============
@tool
def calculator(expression: str) -> str:
"""执行数学计算"""
try:
result = eval(expression)
return f"计算结果:{result}"
except Exception as e:
return f"计算错误:{str(e)}"
@tool
def get_weather(city: str) -> str:
"""查询指定城市的天气"""
weather_data = {
"北京": "晴天,温度 15°C,风力 3 级",
"上海": "多云,温度 18°C,风力 2 级",
"深圳": "晴天,温度 22°C,风力 2 级",
"杭州": "阴天,温度 16°C,风力 4 级"
}
return weather_data.get(city, f"暂无 {city} 的天气数据")
@tool
def search_web(query: str) -> str:
"""搜索网络信息"""
search_results = {
"Python": "Python 是一种高级编程语言,以其简洁易学而著称。",
"AI": "人工智能是计算机科学的一个分支,致力于创建能够执行通常需要人类智能的任务的系统。",
"Agent": "AI Agent 是能够感知环境、做出决策并采取行动的自主系统。"
}
return search_results.get(query, f"未找到关于 '{query}' 的信息")
tools = [calculator, get_weather, search_web]
# ============ 创建 Agent ============
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
system_prompt = """你是一个有用的 AI 助手。你可以使用以下工具来帮助用户:
1. calculator - 执行数学计算
2. get_weather - 查询天气信息
3. search_web - 搜索网络信息
当用户提出问题时,理解意图、选择合适的工具、进行推理、给出清晰的答案。"""
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10,
)
# ============ 运行 Agent ============
if __name__ == "__main__":
# 交互式循环
print("欢迎使用 AI Agent!输入 'quit' 退出。\n")
while True:
user_input = input("你:")
if user_input.lower() == 'quit':
print("再见!")
break
try:
result = agent_executor.invoke({"input": user_input})
print(f"Agent:{result['output']}\n")
except Exception as e:
print(f"错误:{str(e)}\n")
常见问题
Q1: Agent 没有调用工具怎么办?
原因:LLM 可能认为不需要工具就能回答。
解决方案:
- 在系统提示中明确指出何时应该使用工具
- 调整
max_iterations参数 - 检查 LLM 是否支持 tool calling
Q2: 工具调用失败了怎么办?
原因:工具定义有问题或参数不匹配。
解决方案:
python
# 添加错误处理
@tool
def my_tool(param: str) -> str:
"""工具描述"""
try:
# 工具逻辑
return result
except Exception as e:
return f"工具执行失败:{str(e)}"
Q3: 如何让 Agent 记住之前的对话?
解决方案:使用 ConversationBufferMemory
python
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history")
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
memory=memory,
verbose=True,
)
Q4: 如何限制 Agent 的权限?
解决方案:
- 只提供必要的工具
- 在工具中添加权限检查
- 使用沙箱环境执行代码
进阶拓展
1. 添加更多工具
python
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""发送邮件"""
# 实现邮件发送逻辑
return f"邮件已发送给 {to}"
@tool
def read_file(path: str) -> str:
"""读取文件内容"""
with open(path, 'r') as f:
return f.read()
2. 使用不同的 LLM
python
# 使用 OpenAI
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4")
# 使用本地模型
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama2")
3. 持久化对话历史
python
from langchain.memory import ConversationSummaryMemory
memory = ConversationSummaryMemory(
llm=llm,
memory_key="chat_history"
)
4. 添加日志和监控
python
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 在 Agent 执行前后记录日志
logger.info(f"执行 Agent,输入:{user_input}")
result = agent_executor.invoke({"input": user_input})
logger.info(f"Agent 输出:{result['output']}")
最佳实践
-
工具设计:
- 工具应该单一职责
- 提供清晰的文档字符串
- 包含错误处理
-
提示工程:
- 系统提示要明确
- 给出具体的使用示例
- 定义 Agent 的角色和限制
-
性能优化:
- 使用
max_iterations限制循环次数 - 缓存工具结果
- 异步调用工具
- 使用
-
安全性:
- 验证工具输入
- 限制可访问的资源
- 记录所有操作
-
测试:
- 为每个工具编写单元测试
- 测试 Agent 的各种场景
- 监控 Agent 的性能
总结
本篇我们从零开始构建了一个完整的 AI Agent:
✅ 定义了工具集 :计算器、天气查询、网络搜索 ✅ 创建了 Agent :使用 LangChain 框架 ✅ 实现了 ReAct 循环 :思考→行动→观察 ✅ 提供了完整代码:可直接运行
这个 Agent 虽然简单,但包含了生产级 Agent 的所有核心要素。下一篇我们将学习如何让 Agent 拥有长期记忆,通过 RAG 技术增强其知识库。
下篇预告
第 5 篇:RAG 与 Agent 的结合
- 什么是 RAG(检索增强生成)
- 如何为 Agent 构建知识库
- 向量数据库的选择和使用
- 实战:构建一个能查询文档的 Agent