关键词:AI Agent、ReAct、工具调用、长期记忆、LangGraph、Multi-Agent
目录
- [什么是 AI Agent?](#什么是 AI Agent?)
- [Agent 的四大核心组件](#Agent 的四大核心组件)
- 规划(Planning):如何分解复杂任务
- [工具调用(Tool Use)](#工具调用(Tool Use))
- 记忆系统(Memory)
- 感知(Perception)
- [主流 Agent 框架对比](#主流 Agent 框架对比)
- [Multi-Agent 架构](#Multi-Agent 架构)
- [代码实战:从零构建 ReAct Agent](#代码实战:从零构建 ReAct Agent)
- [Agent 开发踩坑总结](#Agent 开发踩坑总结)
1. 什么是 AI Agent?
AI Agent 是以大语言模型为"大脑",能够自主感知环境、制定计划、调用工具并持续执行直到完成目标的系统。
普通 LLM 应用 vs Agent 的核心区别:
| 维度 | 普通 LLM | AI Agent |
|---|---|---|
| 执行方式 | 单次推理,一问一答 | 多步执行,持续行动 |
| 工具使用 | 无 | 可调用外部工具 |
| 规划能力 | 无(只是回答) | 能分解任务、制定步骤 |
| 记忆 | 仅当前上下文窗口 | 短期+长期记忆 |
| 自主性 | 低 | 高(可自行决定下一步) |
一个形象的类比:LLM 是一位博学的顾问,你问一次它答一次。Agent 是一位能独立完成任务的员工,你给它一个目标,它自己规划、查资料、写代码、验证结果,直到任务完成。
2. Agent 的四大核心组件
┌─────────────────────────────────────────┐
│ AI Agent │
│ │
│ ┌─────────┐ ┌──────────────────┐ │
│ │ 规划 │ │ 工具集合 │ │
│ │Planning │ │ 搜索/代码/API │ │
│ └────┬────┘ └──────────────────┘ │
│ │ │
│ ┌────▼────┐ ┌──────────────────┐ │
│ │ LLM │◄──►│ 记忆系统 │ │
│ │ 大脑 │ │ 短期/长期/语义 │ │
│ └────┬────┘ └──────────────────┘ │
│ │ │
│ ┌────▼────┐ │
│ │ 感知 │ ← 文本/图像/文件/API响应 │
│ └─────────┘ │
└─────────────────────────────────────────┘
3. 规划(Planning):如何分解复杂任务
3.1 ReAct(Reasoning + Acting)
最经典的 Agent 规划范式,交替进行推理和行动:
Thought: 我需要分析销售数据,首先要获取数据文件
Action: read_file("sales_2024.csv")
Observation: [返回 CSV 内容,100行数据]
Thought: 数据已获取,现在需要计算各季度总销售额
Action: python_execute("import pandas as pd; df = pd.read_csv(...)...")
Observation: Q1: 120万, Q2: 145万, Q3: 98万, Q4: 167万
Thought: 数据计算完成,Q4销售额最高,现在生成报告
Action: write_file("sales_report.md", "...")
Observation: 文件已保存
Final Answer: 2024年销售分析完成,Q4表现最佳,年度总额530万元...
3.2 Plan-and-Solve
先制定完整计划,再逐步执行(更适合复杂任务):
Step 1: [规划阶段]
问题:帮我研究并撰写一份关于AI Agent的市场报告
计划:
1. 搜索AI Agent市场规模数据
2. 调研主要竞争厂商(OpenAI、Anthropic、Google)
3. 分析技术趋势
4. 撰写报告(5000字)
5. 添加数据可视化
Step 2: [执行阶段]
依次执行以上步骤...
3.3 Tree of Thought(ToT)
对于需要搜索最优路径的问题,探索多条思维路径并选择最佳:
python
# 伪代码:ToT 搜索
def tree_of_thought(problem, max_depth=3, branching_factor=3):
root = ThoughtNode(problem)
for depth in range(max_depth):
leaf_nodes = get_leaf_nodes(root)
for node in leaf_nodes:
# 并行生成多个子思路
children = [generate_thought(node) for _ in range(branching_factor)]
# 评估每个思路的价值
scores = [evaluate_thought(child) for child in children]
# 保留最优的
node.children = prune(children, scores, keep_top=2)
return find_best_path(root)
4. 工具调用(Tool Use)
4.1 Function Calling 原理
现代 LLM 的工具调用通过 Function Calling(也叫 Tool Use)实现:
python
# 定义工具
tools = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "搜索互联网获取最新信息",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "execute_python",
"description": "执行 Python 代码",
"parameters": {
"type": "object",
"properties": {
"code": {"type": "string", "description": "要执行的Python代码"}
},
"required": ["code"]
}
}
}
]
4.2 常见工具类型
| 工具类别 | 示例 | 作用 |
|---|---|---|
| 搜索工具 | Tavily Search、SerpAPI | 获取最新网络信息 |
| 代码执行 | Python REPL、E2B沙箱 | 运行代码、数据分析 |
| 文件操作 | 读/写文件、PDF解析 | 处理本地文件 |
| API 调用 | 天气、股票、日历 | 接入外部服务 |
| 数据库 | SQL 执行器 | 查询结构化数据 |
| 多模态 | 图片生成、OCR | 处理非文本内容 |
4.3 工具设计原则
- 单一职责:每个工具只做一件事
- 清晰描述 :
description字段要精确,这是 LLM 决定是否调用的依据 - 容错处理:工具要有错误处理,返回格式化的错误信息
- 安全边界:代码执行工具要放在沙箱中运行
5. 记忆系统(Memory)
5.1 四种记忆类型
记忆类型
├── 感知记忆(Sensory):当前输入的原始信息
├── 短期记忆(Short-term):当前对话的上下文窗口
├── 长期记忆(Long-term)
│ ├── 语义记忆:用户信息、偏好等结构化存储
│ ├── 情节记忆:过去的对话历史(向量检索)
│ └── 程序记忆:如何完成特定任务的知识
└── 外部记忆(External):文档库、数据库等
5.2 短期记忆(对话历史压缩)
上下文窗口有限,需要压缩历史对话:
python
from langchain.memory import ConversationSummaryBufferMemory
from langchain_openai import ChatOpenAI
llm = ChatOpenAI()
# 超过 token 限制时自动摘要旧对话
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=2000, # 超过此 token 数,旧对话自动摘要
memory_key="chat_history",
return_messages=True
)
5.3 长期记忆(向量存储)
将重要信息持久化到向量数据库:
python
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from datetime import datetime
class AgentMemory:
"""Agent 长期记忆系统"""
def __init__(self):
self.embeddings = OpenAIEmbeddings()
self.vectorstore = Chroma(
collection_name="agent_memory",
embedding_function=self.embeddings,
persist_directory="./agent_memory_db"
)
def store(self, content: str, metadata: dict = None):
"""存储记忆"""
meta = {"timestamp": datetime.now().isoformat()}
if metadata:
meta.update(metadata)
self.vectorstore.add_texts(
texts=[content],
metadatas=[meta]
)
def recall(self, query: str, k: int = 3) -> list[str]:
"""检索相关记忆"""
docs = self.vectorstore.similarity_search(query, k=k)
return [doc.page_content for doc in docs]
def get_relevant_context(self, query: str) -> str:
"""获取格式化的相关记忆"""
memories = self.recall(query)
if not memories:
return ""
return "相关历史记忆:\n" + "\n".join(f"- {m}" for m in memories)
# 使用
memory = AgentMemory()
memory.store("用户偏好使用简洁的代码风格,不喜欢冗余注释", {"type": "user_preference"})
memory.store("用户在做一个电商平台项目,使用 FastAPI + React", {"type": "project_context"})
context = memory.get_relevant_context("帮我写一个用户认证接口")
print(context)
# 相关历史记忆:
# - 用户偏好使用简洁的代码风格,不喜欢冗余注释
# - 用户在做一个电商平台项目,使用 FastAPI + React
6. 感知(Perception)
现代 Agent 越来越多支持多模态输入:
python
from openai import OpenAI
import base64
client = OpenAI()
def analyze_image(image_path: str, question: str) -> str:
"""Agent 感知图像内容"""
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{image_data}"}
},
{"type": "text", "text": question}
]
}]
)
return response.choices[0].message.content
7. 主流 Agent 框架对比
| 框架 | 特点 | 适合场景 |
|---|---|---|
| LangChain | 生态完善,组件丰富 | 快速原型 |
| LangGraph | 图状态机,可控性强 | 复杂工作流 |
| CrewAI | Multi-Agent 角色协作 | 团队协作任务 |
| AutoGen | 多 Agent 对话框架 | 自动化编程 |
| Dify | 低代码,可视化 | 非开发者用户 |
| 自研 | 完全可控 | 生产级、特殊需求 |
8. Multi-Agent 架构
8.1 为什么需要多 Agent?
单个 Agent 处理复杂任务时面临:
- 上下文窗口限制
- 任务过于复杂,难以规划
- 不同子任务需要不同专业能力
8.2 常见 Multi-Agent 模式
监督者模式(Supervisor):
用户需求
↓
[监督者 Agent](任务分配)
├── [研究员 Agent](收集信息)
├── [分析师 Agent](数据分析)
└── [写作 Agent](生成报告)
↓
最终输出
流水线模式(Pipeline):
[爬虫 Agent] → [清洗 Agent] → [分析 Agent] → [报告 Agent]
8.3 CrewAI 多 Agent 示例
python
from crewai import Agent, Task, Crew, Process
# 定义 Agent 角色
researcher = Agent(
role="市场研究员",
goal="收集最新的 AI Agent 市场数据",
backstory="你是一位经验丰富的市场研究员,擅长数据收集和信息整合",
tools=[search_tool],
verbose=True
)
analyst = Agent(
role="数据分析师",
goal="分析研究数据,找出关键趋势",
backstory="你是一位精通数据分析的专家,善于从数据中发现规律",
verbose=True
)
writer = Agent(
role="报告撰写专家",
goal="将分析结果写成清晰专业的报告",
backstory="你是一位专业的商业报告撰写者",
verbose=True
)
# 定义任务
research_task = Task(
description="搜集2024年AI Agent市场规模、主要玩家和增长趋势数据",
agent=researcher,
expected_output="结构化的市场数据摘要"
)
analysis_task = Task(
description="基于收集的数据,分析市场机会和风险",
agent=analyst,
expected_output="SWOT分析和关键洞察"
)
writing_task = Task(
description="整合研究和分析结果,撰写2000字的市场报告",
agent=writer,
expected_output="完整的市场分析报告"
)
# 创建 Crew
crew = Crew(
agents=[researcher, analyst, writer],
tasks=[research_task, analysis_task, writing_task],
process=Process.sequential # 顺序执行
)
result = crew.kickoff()
print(result)
9. 代码实战:从零构建 ReAct Agent
python
"""
从零实现一个 ReAct Agent(不依赖 LangChain)
"""
import json
import re
from openai import OpenAI
from typing import Callable
# ===== 工具定义 =====
def calculator(expression: str) -> str:
"""计算数学表达式"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except Exception as e:
return f"计算错误: {e}"
def get_weather(city: str) -> str:
"""获取城市天气(模拟)"""
weather_data = {
"北京": "晴天,气温22°C,湿度40%",
"上海": "多云,气温25°C,湿度70%",
"广州": "阵雨,气温28°C,湿度85%",
}
return weather_data.get(city, f"未找到 {city} 的天气数据")
def search(query: str) -> str:
"""模拟搜索引擎"""
return f"[搜索结果模拟] 关于'{query}'的搜索结果:这里是相关信息摘要..."
# ===== ReAct Agent 实现 =====
class ReactAgent:
TOOLS = {
"calculator": calculator,
"get_weather": get_weather,
"search": search,
}
SYSTEM_PROMPT = """你是一个智能助手,可以使用以下工具:
- calculator(expression): 计算数学表达式,如 calculator("2 + 3 * 4")
- get_weather(city): 获取城市天气,如 get_weather("北京")
- search(query): 搜索信息,如 search("AI Agent最新进展")
请按照以下格式输出:
Thought: [你的推理过程]
Action: tool_name(参数)
Observation: [等待工具返回结果]
...(可多轮)
Final Answer: [最终回答]
重要:一次只调用一个工具,等待 Observation 后再继续。"""
def __init__(self):
self.client = OpenAI()
self.max_steps = 10
def _parse_action(self, text: str):
"""解析 Action: tool_name(args) 格式"""
pattern = r'Action:\s*(\w+)\(([^)]*)\)'
match = re.search(pattern, text)
if match:
tool_name = match.group(1)
args = match.group(2).strip().strip('"\'')
return tool_name, args
return None, None
def run(self, user_input: str) -> str:
"""运行 Agent"""
messages = [
{"role": "system", "content": self.SYSTEM_PROMPT},
{"role": "user", "content": user_input}
]
for step in range(self.max_steps):
response = self.client.chat.completions.create(
model="gpt-4o",
messages=messages,
stop=["Observation:"], # 在 Observation 处停止,等待工具调用
temperature=0,
)
assistant_text = response.choices[0].message.content
messages.append({"role": "assistant", "content": assistant_text})
# 检查是否有最终答案
if "Final Answer:" in assistant_text:
final = assistant_text.split("Final Answer:")[-1].strip()
return final
# 解析并执行工具调用
tool_name, args = self._parse_action(assistant_text)
if tool_name and tool_name in self.TOOLS:
result = self.TOOLS[tool_name](args)
observation = f"Observation: {result}\n"
print(f"[调用工具] {tool_name}({args}) → {result}")
messages.append({"role": "user", "content": observation})
else:
messages.append({"role": "user", "content": "Observation: 无效的工具调用,请重试\n"})
return "达到最大步骤数,任务未完成"
# ===== 测试 =====
if __name__ == "__main__":
agent = ReactAgent()
test_questions = [
"北京现在天气怎么样?气温换算成华氏度是多少?",
"搜索一下AI Agent的最新进展,并计算 2^10 的值",
]
for q in test_questions:
print(f"\n{'='*50}")
print(f"问题:{q}")
print(f"{'='*50}")
answer = agent.run(q)
print(f"最终答案:{answer}")
10. Agent 开发踩坑总结
常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Agent 陷入循环 | 没有停止条件 | 设置最大步骤数 + 检测重复 Action |
| 工具调用格式错误 | LLM 输出不稳定 | 使用 Function Calling API,更可靠 |
| 长任务上下文溢出 | 消息历史过长 | 对历史消息进行摘要压缩 |
| 并发 Agent 冲突 | 共享状态被并发修改 | 使用锁或消息队列隔离状态 |
| 推理费用过高 | 多步骤消耗大量 Token | 减少工具选项,优化 System Prompt |
Agent 可靠性提升技巧
- Human-in-the-loop:关键操作(发邮件、删除文件)前请求人工确认
- 工具调用日志:记录所有工具调用,便于调试和审计
- 超时机制:每个工具调用设置超时时间
- 幂等性设计:确保工具可以安全地重复调用