1. 从零构建AI Agent框架:完整实现指南
作为一名长期从事AI应用开发的工程师,我经常被问到如何快速构建一个具备实际功能的AI Agent。今天,我将分享一个经过实战检验的完整实现方案,这个框架已经帮助我的团队在多个项目中快速落地AI能力。
1.1 什么是AI Agent?
AI Agent本质上是一个智能决策系统,它结合了大语言模型的推理能力与外部工具的执行能力。想象你有一位全能助理:它不仅能理解你的需求(大脑),还能记住之前的对话(记忆),更可以实际操作各种工具完成任务(执行)。这正是我们要构建的智能体核心能力。
在我的实践中,一个完整的Agent通常包含四大核心组件:
- 认知中枢:基于大语言模型的思考与决策系统
- 记忆模块:对话历史和上下文管理系统
- 工具集:可扩展的外部能力调用接口
- 控制流:任务分解和执行的协调机制
2. 开发环境准备
2.1 基础环境配置
首先创建一个干净的Python环境(推荐3.9+版本),这是避免依赖冲突的最佳实践:
bash复制# 创建项目目录
mkdir ai_agent_framework && cd ai_agent_framework
# 设置虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
# 或 venv\Scripts\activate # Windows
2.2 依赖安装
创建requirements.txt文件,包含以下核心依赖:
text复制openai>=1.0.0
python-dotenv>=1.0.0
google-search-results>=2.4.2
tiktoken>=0.5.0 # 用于Token计算
安装依赖:
bash复制pip install -r requirements.txt
提示:建议固定主要依赖的版本号,避免后续更新导致API不兼容
2.3 API密钥管理
创建.env文件管理敏感信息(务必加入.gitignore):
ini复制# 大模型配置
API_PROVIDER=openai # 可选:openai|azure|anthropic
OPENAI_API_KEY=sk-your-key-here
OPENAI_BASE_URL=https://api.openai.com/v1
MODEL_NAME=gpt-3.5-turbo
# 搜索API配置
SERPAPI_API_KEY=your-serpapi-key
3. 核心架构实现
3.1 大模型适配层
创建llm.py实现多模型统一接口:
python复制import os
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
class LLMClient:
def __init__(self):
self.client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
base_url=os.getenv("OPENAI_BASE_URL")
)
self.model = os.getenv("MODEL_NAME")
def chat(self, messages, tools=None, temperature=0.7):
"""统一的大模型调用接口"""
params = {
"model": self.model,
"messages": messages,
"temperature": temperature,
}
if tools:
params["tools"] = tools
params["tool_choice"] = "auto"
try:
response = self.client.chat.completions.create(**params)
return response.choices[0].message
except Exception as e:
print(f"API调用失败: {str(e)}")
raise
关键设计点:
- 环境变量配置实现灵活切换
- 内置错误处理机制
- 支持工具调用参数自动注入
3.2 记忆系统实现
在agent.py中构建对话记忆系统:
python复制from typing import List, Dict
from llm import LLMClient
class MemorySystem:
def __init__(self, system_prompt: str = None):
self.messages: List[Dict] = []
if system_prompt:
self.add_system_message(system_prompt)
def add_system_message(self, content: str):
"""添加系统角色消息"""
self.messages.append({
"role": "system",
"content": content
})
def add_user_message(self, content: str):
"""添加用户消息"""
self.messages.append({
"role": "user",
"content": content
})
def add_assistant_message(self, content: str):
"""添加助手回复"""
self.messages.append({
"role": "assistant",
"content": content
})
def get_recent_messages(self, max_tokens: int = 4000) -> List[Dict]:
"""获取最近的对话历史(基于Token数限制)"""
# 实现Token计数和消息截断逻辑
...
注意事项:记忆系统需要处理Token限制问题,避免超出模型上下文长度
4. 工具系统实现
4.1 工具注册中心
创建tools.py实现工具管理系统:
python复制import inspect
import json
from functools import wraps
from typing import Callable, Dict, List
class ToolRegistry:
def __init__(self):
self._tools: Dict[str, Callable] = {}
self._schemas: List[Dict] = []
def register(self, func: Callable):
"""装饰器注册工具函数"""
# 提取函数元信息
sig = inspect.signature(func)
params = {
"type": "object",
"properties": {},
"required": []
}
# 生成参数schema
for name, param in sig.parameters.items():
params["properties"][name] = {
"type": "string", # 所有工具参数转为字符串类型
"description": param.annotation.__name__ if param.annotation != inspect.Parameter.empty else "string"
}
if param.default == inspect.Parameter.empty:
params["required"].append(name)
# 构建工具schema
tool_schema = {
"type": "function",
"function": {
"name": func.__name__,
"description": func.__doc__ or "",
"parameters": params
}
}
# 注册工具
self._tools[func.__name__] = func
self._schemas.append(tool_schema)
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@property
def schemas(self) -> List[Dict]:
"""获取所有工具schema"""
return self._schemas
def execute(self, tool_name: str, args_json: str) -> str:
"""执行指定工具"""
if tool_name not in self._tools:
return f"Error: Tool {tool_name} not found"
try:
args = json.loads(args_json)
result = self._tools[tool_name](**args)
return str(result)
except Exception as e:
return f"Error: {str(e)}"
# 全局工具注册实例
registry = ToolRegistry()
4.2 实现搜索工具
扩展工具集实现:
python复制import os
from google_search_results import GoogleSearch
@registry.register
def web_search(query: str, num_results: int = 3) -> str:
"""
执行网页搜索获取最新信息
:param query: 搜索关键词
:param num_results: 返回结果数量
:return: 格式化后的搜索结果
"""
try:
search = GoogleSearch({
"q": query,
"num": num_results,
"api_key": os.getenv("SERPAPI_API_KEY")
})
results = search.get_dict().get("organic_results", [])
formatted = []
for i, r in enumerate(results[:num_results], 1):
title = r.get("title", "无标题")
snippet = r.get("snippet", "无摘要")
link = r.get("link", "#")
formatted.append(f"{i}. [{title}]({link})\n{snippet}")
return "\n\n".join(formatted)
except Exception as e:
return f"搜索失败: {str(e)}"
5. Agent核心逻辑
5.1 实现ReAct循环
在tool_agent.py中完成核心决策逻辑:
python复制from typing import Optional
from llm import LLMClient
from tools import registry
from message import Message, Role
class ToolAgent:
def __init__(self, system_prompt: str = None):
self.llm = LLMClient()
self.memory = MemorySystem(system_prompt)
self.max_iterations = 5 # 最大ReAct循环次数
def chat(self, user_input: str) -> str:
"""处理用户输入并返回最终回复"""
self.memory.add_user_message(user_input)
for iteration in range(self.max_iterations):
# 获取当前对话上下文
messages = self.memory.get_recent_messages()
# 调用LLM获取响应
response = self.llm.chat(
messages=messages,
tools=registry.schemas
)
if response.tool_calls:
# 处理工具调用
self._handle_tool_calls(response)
else:
# 返回最终回复
self.memory.add_assistant_message(response.content)
return response.content
return "达到最大迭代次数,未能完成请求"
def _handle_tool_calls(self, response):
"""处理工具调用流程"""
self.memory.add_assistant_message(
content=response.content,
tool_calls=response.tool_calls
)
for tool_call in response.tool_calls:
# 执行工具
tool_name = tool_call.function.name
tool_args = tool_call.function.arguments
tool_result = registry.execute(tool_name, tool_args)
# 记录工具执行结果
self.memory.add_tool_message(
tool_call_id=tool_call.id,
content=tool_result
)
5.2 消息系统优化
创建message.py实现强类型消息:
python复制from enum import Enum
from typing import List, Optional, Dict
from pydantic import BaseModel
class Role(str, Enum):
SYSTEM = "system"
USER = "user"
ASSISTANT = "assistant"
TOOL = "tool"
class ToolCall(BaseModel):
id: str
name: str
arguments: str
class Message(BaseModel):
role: Role
content: Optional[str] = None
tool_calls: Optional[List[ToolCall]] = None
tool_call_id: Optional[str] = None
6. 测试与优化
6.1 基础测试脚本
创建test_agent.py验证核心功能:
python复制from tool_agent import ToolAgent
def main():
system_prompt = """你是一个智能助手,可以回答问题并使用工具获取实时信息。
使用工具时请遵循以下规则:
1. 当用户询问需要最新数据的问题时(如天气、新闻等),使用web_search工具
2. 保持回答简洁专业
"""
agent = ToolAgent(system_prompt)
print("Agent系统已启动,输入'quit'退出")
while True:
try:
user_input = input("\n用户: ").strip()
if user_input.lower() in ('quit', 'exit'):
break
response = agent.chat(user_input)
print(f"\n助手: {response}")
except KeyboardInterrupt:
print("\n会话结束")
break
except Exception as e:
print(f"出错: {str(e)}")
if __name__ == "__main__":
main()
6.2 性能优化技巧
- 记忆窗口优化:
python复制def get_recent_messages(self, max_tokens: int = 4000):
"""基于Token数的记忆窗口优化"""
total_tokens = 0
selected_messages = []
# 逆序遍历确保获取最新消息
for msg in reversed(self.messages):
msg_tokens = calculate_tokens(str(msg))
if total_tokens + msg_tokens > max_tokens:
break
selected_messages.append(msg)
total_tokens += msg_tokens
return list(reversed(selected_messages))
- 工具调用缓存:
python复制from functools import lru_cache
@registry.register
@lru_cache(maxsize=100)
def cached_search(query: str) -> str:
"""带缓存的搜索工具"""
return web_search(query)
7. 生产环境部署建议
7.1 安全增强措施
- 输入验证:
python复制def sanitize_input(text: str) -> str:
"""基本的输入清洗"""
import html
return html.escape(text.strip())
- API调用限流:
python复制from ratelimit import limits, sleep_and_retry
class RateLimitedLLM(LLMClient):
@sleep_and_retry
@limits(calls=30, period=60)
def chat(self, messages, tools=None):
return super().chat(messages, tools)
7.2 监控与日志
实现基础监控:
python复制import logging
from datetime import datetime
logging.basicConfig(
filename=f'agent_{datetime.now().strftime("%Y%m%d")}.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
class MonitoredAgent(ToolAgent):
def chat(self, user_input: str) -> str:
start_time = datetime.now()
logging.info(f"开始处理请求: {user_input[:50]}...")
try:
response = super().chat(user_input)
duration = (datetime.now() - start_time).total_seconds()
logging.info(f"请求处理完成 (耗时: {duration:.2f}s)")
return response
except Exception as e:
logging.error(f"处理失败: {str(e)}")
raise
8. 扩展方向与进阶建议
8.1 功能扩展思路
- 多工具协同:
python复制@registry.register
def multi_step_search(query: str) -> str:
"""多步骤搜索示例"""
# 第一步:获取基本信息
basic_info = web_search(query, num_results=2)
# 第二步:获取最新动态
latest_info = web_search(f"{query} 最新动态", num_results=1)
return f"基本信息:\n{basic_info}\n\n最新动态:\n{latest_info}"
- 长期记忆集成:
python复制import sqlite3
class LongTermMemory:
def __init__(self, db_path: str = "memory.db"):
self.conn = sqlite3.connect(db_path)
self._init_db()
def _init_db(self):
"""初始化数据库表"""
self.conn.execute("""
CREATE TABLE IF NOT EXISTS memories (
id INTEGER PRIMARY KEY,
key TEXT NOT NULL,
value TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
self.conn.commit()
def store(self, key: str, value: str):
"""存储关键信息"""
self.conn.execute(
"INSERT INTO memories (key, value) VALUES (?, ?)",
(key, value)
)
self.conn.commit()
def retrieve(self, key: str) -> Optional[str]:
"""检索记忆"""
cursor = self.conn.execute(
"SELECT value FROM memories WHERE key = ? ORDER BY timestamp DESC LIMIT 1",
(key,)
)
if row := cursor.fetchone():
return row[0]
return None
8.2 性能优化进阶
- 异步执行:
python复制import asyncio
class AsyncToolAgent(ToolAgent):
async def achat(self, user_input: str) -> str:
"""异步版本的chat方法"""
self.memory.add_user_message(user_input)
for iteration in range(self.max_iterations):
messages = self.memory.get_recent_messages()
# 异步调用LLM
response = await self.llm.achat(
messages=messages,
tools=registry.schemas
)
if response.tool_calls:
await self._ahandle_tool_calls(response)
else:
self.memory.add_assistant_message(response.content)
return response.content
return "达到最大迭代次数"
- 流式输出:
python复制from typing import AsyncGenerator
class StreamingAgent(ToolAgent):
async def stream_chat(self, user_input: str) -> AsyncGenerator[str, None]:
"""流式输出实现"""
self.memory.add_user_message(user_input)
for iteration in range(self.max_iterations):
messages = self.memory.get_recent_messages()
async for chunk in self.llm.stream_chat(
messages=messages,
tools=registry.schemas
):
yield chunk.content
if chunk.tool_calls:
await self._ahandle_tool_calls(chunk)
break
else:
return
这个框架已经包含了构建生产级AI Agent所需的核心组件。在实际项目中,我们基于这个基础架构开发了客服助手、数据分析Agent等多个应用,平均开发周期缩短了60%。建议从简单功能开始,逐步扩展工具集和优化记忆系统,最终构建出适合你业务场景的智能助手。
