🤖 前置依赖:已掌握基础 LLM API 调用、Prompt 工程与 Function Calling。
若基础尚未扎实,请先阅读 LLM API 基础调用指南 和 Prompt 工程深度指南。
1. 从对话到行动:为什么需要智能体?
大语言模型本质上是被动响应器—你输入,它输出。但现实世界的问题往往需要多步推理、状态跟踪和外部工具调用。例如:
- 订机票:搜索航班 → 比价 → 填写预订 → 支付 → 发送确认
- 竞品分析:抓取竞品价格 → 分析功能差异 → 生成对比报告 → 制作可视化图表
- 代码审查:读取 PR → 分析变更 → 运行测试 → 检查安全漏洞 → 撰写评审意见
智能体将 LLM 从文本生成器升级为自主执行引擎,让它能够观察世界、做出决策、调用工具、记录结果、反思优化—循环往复直至目标达成。
2. 智能体的五大核心组件
┌─────────────────────────────────────────┐
│ 感知(Perception) │ ← 输入:用户目标、环境状态、工具返回值
├─────────────────────────────────────────┤
│ 推理(Reasoning) │ ← 核心:如何思考、如何计划、如何反思
├─────────────────────────────────────────┤
│ 记忆(Memory) │ ← 持久化:对话历史、经验沉淀、矢量检索
├─────────────────────────────────────────┤
│ 工具(Tools) │ ← 扩展:API 调用、代码执行、数据库查询
├─────────────────────────────────────────┤
│ 执行(Execution) │ ← 行动:调用工具、返回结果、生成回复
└─────────────────────────────────────────┘
2.1 感知(Perception)
感知层负责将外部信息转化为模型可理解的格式。常见策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 直接注入 | 用户输入直接喂给模型 | 简单问答 |
| 结构化摘要 | 用模板抽取关键字段 | API 返回数据 |
| 检索增强 | 从知识库检索相关上下文 | 知识密集型任务 |
| 多模态融合 | 图像/音频转文本描述 | 需要视觉/听觉感知的任务 |
| 环境快照 | 捕获当前状态(如浏览器 DOM) | 网页自动化 |
2.2 推理(Reasoning)
推理是智能体的"大脑"。主流推理模式包括:
1) Chain-of-Thought (CoT)
一步一步地思考。在 Prompt 中加入 “Let’s think step by step” 即可激活。
2) Tree-of-Thought (ToT)
维护一棵搜索树,每个节点是一种可能的推理路径。用投票或评分机制选择最优路径。适合需要探索多个方案的问题(如数学证明、代码生成)。
3) ReAct (Reasoning + Acting)
交替执行 Thought → Action → Observation:先思考,再行动,基于工具返回再思考。这是当前 Agent 应用最广泛的框架模式。
4) Reflexion
在 ReAct 基础上增加自我反思:当任务失败或结果不理想时,系统分析失败原因并调整策略。
| 推理模式 | 核心思想 | 适用场景 | 代表框架 |
|---|---|---|---|
| CoT | 单步推理链条 | 数学计算、逻辑推断 | 所有 LLM |
| ToT | 多路分支 + 回溯 | 开放式问题、创意生成 | DSPy, entropix |
| ReAct | 推理-行动交替循环 | 工具调用、信息检索 | LangChain, AutoGPT |
| Reflexion | 带反思的 ReAct | 持续改进型任务 | Self-Refine, Reflexion |
2.3 记忆(Memory)
记忆系统决定了 Agent 的上下文延续能力。
记忆层级
├── 工作记忆(Working Memory)
│ └── 当前对话的最近 N 轮
├── 短期记忆(Short-term Memory)
│ └── 可缓存的对话摘要、工具结果
├── 长期记忆(Long-term Memory)
│ ├── 事实性知识(向量数据库检索)
│ └── 经验性知识(历史任务的成败记录)
└── 外部记忆(External Memory)
└── 笔记、文档、网页、数据库
实现建议:
- 对话超出窗口 → 用滑动窗口摘要(每 K 轮做一次摘要)
- 事实检索 → 存入 Chroma / Pinecone / Milvus 等向量库
- 经验积累 → 用结构化 JSON 记录 Task → Strategy → Result → Feedback
2.4 工具(Tools)
工具将 Agent 的能力边界无限扩展。
# 工具签名规范(OpenAI function calling 风格)
{
"type": "function",
"function": {
"name": "search_flight",
"description": "搜索指定日期和目的地的航班。",
"parameters": {
"type": "object",
"properties": {
"origin": {"type": "string", "description": "出发城市代码"},
"destination": {"type": "string", "description": "到达城市代码"},
"date": {"type": "string", "description": "出发日期(YYYY-MM-DD)"}
},
"required": ["origin", "destination", "date"]
}
}
}
2.5 执行(Execution)
执行层负责实际调用工具、处理异常、管理状态。
关键设计原则:
- 幂等性:同一参数的工具调用返回相同结果(避免重复付费)
- 超时控制:每个工具调用设 10-30 秒上限
- 并发限制:同时对同一 API 的并发数设上限
- 错误降级:工具失败时,用备用方案或向用户解释
3. ReAct 模式详解
ReAct = Reasoning + Acting。它通过交错式的思考和行动,让 LLM 在每一步都明确自己的意图再行动。
3.1 交互循环
输入:用户目标 "查一下从上海到北京 8 月 10 日的便宜的机票"
循环 1:
Thought: 用户要查机票,需要调用 search_flight 工具。
参数:origin=上海 → PVG, destination=北京 → PEK, date=2024-08-10
Action: search_flight(origin="PVG", destination="PEK", date="2024-08-10")
Observation: [航班列表:MU5161 ¥580, CA1850 ¥620, ...]
循环 2:
Thought: 找到了航班列表,需要过滤出便宜的选择。
MU5161(¥580)和 CA1850(¥620)都是不错的选择。
Action: 无需进一步调用,直接回复用户。
Observation: (无)
回复:"为您找到上海 → 北京 8 月 10 日的航班..."
3.2 Prompt 模板
你是智能助理 Agent,负责帮助用户完成目标。
可用工具:
- search_flight(origin, destination, date): 搜索航班
- compare_price(flight_list): 比较价格
- book_ticket(flight_id, passenger): 预订机票
规则:
1. 每次只能调用一个工具
2. 调用工具前,先用 <Thought> 说明你的推理过程
3. 工具返回后,用 <Observation> 记录结果
4. 任务完成时,直接回复用户
历史记录:
{{memory}}
用户目标:{{goal}}
4. 可运行 Python 示例
4.1 基础 ReAct Agent
import os, json, re, openai
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# ====== 工具函数 ======
def search_flight(origin: str, destination: str, date: str):
"""Mock 搜索航班"""
return [
{"id": "MU5161", "price": 580, "time": "08:00-10:30"},
{"id": "CA1850", "price": 620, "time": "14:00-16:20"},
{"id": "MU5133", "price": 690, "time": "19:00-21:30"},
]
def compare_price(flight_ids):
return f"价格排序: MU5161(¥580) < CA1850(¥620) < MU5133(¥690)"
TOOLS = {
"search_flight": search_flight,
"compare_price": compare_price,
}
# ====== Agent 类 ======
class ReActAgent:
def __init__(self, client):
self.client = client
self.memory = []
self.max_loop = 10
SYSTEM_PROMPT = """你是一个智能订票代理 Agent。每次只能执行一个操作。
可用工具:search_flight(origin, destination, date), compare_price(flight_ids)
你必须按格式回复:
Thought: [推理过程]
Action: 工具名称(参数) 或 "完成"
"""
def call_tool(self, action_str):
m = re.match(r'(\w+)\((.*)\)', action_str)
if not m:
return "格式错误"
name, args = m.group(1), m.group(2)
# 简单参数解析(生产环境请用 ast.literal_eval)
try:
arg_dict = eval(f"dict({args})")
return TOOLS[name](**arg_dict)
except Exception as e:
return f"工具调用错误: {e}"
def run(self, goal: str):
self.memory.append({"role": "user", "content": goal})
for _ in range(self.max_loop):
messages = [
{"role": "system", "content": self.SYSTEM_PROMPT},
*self.memory,
]
resp = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.2,
)
content = resp.choices[0].message.content
self.memory.append({"role": "assistant", "content": content})
# 提取 Thought 和 Action
thought = re.search(r'Thought:\s*(.*?)(?:\n|$)', content, re.DOTALL)
action = re.search(r'Action:\s*(.*?)(?:\n|$)', content, re.DOTALL)
if action:
action_str = action.group(1).strip()
if "完成" in action_str or not action_str:
print("✅ 任务完成")
return content
# 调用工具
result = self.call_tool(action_str)
obs = f"Observation: {json.dumps(result, ensure_ascii=False)}"
self.memory.append({"role": "user", "content": obs})
print(f"🧠 Thought: {thought.group(1).strip() if thought else 'N/A'}")
print(f"🔧 Action: {action_str}")
print(f"📊 {obs}")
else:
break
# 运行
agent = ReActAgent(client)
result = agent.run("帮我查 2024-08-10 从上海到北京最便宜的机票")
print("\n=== 最终回复 ===\n", result)
4.2 带向量记忆的 Agent
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.tools import Tool
# 初始化组件
llm = ChatOpenAI(model="gpt-4o-mini")
embedding = OpenAIEmbeddings()
vectorstore = Chroma(embedding_function=embedding, persist_directory="./chroma_db")
# 创建检索工具
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
def retrieve_context(query):
docs = retriever.invoke(query)
return "\n".join([d.page_content for d in docs])
retrieval_tool = Tool.from_function(
func=retrieve_context,
name="knowledge_retrieval",
description="从历史文档和公司知识库中检索相关信息。",
)
# Prompt 模板(带记忆插槽)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个客服 Agent。使用知识库回答用户问题。"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
# 创建 Agent
agent = create_openai_functions_agent(llm, [retrieval_tool], prompt)
executor = AgentExecutor(agent=agent, tools=[retrieval_tool], verbose=True)
# 运行
response = executor.invoke({
"input": "我们公司支持哪些支付方式?",
"chat_history": []
})
5. 生产级安全护栏
┌─────────────────────────────────────┐
│ 输入护栏 (Input Guards) │
│ - Prompt Injection 检测 │
│ - SQL 注入 / XSS 过滤 │
│ - 敏感信息 PII 脱敏 │
├─────────────────────────────────────┤
│ 工具护栏 (Tool Guards) │
│ - 参数 Schema 校验 │
│ - 权限检查(RBAC) │
│ - 速率限制与熔断 │
├─────────────────────────────────────┤
│ 输出护栏 (Output Guards) │
│ - 有害内容检测 │
│ - 事实一致性验证 │
│ - 合规审计日志 │
└─────────────────────────────────────┘
必备防御规则:
- Prompt Injection 检测 — 在输入中检测 “ignore previous instructions”、“you are now in DAN mode” 等攻击向量
- 工具参数校验 — 所有工具参数必须经过 Pydantic Schema 校验
- 人审触发器 — 高风险操作(如支付、删除数据)必须人工确认
- 沙箱执行 — 代码生成必须在受限环境中运行(如 Docker、WASM)
6. 常见架构反模式
| 反模式 | 问题 | 建议 |
|---|---|---|
| 过度规划 | Agent 在简单问题上花太多步数 | 为简单任务设置单步快速通道 |
| 记忆泄漏 | 敏感对话混入公共上下文 | 按用户/会话隔离记忆 |
| 工具蔓延 | 工具太多导致模型选择困难 | 按领域分组,<10 个活跃工具 |
| 幻觉自信 | Agent 基于虚构的 Observation 继续推理 | 要求模型明确标注信息来源 |
| 无限循环 | 没有终止条件导致死循环 | max_loop 限制 + 循环检测 |
| 权限过宽 | Agent 可以调用所有 API | 最小权限原则 + OAuth scope |
7. 生产部署与成本优化
7.1 模型选择策略
| 层级 | 模型 | 用途 | 成本 |
|---|---|---|---|
| 路由层 | 规则/小模型 | 意图分类 | ~零 |
| 思考层 | GPT-4o-mini / Claude 3 Haiku | 推理 Planning | $ |
| 执行层 | GPT-4o / Claude 3.5 Sonnet | 复杂任务 + 代码 | $$ |
| 质检层 | Claude 3.5 Sonnet / GPT-4o | 输出审核(可选) | $$ |
7.2 成本估算
对于 1000 次订票查询:
- GPT-4o-mini 做路由 + 规划:~200K tokens ≈ $0.06
- GPT-4o 处理复杂逻辑:~50K tokens ≈ $0.50
- 工具调用 API 费用:取决于第三方 API(如 Skyscanner)
- 总计:约 $0.56 / 1000 次(不含第三方)
7.3 缓存策略
- LLM 响应缓存:相同输入的推理结果缓存 5min
- 工具结果缓存:查询结果 TTL=1h
- 向量索引缓存:频繁查询的 TopK 结果常驻内存
8. 总结与选型建议
| 你的场景 | 推荐模式 | 框架 | 起步复杂度 |
|---|---|---|---|
| 简单工具流 | ReAct + 2-3 个工具 | LangChain | ⭐⭐ |
| 需要长期记忆 | ReAct + 向量库 | LangChain + Chroma | ⭐⭐⭐ |
| 多智能体协作 | CrewAI / AutoGen | CrewAI | ⭐⭐⭐ |
| 动态规划 | Plan-and-Solve / ToT | DSPy | ⭐⭐⭐⭐ |
| 代码生成 | ReAct + Code Interpreter | OpenAI Code Interpreter | ⭐⭐ |
| 端到端 RPA | AutoGPT (无头浏览器) | AutoGPT + Playwright | ⭐⭐⭐⭐⭐ |
📂 继续阅读:
- AI 智能体多智能体协作与编排 — CrewAI、AutoGen、多智能体通信协议
- Agent 工作流编排设计 — DAG、状态机、暂停/恢复机制
- LLM Agent 安全与评估 — 红队测试、对齐、审计
高价值 FAQ
Q: ReAct 和 AutoGPT 有什么区别?
A: ReAct 是推理模式(理解 → 行动 → 观察),AutoGPT 是实现框架(目标分解 + 记忆 + 工具 + 自主迭代)。你可以用 AutoGPT 来运行 ReAct,也可以用 LangChain 来运行 ReAct。
Q: Agent 和 RAG 怎么结合?
A: RAG 解决知识获取问题,Agent 解决任务执行问题。最佳实践是:将 RAG 封装为一个知识检索工具,Agent 在推理过程中自主决定何时调用这个工具获取知识。
Q: 单智能体和多个单智能体组合,哪个更可靠?
A: 经验法则:简单任务用单智能体,复杂任务用多智能体。单智能体的错误传播短、调试简单;多智能体并行度高、职责更清晰但通信开销和一致性成本更高。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。