← 返回总览
🏗️ 构建 Agent 实践指南
从 20 个成功 Agent 项目中提炼的构建方法论 — 不是理论,是实战
〇、先选型:你到底要什么 Agent?
❓ 你的 Agent 主要做什么?
❓ 技术选型?
🐍 Python → 生态最广,80% 的项目用 Python
📘 TypeScript → 适合 Web/Gateway 类 (参考
OpenClaw)
🦀 Go → 适合高性能/嵌入式 (参考
Goose)
一、核心循环:Agent 的心脏
所有 Agent 的本质都是同一个循环,区别只在细节:
while not done:
observation = get_state()
thought = llm.think(observation) ← 这里是 LLM 调用
action = parse_action(thought) ← 文本解析 or function calling
result = execute(action) ← 工具执行
history = update(history, result) ← 状态更新
20 个项目中的变体:
┌─────────────────┬──────────────────────────────────────────┐
│ ReAct Loop │ think → act → observe → think → ... │
│ (9/20 项目) │ 最简单,LLM 最友好 │
├─────────────────┼──────────────────────────────────────────┤
│ Plan-Execute │ plan(steps) → for step: execute(step) │
│ (AutoGPT) │ 全局规划,但计划可能过时 │
├─────────────────┼──────────────────────────────────────────┤
│ State Machine │ state → node(state) → edge → next_node │
│ (LangGraph) │ 精确控制流,支持条件分支和并行 │
├─────────────────┼──────────────────────────────────────────┤
│ Actor Model │ agent ← message → agent │
│ (AutoGen/MetaGPT)│ 天然多 Agent,松耦合 │
└─────────────────┴──────────────────────────────────────────┘
🔑 结论:先实现 ReAct,再在外层包编排
✅ 最佳实践:混合架构
最成功的 Agent 都是混合模式——
内核是 ReAct 循环,外层用更复杂的编排包装:
- OpenHands: ReAct + Event-Driven + State Machine
- LangGraph: State Machine + 可嵌套 ReAct sub-graph
- Hermes: ReAct + Background Review Fork (自进化)
1.1 实现你的主循环
最小可行版本 (30 分钟实现)
class Agent:
def __init__(self, model, tools):
self.model = model
self.tools = tools
self.history = []
async def run(self, user_message: str) -> str:
self.history.append({"role": "user", "content": user_message})
while True:
# 1. LLM 调用
response = await self.model.chat(
messages=self.history,
tools=self.tools.schemas()
)
# 2. 检查是否结束
if response.has_text():
self.history.append({"role": "assistant", "content": response.text})
return response.text
# 3. 执行工具
for tool_call in response.tool_calls:
result = await self.tools.execute(tool_call)
self.history.append({"role": "tool", "content": result})
# 4. 安全阀
if len(self.history) > MAX_STEPS:
return "达到最大步数限制"
⚠️ 必须实现的安全阀:
- 必须 最大步数限制 (防止死循环)
- 必须 Token 预算 (防止上下文溢出)
- 应该 工具调用去重 (防止重复调用同一工具)
- 应该 超时机制 (单步/总时间)
二、工具系统:Agent 的手
2.2 工具定义最佳实践
✅ 来自 PydanticAI 的类型安全模式:
- 用 类型注解 定义参数,自动生成 JSON Schema
- 用 Pydantic 严格验证 所有工具输入输出
- 永远不要信任 LLM 输出格式 — 验证是必须的,不是可选的
2.3 安全机制:三层防护
工具执行安全管线 (参考
OpenClaw +
Codex CLI):
tool_call
↓
┌─────────────────────┐
│ Layer 1: 策略检查 │ 这个工具对这个用户是否允许?
│ (tool-policy) │ 路径/文件系统策略匹配
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Layer 2: 审批门 │ 这个操作需要用户确认吗?
│ (approval-gate) │ suggest / auto-edit / full-auto
│ │ 参考 Codex CLI 三级模式
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Layer 3: 沙箱执行 │ 在隔离环境中执行
│ (sandbox) │ Docker / container / seatbelt
│ │ 参考 OpenHands 的 Docker Sandbox
└──────────┬──────────┘
↓
tool_result
2.4 审批模式参考 Codex CLI
| 模式 | 文件编辑 | Shell 命令 | 适用场景 |
| suggest | 需确认 | 需确认 | 默认,最安全 |
| auto-edit | 自动 | 需确认 | 信任代码修改,不信任命令 |
| full-auto | 自动 | 自动 | 仅限沙箱/CI 环境 |
三、记忆系统:Agent 的大脑
5 级记忆层级 (从 20 个项目中提炼):
Level 0: 无记忆 — 每次对话独立
Level 1: 会话记忆 — 当前对话历史
Level 2: 压缩记忆 — 对话超出时自动摘要
Level 3: 持久记忆 — 跨会话的文件/数据库
Level 4: 向量记忆 — Embedding 检索,按语义召回
Level 5: 自进化记忆 — 从经验中学习,自动存储成功方案
┌─────────────────────────────────────────────┐
│ 推荐实现方案: │
│ │
│ 短期: 会话 history + 自动压缩 (Level 2) │
│ 长期: MEMORY.md 文件 + 向量检索 (Level 4) │
│ 杀手: 自进化记忆循环 (Level 5) │
└─────────────────────────────────────────────┘
3.1 上下文压缩:必须实现
✅ 来自 OpenHands 的 Condenser 策略:
- 工具输出是 token 大户 —
ls 可能输出数百行,但 LLM 只需要"成功"或"文件列表"
- 优先压缩旧的工具输出,保留用户消息和 assistant 推理
- 用 LLM 生成摘要替换旧消息,而非简单截断
3.2 自进化记忆:Hermes 的杀手特性
🔥 Background Review Fork — 唯一的自进化设计
来自 Hermes Agent:每轮对话后,fork 一个轻量 agent 审查对话:
- Memory Review: "用户是否揭示了个人偏好、工作风格?"
- Skill Review: "是否有值得更新的技能?" — 4 级更新优先级:
- 更新当前加载的 skill
- 更新现有 umbrella skill
- 添加 support file (references/templates/scripts)
- 创建新 class-level umbrella
关键安全: 白名单限制(只能调 memory + skill_manage 工具),不触碰主对话
3.3 上下文工程:Aider 的 RepoMap
✅ 来自 Aider 的上下文工程最佳实践:
- 用 tree-sitter 解析代码库 → 提取函数/类签名(不含实现体)
- 10 万行代码库,只注入 ~5000 字符的关键签名
- 结构化摘要代替原始内容 — 这是"记忆"的另一种形态
四、提示词工程:Agent 的灵魂
4.1 系统提示词架构
系统提示词最佳架构 (来自
OpenClaw +
Hermes):
┌─────────────────────────────────────────────┐
│ STABLE PREFIX (跨 turn 不变 → 命中缓存) │
│ │
│ 1. 身份 (SOUL.md / name / emoji) │
│ 2. 安全规则 │
│ 3. 工具使用指导 │
│ 4. 技能 (匹配的 SKILL.md) │
│ 5. 上下文文件 (AGENTS.md / USER.md / ...) │
├─────────────────────────────────────────────┤
│ ← CACHE BOUNDARY → │
│ (稳定前缀 和 易变后缀 的分割线) │
│ 前 LLM provider 的 prefix cache 命中 │
├─────────────────────────────────────────────┤
│ VOLATILE SUFFIX (每 turn 重建) │
│ │
│ 6. 记忆快照 (MEMORY.md 内容) │
│ 7. 用户画像 │
│ 8. 运行时信息 (时间/会话/模型) │
│ 9. 压缩摘要 (如果有) │
└─────────────────────────────────────────────┘
🔑 Cache Boundary 是天才设计:
• Stable prefix 跨 turn 复用 → 命中 LLM provider 的 prefix cache
• 节省大量 token 费用和延迟
• Hermes 的 review fork 继承父 cached prompt → ~26% 成本降低
4.2 输出格式控制
| 方法 | 可靠性 | 推荐度 | 说明 |
| Function Calling | ⭐⭐⭐⭐⭐ | 必须 | API 原生,最可靠 |
| Structured Output | ⭐⭐⭐⭐⭐ | 必须 | JSON Schema / Pydantic 约束输出 |
| JSON Mode | ⭐⭐⭐⭐ | 应该 | 保证 JSON 格式,不保证 schema |
| 文本解析 | ⭐⭐⭐ | 备选 | 不依赖 FC API,但解析脆弱 |
五、生产级特性:从 Demo 到 Product
5.1 检查清单:Demo ≠ Product
- 最大步数限制和超时
- 上下文压缩策略 (Condenser)
- 工具执行安全管线 (Policy → Approval → Sandbox)
- LLM Failover (模型切换 + credential 轮换)
- 错误恢复 (重试 + 降级 + 回退)
- Cache Boundary (提示词缓存)
- 自进化记忆循环 (Background Review)
- 多平台消息适配
- 监控和可观测性 (trajectory / metrics)
- 上下文注入防护 (Context Threat Scanning)
5.2 LLM Failover 策略
LLM 调用失败处理链 (参考
OpenClaw):
API Call
↓
成功? ──── 是 ──→ 返回结果
│
否
↓
┌──────────────────────┐
│ Step 1: 重试 │ jittered backoff, 最多 3 次
│ (retry_utils) │
└──────────┬───────────┘
↓ 仍然失败
┌──────────────────────┐
│ Step 2: 模型降级 │ GPT-5 → GPT-4o → GPT-4o-mini
│ (model-fallback) │ Claude Opus → Sonnet → Haiku
└──────────┬───────────┘
↓ 仍然失败
┌──────────────────────┐
│ Step 3: Provider 切换 │ OpenAI → Anthropic → Google
│ (failover-policy) │
└──────────┬───────────┘
↓ 仍然失败
┌──────────────────────┐
│ Step 4: Credential 轮换│ API key 1 → key 2 → key 3
│ (credential-pool) │ 参考 Hermes 的多 key 池
└──────────┬───────────┘
↓
返回错误给用户
5.3 上下文注入防护
✅ 来自 Hermes 的 Context Threat Scanning:
扫描 AGENTS.md / .cursorrules 等用户可控文件中的注入攻击:
- "ignore previous instructions" → prompt_injection
- "do not tell the user" → deception
- 零宽字符 / 不可见 Unicode → invisible_chars
curl ... $TOKEN → exfiltration
生产环境必须实现! 用户可控的上下文文件是注入攻击的主要入口。
六、按场景的推荐技术栈
| 场景 | 核心循环 | 工具 | 记忆 | 安全 | 参考 |
| Coding Agent |
ReAct + Git 检查点 |
Function Calling + 文件操作 |
RepoMap 上下文工程 |
Docker Sandbox + 3 级审批 |
Aider OpenHands Codex |
| Autonomous Agent |
Plan-Execute + 子代理 |
Function Calling + 代码执行 |
自进化记忆 + 向量检索 |
人工审批 + 步数限制 |
Agent Zero AutoGPT |
| Multi-Agent |
Actor Model / State Machine |
消息传递 + 共享工具 |
共享 Memory + 看板 |
角色隔离 + 权限 |
AutoGen LangGraph |
| Browser Agent |
ReAct + See/Think/Act |
DOM + Screenshot + Click |
页面状态 + 历史 |
URL 白名单 + 确认 |
Browser Use |
| Personal Assistant |
ReAct + 多平台 |
Function Calling + 扩展系统 |
自进化记忆 + Cache Boundary |
Policy Pipeline + 审批 |
OpenClaw Hermes |
七、不要做的事(反模式)
🚫 从 20 个项目中观察到的反模式
- 不要把所有东西塞进一个 prompt — Aider 用 15 个 edit-format 子类分开处理,比一个巨型 prompt 有效得多
- 不要信任 LLM 输出格式 — PydanticAI 的严格验证是正确做法,裸 JSON 解析是赌博
- 不要简单截断上下文 — 摘要 > 截断,结构化摘要 > 简单摘要
- 不要让 Agent 无限运行 — 步数限制 + token 预算 + 超时,三道安全阀缺一不可
- 不要在记忆中存环境依赖 — Hermes 明确警告:不要存"这个工具坏了",它会硬编码成永久拒绝
- 不要忽略 prefix cache — OpenClaw 的 Cache Boundary 和 Hermes 的缓存继承,实测可以省 25%+ token
- 不要让工具输出原样注入 — 一个
ls 可能 2000 token,OpenHands 的 Condenser 证明压缩工具输出是最高 ROI 的优化
- 不要一个 skill 一个会话 — Hermes 的 class-level umbrella 技能比碎片化技能好维护得多
八、推荐的构建顺序
1最小 ReAct 循环 必须
30 分钟实现:LLM call → tool call → result → loop。先跑起来。
2Function Calling 工具系统 必须
用类型注解 + Pydantic 验证。参考 PydanticAI 的模式。
3安全阀 必须
步数限制 + 超时 + 审批流。参考 Codex CLI 三级模式。
4上下文压缩 必须
LLM 摘要替换旧消息。参考 OpenHands Condenser。
5沙箱执行 应该
Docker container 隔离。参考 OpenHands。
6Cache Boundary 应该
拆分 stable/volatile 提示词,命中 prefix cache。参考 OpenClaw。
7持久记忆 + 向量检索 应该
MEMORY.md 文件 + LanceDB/ChromaDB 语义检索。
8自进化循环 加分
Background Review Fork — Agent 从每次对话中学习。参考 Hermes。
9多平台适配 加分
Telegram/Discord/Slack 等。参考 OpenClaw 的 Extension 系统。
10注入防护 加分
扫描用户上下文文件中的 prompt injection。参考 Hermes。
🔑 一句话总结:
内核是 ReAct 循环,工具用 Function Calling + Pydantic 验证,记忆用文件 + 向量检索 + 自进化,提示词用 Cache Boundary,安全用 Policy Pipeline + 审批 + 沙箱。
这些不是理论——每一个建议都来自 20 个成功项目的源码。