1. Python AI Agent 构建指南:从入门到实战
在人工智能技术快速发展的今天,AI Agent(人工智能代理)已经成为开发者工具箱中的重要组成部分。作为一名长期从事AI开发的工程师,我发现Python因其丰富的库生态系统和简洁的语法,成为构建AI Agent的首选语言。本文将分享三种经过实战验证的Python AI Agent构建方法,每种方法都附有详细实现代码和避坑指南。
1.1 什么是AI Agent?
AI Agent本质上是一个能够自主感知环境、处理信息并执行任务的智能系统。与传统的程序不同,AI Agent具备以下核心特征:
- 环境感知:通过API、传感器或用户输入获取环境信息
- 自主决策:基于LLM(大语言模型)的推理能力做出判断
- 任务执行:调用各种工具完成具体操作
- 持续学习:通过记忆系统积累经验并优化行为
在实际项目中,我经常使用AI Agent来处理以下场景:
- 自动化客服系统
- 智能数据分析助手
- 个性化推荐引擎
- 复杂工作流自动化
1.2 AI Agent的核心架构解析
一个完整的AI Agent通常包含五个关键组件:
1.2.1 LLM(大语言模型)
作为Agent的"大脑",LLM负责理解输入、生成响应和做出决策。在选择LLM时需要考虑:
- 模型大小与推理速度的平衡
- API调用成本
- 对中文的支持程度
- 函数调用能力
提示:对于中文场景,建议优先考虑支持function calling的模型,如GPT-3.5-turbo或ERNIE-Bot
1.2.2 记忆系统
记忆系统使Agent能够记住对话历史和任务上下文。常见的实现方式包括:
- 短期记忆:维护对话上下文窗口
- 长期记忆:向量数据库存储历史信息
- 知识图谱:结构化存储领域知识
1.2.3 工具系统
工具是Agent能力的延伸,典型的工具包括:
- 搜索引擎API
- 计算器
- 数据库查询接口
- 文件操作工具
1.2.4 规划器
规划器负责将复杂任务分解为可执行的子任务。好的规划器应该能够:
- 识别任务依赖关系
- 处理并行任务
- 应对执行失败的情况
1.2.5 执行器
执行器负责实际调用工具并处理返回结果。关键功能包括:
- 参数验证
- 错误处理
- 结果格式化
2. 方法一:使用LangChain构建AI Agent
2.1 LangChain框架概述
LangChain是目前最流行的AI Agent开发框架之一,它提供了:
- 标准化的工具接口
- 多种预置Agent类型
- 丰富的记忆系统实现
- 便捷的LLM集成
2.1.1 环境准备
首先安装必要的依赖:
bash复制pip install langchain langchain-openai python-dotenv
建议使用.env文件管理API密钥:
python复制# .env文件内容
OPENAI_API_KEY=your-api-key
2.1.2 基础Agent实现
下面是一个完整的LangChain Agent示例:
python复制import os
from dotenv import load_dotenv
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI
from langchain.tools import Tool
# 加载环境变量
load_dotenv()
# 初始化LLM - 使用gpt-3.5-turbo模型
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.7, # 控制创造性
max_tokens=2000 # 限制响应长度
)
# 定义自定义工具
def advanced_calculator(expression: str) -> str:
"""支持复杂数学运算的计算器"""
try:
# 安全评估数学表达式
allowed_chars = set("0123456789+-*/.() ")
if not all(c in allowed_chars for c in expression):
return "错误:表达式包含非法字符"
# 使用ast.literal_eval更安全
import ast
node = ast.parse(expression, mode='eval')
if not isinstance(node, ast.Expression):
return "错误:无效表达式"
for subnode in ast.walk(node):
if isinstance(subnode, ast.Call):
return "错误:不允许函数调用"
result = eval(compile(node, '<string>', 'eval'))
return f"计算结果:{result}"
except Exception as e:
return f"计算错误:{str(e)}"
# 创建工具列表
tools = [
Tool(
name="高级计算器",
func=advanced_calculator,
description="用于执行复杂数学计算,支持加减乘除和括号"
)
]
# 创建Agent
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
handle_parsing_errors=True # 更好的错误处理
)
# 使用Agent处理复杂查询
question = "请计算(3.14 * 15.7^2) / (2 + 3)的值"
result = agent.run(question)
print(result)
2.1.3 实战技巧与避坑指南
-
工具设计原则:
- 每个工具应专注于单一功能
- 工具描述要准确清晰(LLM依赖描述决定是否调用)
- 实现完善的错误处理
-
常见问题排查:
- 如果Agent频繁调用错误工具,检查工具描述是否准确
- 遇到解析错误时,尝试降低temperature值
- API调用超时可设置合理的timeout参数
-
性能优化建议:
- 对耗时工具实现缓存机制
- 使用流式响应改善用户体验
- 限制工具调用次数防止无限循环
注意:生产环境中务必添加速率限制和错误监控,避免因API故障导致服务不可用
3. 方法二:使用LlamaIndex构建文档问答Agent
3.1 LlamaIndex框架特点
LlamaIndex特别适合构建基于文档的问答系统,其主要优势包括:
- 高效的文档索引和检索
- 灵活的存储后端支持
- 与多种LLM无缝集成
- 内置的查询优化机制
3.1.1 环境配置
安装必要依赖:
bash复制pip install llama-index python-dotenv unstructured
准备文档数据:
- 创建
data目录 - 放入PDF、Word或TXT格式的文档
3.1.2 文档问答系统实现
python复制import os
from dotenv import load_dotenv
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.tools import QueryEngineTool
from llama_index.core.agent import ReActAgent
from llama_index.llms.openai import OpenAI
# 加载环境变量
load_dotenv()
# 文档加载与预处理
documents = SimpleDirectoryReader(
"data",
recursive=True, # 递归读取子目录
required_exts=[".pdf", ".docx", ".txt"] # 支持的文件类型
).load_data()
# 创建向量索引
index = VectorStoreIndex.from_documents(
documents,
show_progress=True # 显示索引进度
)
# 配置查询引擎
query_engine = index.as_query_engine(
similarity_top_k=3, # 返回最相关的3个结果
response_mode="compact" # 压缩响应长度
)
# 创建文档问答工具
doc_tool = QueryEngineTool.from_defaults(
query_engine=query_engine,
name="文档知识库",
description="用于回答基于上传文档内容的问题",
return_direct=False # 允许Agent进一步处理结果
)
# 初始化LLM
llm = OpenAI(
model="gpt-3.5-turbo",
temperature=0.3 # 降低创造性以提高准确性
)
# 创建Agent
agent = ReActAgent.from_tools(
[doc_tool],
llm=llm,
verbose=True,
max_iterations=5 # 限制最大迭代次数
)
# 使用示例
response = agent.query("文档中提到的关键技术有哪些?请列出三点")
print(response)
3.2 高级功能扩展
3.2.1 混合检索策略
结合关键词检索和向量检索提高准确率:
python复制from llama_index.core import KeywordTableIndex
# 创建关键词索引
keyword_index = KeywordTableIndex.from_documents(documents)
# 混合查询引擎
from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.selectors import LLMSingleSelector
query_engine = RouterQueryEngine(
selector=LLMSingleSelector.from_defaults(),
query_engine_tools=[
QueryEngineTool.from_defaults(
query_engine=vector_query_engine,
description="向量检索,适合语义搜索"
),
QueryEngineTool.from_defaults(
query_engine=keyword_query_engine,
description="关键词检索,适合精确匹配"
)
]
)
3.2.2 实战经验分享
-
文档预处理技巧:
- 对大文档进行分块处理(建议每块500-1000字)
- 添加元数据标记文档来源和章节
- 对技术文档提取关键词作为补充索引
-
性能优化:
- 对索引进行持久化存储避免重复计算
- 使用GPU加速向量计算
- 实现缓存机制减少重复查询
-
常见问题处理:
- 遇到"我不知道"的回答时,检查文档是否相关
- 对模糊查询添加澄清机制
- 处理文档中的表格和图表信息
4. 方法三:自定义Agent框架开发
4.1 自定义框架的优势
当现有框架无法满足需求时,自定义Agent框架提供了:
- 完全的架构控制权
- 针对特定场景的优化
- 轻量级的部署方案
- 灵活的扩展机制
4.1.1 基础Agent类实现
python复制import json
import openai
from typing import List, Dict, Any, Callable, Optional
from pydantic import BaseModel, validator
class ToolDefinition(BaseModel):
"""工具定义模型"""
name: str
description: str
parameters: Dict[str, Any]
function: Callable
class AgentMemory(BaseModel):
"""记忆项模型"""
role: str # 'user' 或 'assistant'
content: str
timestamp: float
class SimpleAgent:
def __init__(self, api_key: str, model: str = "gpt-3.5-turbo"):
self.api_key = api_key
self.model = model
self.tools: Dict[str, ToolDefinition] = {}
self.memory: List[AgentMemory] = []
self.max_memory_items = 10 # 限制记忆长度
def add_tool(self, tool: ToolDefinition):
"""添加工具"""
if tool.name in self.tools:
raise ValueError(f"工具{tool.name}已存在")
self.tools[tool.name] = tool
def add_memory(self, role: str, content: str):
"""添加记忆项"""
if len(self.memory) >= self.max_memory_items:
self.memory.pop(0) # 移除最旧的记忆
self.memory.append(
AgentMemory(
role=role,
content=content,
timestamp=time.time()
)
)
def _generate_messages(self, prompt: str) -> List[Dict[str, str]]:
"""生成对话上下文"""
messages = []
# 添加记忆
for item in self.memory:
messages.append({
"role": item.role,
"content": item.content
})
# 添加当前提示
messages.append({
"role": "user",
"content": prompt
})
return messages
def _call_llm(self, messages: List[Dict[str, str]]) -> Dict[str, Any]:
"""调用LLM API"""
openai.api_key = self.api_key
try:
response = openai.ChatCompletion.create(
model=self.model,
messages=messages,
tools=[self._convert_tool_to_schema(t) for t in self.tools.values()],
tool_choice="auto",
timeout=10 # 设置超时
)
return response.choices[0].message
except Exception as e:
raise RuntimeError(f"LLM调用失败: {str(e)}")
def _convert_tool_to_schema(self, tool: ToolDefinition) -> Dict[str, Any]:
"""转换工具定义到OpenAI schema"""
return {
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.parameters
}
}
def run(self, prompt: str) -> str:
"""执行Agent"""
try:
# 调用LLM获取初始响应
messages = self._generate_messages(prompt)
response = self._call_llm(messages)
# 处理工具调用
if response.tool_calls:
for tool_call in response.tool_calls:
tool_name = tool_call.function.name
if tool_name not in self.tools:
return f"错误:未知工具{tool_name}"
# 执行工具
try:
tool = self.tools[tool_name]
args = json.loads(tool_call.function.arguments)
result = tool.function(**args)
# 添加工具调用结果到上下文
messages.append({
"role": "tool",
"name": tool_name,
"content": str(result)
})
# 再次调用LLM处理结果
response = self._call_llm(messages)
except Exception as e:
return f"工具{tool_name}执行失败: {str(e)}"
# 保存对话历史
self.add_memory("user", prompt)
if response.content:
self.add_memory("assistant", response.content)
return response.content or "未获得有效响应"
except Exception as e:
return f"Agent执行出错: {str(e)}"
4.1.2 自定义工具示例
python复制# 定义天气查询工具
class WeatherTool:
@staticmethod
def get_definition():
return ToolDefinition(
name="get_weather",
description="获取指定城市的当前天气信息",
parameters={
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
},
function=WeatherTool.execute
)
@staticmethod
def execute(city: str):
# 模拟天气API调用
# 实际项目中替换为真实API调用
weather_data = {
"北京": "晴, 25°C",
"上海": "多云, 27°C",
"广州": "雷阵雨, 30°C"
}
return weather_data.get(city, "未知城市")
# 使用自定义Agent
agent = SimpleAgent(api_key="your-api-key")
agent.add_tool(WeatherTool.get_definition())
response = agent.run("北京现在的天气怎么样?")
print(response)
4.2 高级功能实现
4.2.1 记忆优化策略
python复制class EnhancedAgent(SimpleAgent):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.important_memory = [] # 重要记忆
def add_important_memory(self, content: str):
"""添加重要记忆"""
self.important_memory.append(
AgentMemory(
role="system",
content=f"重要记忆:{content}",
timestamp=time.time()
)
)
def _generate_messages(self, prompt: str) -> List[Dict[str, str]]:
"""重写消息生成方法"""
messages = []
# 添加重要记忆(始终保留)
for item in self.important_memory:
messages.append({
"role": item.role,
"content": item.content
})
# 添加普通记忆(有限长度)
for item in self.memory[-self.max_memory_items:]:
messages.append({
"role": item.role,
"content": item.content
})
# 添加当前提示
messages.append({
"role": "user",
"content": prompt
})
return messages
4.2.2 实战中的经验教训
-
错误处理要点:
- 对LLM响应进行完整性验证
- 实现工具调用的超时机制
- 记录完整执行日志便于排查问题
-
性能关键点:
- 避免在工具函数中执行耗时操作
- 对频繁使用的工具结果实现缓存
- 限制单次对话的交互轮次
-
安全注意事项:
- 验证工具参数防止注入攻击
- 对敏感信息进行脱敏处理
- 实现访问控制和速率限制
在实际项目中,我发现自定义Agent最适合以下场景:
- 需要高度定制化的业务流程
- 对性能有极致要求的应用
- 特殊领域的专业知识处理
- 与现有系统的深度集成
5. AI Agent开发中的常见问题与解决方案
5.1 工具调用问题排查
5.1.1 工具未被正确调用
症状:
- Agent没有按预期调用工具
- 工具描述似乎被忽略
解决方案:
- 检查工具描述是否清晰准确
- 验证工具参数定义是否符合规范
- 尝试简化工具描述测试基本功能
- 检查LLM的temperature参数(过高可能导致随机性)
5.1.2 工具参数解析失败
症状:
- 收到参数解析错误
- 工具接收到错误格式的参数
解决方案:
- 在工具定义中添加详细的参数描述
- 实现参数预处理和验证逻辑
- 对复杂参数使用JSON schema严格定义
5.2 记忆管理优化技巧
5.2.1 记忆窗口太小
症状:
- Agent忘记之前的对话内容
- 在多轮对话中表现不一致
解决方案:
- 增加记忆保留数量
- 实现摘要记忆机制(定期总结对话)
- 区分重要记忆和普通记忆
5.2.2 记忆混乱
症状:
- Agent混淆不同话题的内容
- 响应中包含无关信息
解决方案:
- 实现基于话题的记忆分区
- 添加记忆清理机制
- 为不同对话session维护独立记忆
5.3 性能优化实战
5.3.1 响应延迟问题
优化策略:
- 对LLM响应实现流式处理
- 并行执行独立的工具调用
- 使用更轻量的LLM模型
5.3.2 高并发场景处理
架构建议:
- 实现请求队列和限流
- 使用异步IO处理并发请求
- 对昂贵操作实现结果缓存
6. AI Agent的高级应用场景
6.1 多Agent协作系统
通过多个Agent分工合作处理复杂任务:
python复制class CoordinatorAgent:
def __init__(self, specialist_agents: Dict[str, SimpleAgent]):
self.agents = specialist_agents
def delegate_task(self, task_description: str) -> str:
# 分析任务类型
analysis_prompt = f"""
请分析以下任务最适合哪个专业Agent处理:
任务:{task_description}
可选Agent:{', '.join(self.agents.keys())}
只需返回Agent名称,不要包含其他内容。
"""
# 调用LLM决定任务分配
chosen_agent = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": analysis_prompt}],
temperature=0
).choices[0].message.content
# 委托给专业Agent执行
if chosen_agent in self.agents:
return self.agents[chosen_agent].run(task_description)
return "错误:找不到合适的处理Agent"
6.2 持续学习机制实现
让Agent能够从交互中学习:
python复制class LearningAgent(SimpleAgent):
def __init__(self, *args, knowledge_db: str, **kwargs):
super().__init__(*args, **kwargs)
self.knowledge_db = knowledge_db # 知识库路径
def learn_from_feedback(self, question: str, correct_answer: str):
"""从反馈中学习"""
# 将问答对保存到知识库
with open(self.knowledge_db, "a") as f:
f.write(f"Q: {question}\nA: {correct_answer}\n\n")
# 更新检索系统(简化示例)
if hasattr(self, "retriever"):
self.retriever.update_index(question, correct_answer)
6.3 领域特定Agent开发
以医疗问答Agent为例的关键实现:
python复制class MedicalAgent(SimpleAgent):
def __init__(self, *args, medical_kb: str, **kwargs):
super().__init__(*args, **kwargs)
self.load_medical_knowledge(medical_kb)
def load_medical_knowledge(self, filepath: str):
"""加载医疗知识库"""
# 实际项目中应使用专业医疗知识图谱
with open(filepath) as f:
self.medical_data = json.load(f)
# 添加医疗专用工具
self.add_tool(
ToolDefinition(
name="query_medical_kb",
description="查询医疗知识库",
parameters={
"type": "object",
"properties": {
"symptom": {"type": "string"},
"medication": {"type": "string"}
}
},
function=self.query_medical_data
)
)
def query_medical_data(self, symptom: str = None, medication: str = None):
"""查询医疗数据"""
results = []
if symptom:
results.extend(
item for item in self.medical_data
if symptom.lower() in item["symptoms"]
)
if medication:
results.extend(
item for item in self.medical_data
if medication.lower() in item["medications"]
)
return json.dumps(results[:5]) # 返回前5个结果
在开发医疗类Agent时需要特别注意:
- 实现免责声明和风险提示
- 严格验证信息来源
- 对诊断建议进行置信度标注
- 遵循医疗行业合规要求
