Agent 不是一个简单的 LLM 封装。它是一个自主决策系统——接收目标,规划步骤,调用工具,处理异常,持续迭代,直到目标达成。
与普通 LLM 调用的本质区别:
| 维度 | 普通 LLM 调用 | Agent 系统 |
|---|---|---|
| 控制流 | 单次请求-响应 | 多步循环,自主决策下一步 |
| 工具 | 无或固定 | 动态选择、组合、创建 |
| 状态 | 无状态 | 需要记忆、上下文管理 |
| 错误处理 | 抛异常 | 自修复、重试、降级 |
| 终止条件 | 响应完成 | 目标达成或预算耗尽 |
ReAct + Function Calling 已经成为 Agent 架构的事实标准。
从 20 个项目中提炼出的六种架构模式,覆盖从简单到复杂的全部场景:
ReAct(Reasoning + Acting)是 Agent 的"Hello World"。9/20 项目以此为核心。
谁做得最好:
while not is_done: 一目了然Python 实现(Smolagents 风格):
class ReactAgent:
def __init__(self, model, tools, max_steps=10):
self.model = model
self.tools = {t.name: t for t in tools}
self.max_steps = max_steps
def run(self, task: str) -> str:
messages = [{"role": "user", "content": task}]
for step in range(self.max_steps):
# Think: LLM 决定下一步
response = self.model.chat(messages)
messages.append({"role": "assistant", "content": response})
# 解析:提取动作和参数
action = self.parse_action(response)
if action is None: # 没有动作 = 完成
return response
# Act: 执行工具
tool_name, tool_input = action
if tool_name not in self.tools:
observation = f"Error: Tool '{tool_name}' not found"
else:
try:
observation = self.tools[tool_name].run(tool_input)
except Exception as e:
observation = f"Error: {e}"
# Observe: 把结果喂回 LLM
messages.append({
"role": "user",
"content": f"Observation: {observation}"
})
return "Max steps reached"
# 使用
agent = ReactAgent(
model=LiteLLM("gpt-4o"),
tools=[WebSearch(), FileRead(), CodeRun()],
)
result = agent.run("查找 Python 3.13 的新特性并写一个摘要")
先规划,再执行。适合步骤相对固定的场景,如数据处理流水线、代码生成。
谁做得最好:
# Plan-Execute 模式
class PlanExecuteAgent:
def __init__(self, planner_model, executor_model, tools):
self.planner = planner_model
self.executor = executor_model
self.tools = tools
def run(self, task: str) -> str:
# Phase 1: Plan
plan = self.planner.chat(
f"将以下任务分解为具体步骤:\n{task}\n"
"输出 JSON 格式: {\"steps\": [...]}"
)
steps = json.loads(plan)["steps"]
# Phase 2: Execute
results = []
for i, step in enumerate(steps):
result = self.executor.run(step, self.tools)
results.append(result)
# Phase 3: Replan if needed
if self.needs_replan(result, steps[i:]):
updated_plan = self.planner.chat(
f"步骤 {i} 的结果与预期不符:{result}\n"
f"剩余步骤:{steps[i+1:]}\n"
"请更新计划:"
)
steps = json.loads(updated_plan)["steps"]
return "\n".join(results)
用显式状态转移替代隐式的 LLM 决策。适合需要严格流程控制的企业场景。
谁做得最好:
# LangGraph 风格的状态机
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
messages: list
next_action: str
retry_count: int
def analyze(state):
# 分析用户输入
result = llm.invoke(state["messages"])
return {"next_action": result.action, "messages": [result]}
def plan(state):
# 生成计划
plan = llm.invoke(f"制定计划:{state['messages'][-1]}")
return {"messages": [plan]}
def execute(state):
# 执行工具
result = tool_executor.run(state["messages"][-1].tool_calls)
return {"messages": [result], "retry_count": 0}
def should_plan(state):
if state["next_action"] == "complex":
return "plan"
return "execute"
# 构建图
graph = StateGraph(AgentState)
graph.add_node("analyze", analyze)
graph.add_node("plan", plan)
graph.add_node("execute", execute)
graph.add_conditional_edges("analyze", should_plan)
graph.add_edge("plan", "execute")
graph.add_edge("execute", END)
app = graph.compile()
每个 Agent 是独立的 Actor,通过消息传递通信。适合需要 Agent 间协商、辩论的场景。
谁做得最好:
# AutoGen 风格的 Actor Model
from autogen import ConversableAgent, GroupChat, GroupChatManager
researcher = ConversableAgent(
"researcher",
system_message="你是研究员,负责收集信息",
llm_config={"model": "gpt-4o"},
human_input_mode="NEVER",
)
writer = ConversableAgent(
"writer",
system_message="你是写作者,负责根据研究结果写文章",
llm_config={"model": "gpt-4o"},
human_input_mode="NEVER",
)
reviewer = ConversableAgent(
"reviewer",
system_message="你是审稿人,负责检查文章质量",
llm_config={"model": "gpt-4o"},
human_input_mode="NEVER", # 或 "TERMINATE" 需要人工终审
)
# 群组对话
group_chat = GroupChat(
agents=[researcher, writer, reviewer],
messages=[],
max_round=10,
speaker_selection_method="round_robin", # 或 "auto" (LLM选择)
)
manager = GroupChatManager(groupchat=group_chat)
researcher.initiate_chat(
manager,
message="请研究 AI Agent 架构的最新进展并写一篇综述",
)
一个中心编排器分配任务给专业 Worker。适合流水线式的复杂任务。
谁做得最好:
# MetaGPT 风格的 SOP 编排
from metagpt.roles import Role
from metagpt.schema import Message
class ProductManager(Role):
name: str = "Alice"
profile: str = "Product Manager"
async def _act(self) -> Message:
# 生成 PRD
prd = await self._write_prd()
return Message(content=prd, role=self.profile)
class Architect(Role):
name: str = "Bob"
profile: str = "Architect"
async def _act(self) -> Message:
# 根据PRD设计系统架构
design = await self._design_system()
return Message(content=design, role=self.profile)
class Engineer(Role):
name: str = "Charlie"
profile: str = "Engineer"
async def _act(self) -> Message:
# 根据设计写代码
code = await self._write_code()
return Message(content=code, role=self.profile)
# SOP:PM → Architect → Engineer
async def software_sop(requirement: str):
pm = ProductManager()
architect = Architect()
engineer = Engineer()
prd_msg = await pm.run(requirement)
design_msg = await architect.run(prd_msg)
code_msg = await engineer.run(design_msg)
return code_msg
Agent 不仅执行任务,还能反思自己的表现、修改自身行为。这是目前最前沿的方向。
谁做得最好:
工具是 Agent 的"手和脚"。工具系统的设计直接决定 Agent 的能力边界。
JSON Schema 定义工具签名,LLM 输出结构化调用。
{
"name": "web_search",
"description": "搜索互联网",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"max_results": {"type": "integer"}
},
"required": ["query"]
}
}
Python 类型注解 → 自动生成 Schema + 运行时验证。
from pydantic import BaseModel
class SearchArgs(BaseModel):
query: str
max_results: int = 5
@agent.tool
async def web_search(
ctx: RunContext,
args: SearchArgs,
) -> str:
results = await search(args.query)
return results[:args.max_results]
Shell 脚本 + YAML 定义,容器内执行。
# search.yaml
name: search
command: ./scripts/search.sh
args:
- name: query
type: string
- name: max_results
type: integer
default: 5
不同工具有不同的风险等级。好的工具系统不是一刀切,而是分级的:
| 级别 | 描述 | 示例 | 项目 |
|---|---|---|---|
| GREEN | 只读、无副作用 | web_search, file_read | 所有项目 |
| YELLOW | 有副作用但可逆 | file_write, git_commit | Codex CLI (需确认) |
| RED | 不可逆或有风险 | rm, deploy, send_email | OpenClaw (Policy Pipeline) |
最佳实践组合(参考 安全机制):
# OpenClaw 风格的 Policy Pipeline
class ToolPolicy:
def check(self, tool: str, args: dict) -> PolicyResult:
tool_def = self.registry.get(tool)
# 1. 静态规则检查
if tool_def.risk_level == "RED":
if not self.user_approved(tool, args):
return PolicyResult(deny=True, reason="需要用户审批")
# 2. 动态上下文检查(Hermes 风格)
threats = self.threat_scanner.scan(args)
if threats:
return PolicyResult(deny=True, reason=f"检测到威胁: {threats}")
# 3. 沙箱执行(SWE-agent/OpenHands 风格)
if tool_def.requires_sandbox:
return PolicyResult(sandbox=True)
return PolicyResult(allow=True)
# Codex CLI 风格的三级 Profile
class ApprovalProfile:
SUGGEST = "suggest" # 建议但不阻止
AUTO_EDIT = "auto-edit" # 文件编辑自动通过
FULL_AUTO = "full-auto" # 全自动(危险!)
当工具数量超过 10 个,LLM 选错工具的概率急剧上升。两个解决方案:
这是 Agent 架构中最被低估的模块。上下文窗口有限,如何高效利用是核心挑战。
从无状态到自进化,记忆系统的 5 个层级:
| 级别 | 名称 | 特点 | 代表项目 |
|---|---|---|---|
| L0 | 无状态 | 每次调用全新开始 | 最简单的 ChatGPT wrapper |
| L1 | 对话历史 | 保留最近 N 轮对话 | 大多数项目的默认模式 |
| L2 | 摘要压缩 | 历史对话压缩为摘要 | OpenHands (LLMSummarizingCondenser) |
| L3 | 检索增强 | 向量数据库 + 语义检索 | Agent Zero (3区域FAISS), GPT Researcher |
| L4 | 自进化记忆 | 经验累积 + 行为调整 | Hermes (HRR + 信任评分) |
OpenHands 的 LLMSummarizingCondenser 是目前最优雅的解决方案:
# OpenHands 风格的 Condenser
class Condenser:
"""上下文压缩器——把无限历史压缩进有限窗口"""
def condense(self, events: list[Event], max_tokens: int) -> list[Event]:
current_tokens = sum(e.token_count for e in events)
if current_tokens <= max_tokens:
return events # 不需要压缩
# 策略 1: 丢弃旧的观察结果(保留动作)
events = self._drop_old_observations(events)
if self._token_count(events) <= max_tokens:
return events
# 策略 2: 摘要压缩早期历史
early, recent = self._split(events, ratio=0.4)
summary = self.llm.summarize(early)
return [SummaryEvent(summary)] + recent
def _drop_old_observations(self, events):
"""只保留最近 N 次工具返回的完整结果,旧的结果截断"""
obs_count = 0
result = []
for e in reversed(events):
if e.type == "observation":
obs_count += 1
if obs_count > 5: # 只保留最近5次
e = e.truncate(max_chars=200)
result.append(e)
return list(reversed(result))
当 Agent 操作代码仓库时,如何把几千个文件塞进有限的上下文?Aider 的 RepoMap 用 PageRank 算法解决:
# Aider RepoMap 简化原理
class RepoMap:
def get_repo_map(self, chat_files: list[str]) -> str:
# 1. 解析所有文件的 AST,提取定义和引用
tags = self._get_tags() # {filepath: [(name, kind, line), ...]}
# 2. 构建引用图:谁引用了谁
G = self._build_graph(tags)
# 3. PageRank 排序——被引用最多的定义最重要
rankings = pagerank(G)
# 4. 只保留 Top-K 重要的定义,用压缩格式输出
top_tags = sorted(tags, key=lambda t: rankings[t], reverse=True)
map_str = ""
for tag in top_tags:
if len(map_str) > MAX_MAP_TOKENS:
break
map_str += f"{tag.filepath}:{tag.line} {tag.name}\n"
return map_str # 几千文件 → 几百行摘要
Agent 的 prompt 不是写一次就完事——它是动态组装的,每次调用可能不同。
# Hermes 风格的三层 Prompt 组装
class PromptComposer:
def compose(self, agent, user_input, memory, tools):
parts = []
# Layer 1: Identity (静态,可缓存)
parts.append(self._identity_block(agent))
parts.append(self._capabilities_block(agent))
# Layer 2: Context (动态,每轮变化)
parts.append(self._memory_block(memory))
parts.append(self._tools_block(tools))
parts.append(self._user_input_block(user_input))
# Layer 3: Safety (静态,可缓存)
parts.append(self._safety_guardrails())
parts.append(self._output_format_spec())
return "\n\n".join(parts)
OpenClaw 的 Cache Boundary 是提示词缓存的教科书级实现:
# OpenClaw Cache Boundary 原理
#
# LLM API 的 Prompt Cache 机制:
# - 前缀匹配的 prompt 只计算一次
# - 后续请求如果前缀不变,只计算新增部分
#
# 关键:把静态内容放在前面,动态内容放在后面!
COMPOSED_PROMPT = """
[SYSTEM - 静态,可缓存] ← Cache Boundary
├── 角色定义 ← 几乎不变
├── 工具描述 ← 偶尔变
├── 安全约束 ← 几乎不变
│
[CACHE BOUNDARY] ← 在此插入标记
│
[USER - 动态,不缓存]
├── 记忆检索结果 ← 每轮变化
├── 当前对话 ← 每轮变化
└── 用户最新输入 ← 每轮变化
"""
# 实现效果:
# 第1轮: 计算全部 4000 tokens
# 第2轮: 只计算新增 ~500 tokens (前缀命中缓存)
# 节省: ~87% token 计算成本
system、repo_map、context、chat 四个 chunk,每个 chunk 独立缓存,只有变化的 chunk 重新计算。
Agent 运行在不确定的环境中——LLM 输出不稳定、工具调用失败、网络超时。容错设计是生产系统的心脏。
最简单的容错。LLM 输出格式错误?重试。工具超时?重试。
关键参数:
简单 必须
SWE-agent 的 RetryAgent + Reviewer:生成多个方案,Reviewer 选最佳。
适用:高价值任务(如代码修复),一次失败代价高。
中等 推荐
OpenHands 的 StuckDetector:5 种卡住模式检测。
中等 推荐
LangGraph 的 Checkpoint:每步持久化状态,失败后从检查点恢复。
适用:长时运行任务(>5 分钟),中断代价高。
复杂 推荐
# 综合:生产级容错 Agent
class ProductionAgent:
def __init__(self, ...):
self.retry_policy = RetryPolicy(max_retries=3, backoff="exponential")
self.stuck_detector = StuckDetector(
patterns=["repeat_action", "no_progress", "error_loop"],
window_size=5,
)
self.checkpointer = FileCheckpointer("./checkpoints/")
@checkpoint # 自动保存检查点
def run(self, task: str) -> str:
for step in range(self.max_steps):
# 卡住检测
if self.stuck_detector.is_stuck(self.history):
self.stuck_detector.intervene(self) # 注入反思 prompt
continue
# 带重试的执行
result = self.retry_policy.execute(
lambda: self._step(task),
retry_on=[OutputParseError, ToolTimeoutError],
)
if result.is_final:
return result.output
return "任务未完成(达到步数上限)"
当你确定需要多 Agent 时,选择哪种协作模式?
| 模式 | 适用场景 | 优点 | 缺点 | 代表 |
|---|---|---|---|---|
| Round Robin | 简单讨论/头脑风暴 | 实现简单,公平 | 无重点,容易跑题 | AutoGen |
| Selector (LLM 选) | 动态决定谁发言 | 灵活,有重点 | 额外 LLM 调用开销 | AutoGen |
| Swarm + Handoff | 层级指挥/接力 | 控制流清晰 | 需要精心设计 Handoff | AutoGen/OpenAI |
| DAG/State Machine | 有条件分支的流程 | 精确控制,可调试 | 定义复杂 | LangGraph |
| SOP/Orchestrator | 流水线式任务 | 角色清晰,可重复 | 不够灵活 | MetaGPT/CrewAI |
| SocietyOfMind | 嵌套团队(团队中包含子团队) | 可组合,可扩展 | 调试困难 | AutoGen |
把以上所有模块组合起来,一个生产级 Agent 系统的完整架构:
如果你想最快上线一个 Agent:
# 最小可行 Agent: ReAct + Function Calling + 对话历史
from litellm import completion
TOOLS = [
{"type": "function", "function": {
"name": "web_search", "description": "搜索互联网",
"parameters": {"type": "object", "properties": {
"query": {"type": "string"}}, "required": ["query"]}
}}
]
def run_agent(task: str, max_steps: int = 5) -> str:
messages = [{"role": "system", "content": "你是一个有用的助手。"},
{"role": "user", "content": task}]
for _ in range(max_steps):
resp = completion(model="gpt-4o", messages=messages, tools=TOOLS)
msg = resp.choices[0].message
messages.append(msg)
if msg.tool_calls is None:
return msg.content # Agent 完成
# 执行工具
for tc in msg.tool_calls:
result = execute_tool(tc.function.name,
json.loads(tc.function.arguments))
messages.append({"role": "tool",
"tool_call_id": tc.id,
"content": str(result)})
return "达到最大步数"
# 就这么简单。3 个函数,50 行代码。
加上安全、缓存、容错、记忆:
# 生产级 Agent 配置
class ProductionAgentConfig:
# 核心循环
loop_type: str = "react" # react | plan_execute | state_machine
# LLM 配置
model: str = "gpt-4o"
fallback_model: str = "claude-sonnet" # Failover
cache_boundary: bool = True # 提示词缓存
# 工具系统
tools: list[Tool] = []
tool_policy: PolicyPipeline = PolicyPipeline()
sandbox: bool = True # 工具在沙箱中执行
# 记忆系统
memory_level: int = 2 # 0-4, 推荐 L2
condenser: Condenser = LLMSummarizingCondenser(max_tokens=4000)
# 安全
human_approval_for: list[str] = ["RED"] # 需要人工审批的风险级别
threat_scanner: Scanner = ContextThreatScanner()
audit_log: bool = True
# 容错
max_retries: int = 3
stuck_detector: StuckDetector = StuckDetector()
checkpointer: Checkpointer = FileCheckpointer()
# 成本控制
max_tokens_per_run: int = 100_000
max_cost_per_run: float = 1.0 # USD
如果你不想从零构建,选择哪个框架?
| 框架 | 最适合 | 学习曲线 | 灵活性 | 生产就绪 |
|---|---|---|---|---|
| LangGraph | 复杂工作流、需要精确控制 | 中 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| AutoGen | 多 Agent 协作、对话式 | 中 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| CrewAI | 团队协作、流水线任务 | 低 | ⭐⭐⭐ | ⭐⭐⭐ |
| Smolagents | 快速原型、学习 Agent | 低 | ⭐⭐⭐ | ⭐⭐ |
| PydanticAI | 类型安全、Pythonic | 低 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Agno | 轻量级、快速开始 | 低 | ⭐⭐⭐ | ⭐⭐⭐ |
| Google ADK | Google 生态、A2A 协议 | 中 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 自建 | 完全控制、特殊需求 | 高 | ⭐⭐⭐⭐⭐ | 看你 |
80% 的任务单 Agent 就够。多 Agent 带来的协作复杂度(消息格式、状态同步、调试)远超想象。先用单 Agent 做,遇到瓶颈再加。
信号:如果你发现多个 Agent 之间频繁传大量上下文 → 可能应该合并为一个 Agent。
每一步都追加完整历史,5 轮后 token 就爆了。必须从第一天起就加入 Condenser 或摘要机制。
数据:一个 10 步的 ReAct 循环,不压缩约 20K tokens,压缩后 5K tokens。4 倍差距。
工具调用失败是常态,不是异常。每个工具调用都必须有 try-catch,返回错误信息给 LLM 让它重试,而不是直接抛异常终止。
必须有硬性上限:max_steps、max_tokens、max_cost。加上 StuckDetector。
用户输入中可能包含"忽略之前的指令"之类的攻击。必须做 Context Threat Scanning(参考 Hermes 的 60+ 威胁模式扫描)。
不懂 Cache Boundary,每次 LLM 调用都重新计算完整 prompt。成本和延迟都是 10 倍差距。参考 OpenClaw 和 Aider。
Agent 架构不是孤立的,它与 SaaS 全栈知识库的其他模块紧密关联:
| 关联模块 | 关联点 |
|---|---|
| 🧠 LLM 集成 | Agent 的大脑——Provider 选型、Failover、路由、成本控制 |
| 📚 RAG 架构 | Agent 的知识——检索增强生成,为 Agent 提供外部知识 |
| 🧮 向量数据库 | Agent 的 L3/L4 记忆的存储引擎 |
| 📝 提示词工程 | Agent 的语言——Cache Boundary、注入防护、输出控制 |
| 🦀 后端框架 | Agent 服务的宿主——FastAPI/Hono 提供 Agent API |
| 📋 异步任务 | 长时运行的 Agent 任务需要异步队列——Inngest/Temporal |
| 💾 缓存策略 | Agent 结果缓存——相似任务避免重复计算 |
| 🔐 认证授权 | Agent 调用工具时的权限控制——RBAC/ABAC |
| 📊 监控 | Agent 运行时可观测性——OpenTelemetry |
本文是从 20 个 Agent 项目研究中提炼的概览。每个子模块有独立深度分析页:
| 特征 | 项目数 | 项目 |
|---|---|---|
| ReAct 循环 | 9/20 | Smolagents, Agent Zero, SWE-agent, OpenHands, AutoGPT, GPT Researcher, Goose, Codex CLI, Agno |
| Function Calling | 12/20 | LangGraph, PydanticAI, AutoGen, CrewAI, OpenClaw, Google ADK, Aider, Browser Use, ... |
| 多 Agent 原生 | 8/20 | AutoGen, CrewAI, MetaGPT, LangGraph, CAMEL, Google ADK, OpenClaw, Hermes |
| 沙箱执行 | 6/20 | SWE-agent, OpenHands, Codex CLI, OpenClaw, Goose, Agent Zero |
| 检查点/恢复 | 3/20 | LangGraph, OpenClaw, PydanticAI |
| 自进化 | 2/20 | Hermes, Agent Zero |
| Prompt 缓存优化 | 3/20 | OpenClaw (Cache Boundary), Aider (ChatChunks), Hermes (三层组装) |
单一 ReAct 已经不够。趋势是 ReAct 作为核心执行单元,外层用状态机/Orchestrator 编排多个 ReAct Agent。LangGraph 的 Pregel 引擎就是这个思路。
SWE-agent 的核心洞察:不要让 Agent 复用人类接口,而是设计 Agent-Computer Interface (ACI)。Shell 命令的输出太冗长?设计精简的 Agent 专用命令。文件浏览太慢?提供 grep + 定位的一体化接口。
Google ADK 的 A2A (Agent-to-Agent) 协议:让不同框架的 Agent 可以互相通信。就像 HTTP 统一了 Web 通信,A2A 可能统一 Agent 通信。
Hermes 的 Background Review Fork 是目前唯一的实现,但方向清晰:Agent 在后台持续审计自己的行为,发现可优化点并自动调整。这是 Agent 从"工具"到"同事"的关键一步。