Agent 设计模式
在 AI Native 应用中,Agent 是核心的智能单元。本文将深入探讨 Agent 的设计原则、架构模式和最佳实践。
什么是 Agent
Agent 是一个能够感知环境、做出决策并采取行动的自主实体。在 LLM 时代,Agent 通常由以下组件构成:
- 大语言模型 (LLM):作为 Agent 的"大脑",负责理解、推理和决策
- 记忆系统 (Memory):存储对话历史、用户偏好和长期知识
- 工具集 (Tools):扩展 Agent 的能力边界,如搜索、代码执行、API 调用等
- 规划模块 (Planning):将复杂任务分解为可执行的子任务
┌─────────────────────────────────────────────────────────┐
│ Agent │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ LLM │ │ Memory │ │ Tools │ │
│ │ (Reasoning)│ │ (Context) │ │ (Capabilities) │ │
│ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
│ │ │ │ │
│ └────────────────┼───────────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Planning │ │
│ │ (Strategy) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
核心设计原则
1. 单一职责原则 (重要)
每个 Agent 应该专注于一个明确的领域或任务。避免创建"万能 Agent",而是设计多个专业化的 Agent 协同工作。
# 不推荐:一个 Agent 处理所有事情
class UniversalAgent:
def handle(self, query):
# 处理客服、数据分析、代码生成...
pass
# 推荐:专业化的 Agent
class CustomerServiceAgent:
"""专注于客户服务场景"""
pass
class DataAnalysisAgent:
"""专注于数据分析任务"""
pass
class CodeAssistantAgent:
"""专注于代码辅助"""
pass
2. 可观测性优先
Agent 的决策过程应该是透明可追踪的。记录每一步推理、工具调用和决策依据。
class ObservableAgent:
def __init__(self):
self.trace = []
def think(self, context: str) -> str:
thought = self.llm.reason(context)
self.trace.append({
"type": "thought",
"content": thought,
"timestamp": datetime.now()
})
return thought
def act(self, action: str) -> str:
result = self.execute(action)
self.trace.append({
"type": "action",
"action": action,
"result": result,
"timestamp": datetime.now()
})
return result
3. 优雅降级
当 Agent 遇到无法处理的情况时,应该能够优雅地降级,而不是崩溃或给出错误答案。
class ResilientAgent:
def handle(self, query: str) -> Response:
try:
# 尝试使用完整能力处理
return self.full_process(query)
except ToolUnavailableError:
# 工具不可用时,使用纯 LLM 推理
return self.llm_only_process(query)
except ConfidenceTooLowError:
# 置信度过低时,请求人工介入
return self.escalate_to_human(query)
except Exception as e:
# 兜底:承认无法处理
return Response(
status="failed",
message="抱歉,我暂时无法处理这个请求,已通知人工客服"
)
常见架构模式
ReAct 模式
ReAct (Reasoning + Acting) 是最经典的 Agent 模式,交替进行推理和行动。
Thought: 用户想查询北京的天气,我需要调用天气 API
Action: weather_api(city="北京")
Observation: 北京今天晴,气温 25°C
Thought: 我已经获取到天气信息,可以回复用户了
Answer: 北京今天天气晴朗,气温 25°C,适合外出活动。
class ReActAgent:
def run(self, query: str) -> str:
context = f"用户问题: {query}\n"
for _ in range(self.max_iterations):
# 思考
thought = self.llm.think(context)
context += f"Thought: {thought}\n"
# 判断是否需要行动
if self.should_act(thought):
action, params = self.parse_action(thought)
observation = self.tools[action](**params)
context += f"Action: {action}({params})\n"
context += f"Observation: {observation}\n"
else:
# 生成最终答案
return self.llm.answer(context)
return "达到最大迭代次数,无法完成任务"
Plan-and-Execute 模式
先制定完整计划,再逐步执行。适合复杂的多步骤任务。
class PlanAndExecuteAgent:
def run(self, query: str) -> str:
# 阶段1:制定计划
plan = self.planner.create_plan(query)
# plan = ["搜索相关文档", "提取关键信息", "生成摘要", "格式化输出"]
results = []
# 阶段2:逐步执行
for step in plan:
result = self.executor.execute(step, context=results)
results.append(result)
# 检查是否需要重新规划
if self.should_replan(step, result):
plan = self.planner.replan(query, results)
return self.synthesize(results)
Multi-Agent 协作模式
多个专业 Agent 协同完成复杂任务。
class MultiAgentOrchestrator:
def __init__(self):
self.agents = {
"researcher": ResearchAgent(),
"writer": WriterAgent(),
"reviewer": ReviewerAgent(),
}
def run(self, task: str) -> str:
# 研究员收集信息
research = self.agents["researcher"].run(task)
# 写作者生成初稿
draft = self.agents["writer"].run(
task=task,
research=research
)
# 审核者评审并提供反馈
review = self.agents["reviewer"].run(draft)
# 如果需要修改,循环迭代
while review.needs_revision:
draft = self.agents["writer"].revise(draft, review.feedback)
review = self.agents["reviewer"].run(draft)
return draft
记忆系统设计
短期记忆
存储当前对话上下文,通常使用滑动窗口或摘要压缩。
class ShortTermMemory:
def __init__(self, max_tokens: int = 4000):
self.messages = []
self.max_tokens = max_tokens
def add(self, message: dict):
self.messages.append(message)
self._compress_if_needed()
def _compress_if_needed(self):
while self._count_tokens() > self.max_tokens:
# 策略1:移除最早的消息
# self.messages.pop(0)
# 策略2:摘要压缩
old_messages = self.messages[:5]
summary = self.llm.summarize(old_messages)
self.messages = [{"role": "system", "content": summary}] + self.messages[5:]
长期记忆
使用向量数据库存储和检索历史知识。
class LongTermMemory:
def __init__(self):
self.vector_store = VectorStore()
self.embedding_model = EmbeddingModel()
def store(self, content: str, metadata: dict = None):
embedding = self.embedding_model.encode(content)
self.vector_store.insert(
embedding=embedding,
content=content,
metadata=metadata
)
def retrieve(self, query: str, top_k: int = 5) -> list:
query_embedding = self.embedding_model.encode(query)
return self.vector_store.search(query_embedding, top_k=top_k)
工具设计最佳实践
1. 清晰的工具描述
工具描述决定了 LLM 能否正确理解和使用工具。
# 不推荐:模糊的描述
@tool(description="搜索")
def search(query: str):
pass
# 推荐:详细清晰的描述
@tool(
name="web_search",
description="""
在互联网上搜索信息。适用于:
- 查询最新新闻和事件
- 获取实时数据(股价、天气等)
- 搜索特定网站或文档
不适用于:
- 查询用户的私有数据
- 需要登录才能访问的内容
""",
parameters={
"query": {
"type": "string",
"description": "搜索关键词,建议使用精确的关键词组合"
},
"num_results": {
"type": "integer",
"description": "返回结果数量,默认5条",
"default": 5
}
}
)
def web_search(query: str, num_results: int = 5):
pass
2. 错误处理和重试
@tool(name="api_call")
def api_call(endpoint: str, params: dict) -> dict:
for attempt in range(3):
try:
response = requests.get(endpoint, params=params, timeout=10)
response.raise_for_status()
return {"success": True, "data": response.json()}
except requests.Timeout:
if attempt == 2:
return {"success": False, "error": "请求超时,请稍后重试"}
except requests.HTTPError as e:
return {"success": False, "error": f"API 错误: {e.response.status_code}"}
return {"success": False, "error": "未知错误"}
安全考虑
1. Prompt 注入防护
class SecureAgent:
def sanitize_input(self, user_input: str) -> str:
# 检测潜在的 prompt 注入
injection_patterns = [
r"ignore previous instructions",
r"system prompt",
r"你是一个",
]
for pattern in injection_patterns:
if re.search(pattern, user_input, re.IGNORECASE):
raise SecurityError("检测到潜在的 prompt 注入")
return user_input
def run(self, query: str) -> str:
safe_query = self.sanitize_input(query)
return self._process(safe_query)
2. 工具调用权限控制
class PermissionManager:
def __init__(self):
self.permissions = {
"read_file": ["admin", "developer"],
"write_file": ["admin"],
"execute_code": ["admin"],
"web_search": ["admin", "developer", "user"],
}
def check(self, tool: str, user_role: str) -> bool:
allowed_roles = self.permissions.get(tool, [])
return user_role in allowed_roles
性能优化
1. 并行工具调用
import asyncio
class ParallelAgent:
async def run_tools_parallel(self, tool_calls: list) -> list:
tasks = [
self.execute_tool(call["name"], call["params"])
for call in tool_calls
]
return await asyncio.gather(*tasks)
2. 缓存策略
from functools import lru_cache
class CachedAgent:
@lru_cache(maxsize=1000)
def get_embedding(self, text: str) -> list:
return self.embedding_model.encode(text)
def search_with_cache(self, query: str) -> list:
# 相同查询直接返回缓存结果
cache_key = hashlib.md5(query.encode()).hexdigest()
if cache_key in self.search_cache:
return self.search_cache[cache_key]
result = self.vector_store.search(query)
self.search_cache[cache_key] = result
return result
总结
设计一个优秀的 Agent 需要考虑多个维度:
- 架构选择:根据任务复杂度选择 ReAct、Plan-and-Execute 或 Multi-Agent 模式
- 记忆管理:合理设计短期和长期记忆,平衡上下文长度和信息完整性
- 工具设计:提供清晰的描述,做好错误处理
- 安全防护:防范 prompt 注入,控制工具权限
- 性能优化:使用并行调用和缓存提升响应速度
Agent 设计是一个不断演进的领域,随着 LLM 能力的提升,我们可以期待更强大、更智能的 Agent 架构出现。