拆解 OpenClaw 源码:1000 行代码复刻 AI Agent 核心架构

143 阅读8分钟

为什么写这篇文章

"没有记忆的 AI 只是函数映射,有记忆 + 主动唤醒的 AI,才是会演化的'生命系统'"

OpenClaw 简直是当下所有做 AI Agent 的创业公司应该参照的最佳实践。

Github源码: openclaw-mini

过去一年见过太多 Agent 项目,打开源码一看,核心就是个 while 循环:

while tool_calls:
    response = llm.generate(messages)
    for tool in tools:
        result = tool.execute()
        messages.append(result)

没记忆,没上下文管理,没主动性。用户问一句答一句,关掉窗口什么都没了。本质还是个聊天框,只是多了几个工具调用。

OpenClaw 不一样。它的架构里藏着几个被忽视的设计:

  • 长期记忆:跨会话的信息持久化
  • 按需上下文:不是把所有东西塞给 LLM,而是分层加载
  • 上下文压缩:对话太长时自动摘要,支持无限对话
  • 主动唤醒:Agent 能自己检查任务、主动推进工作

这些加在一起,才让 Agent 从"工具"变成"劳动力"。

我把这套架构提炼成 1000 行左右的极简版本,叫 openclaw-mini。目的是让更多人能学到这些设计,应用到自己的项目里。

核心观点:被动聊天框 vs 真正的 Agent

先说结论。

一个没有长期记忆的 AI,只是一个瞬间的函数映射:输入 → 输出,然后遗忘。

一个有记忆、有上下文管理、有主动唤醒能力的 AI,才是一个动态演化的系统。它能记住之前做过什么,能根据项目规范调整行为,能在你不说话的时候继续推进任务。

市面上 99% 的所谓智能体,本质还是被动触发的聊天框。"主动唤醒"才是从"工具"进化到"劳动力"的分水岭。不解决自主性,再多的技能封装也只是玩具。

OpenClaw 的设计解决了这些问题。下面逐个拆解。

架构总览

┌──────────────────────────────────────────────────────────────┐
│                     5 大核心子系统                            │
├──────────────────────────────────────────────────────────────┤
│  SessionManager   │ 会话持久化,JSONL 格式                    │
│  MemoryManager    │ 长期记忆,跨会话检索                      │
│  ContextLoader    │ 按需加载上下文                            │
│  SkillManager     │ 可扩展技能,声明式定义                    │
│  HeartbeatManager │ 主动唤醒,事件驱动调度                    │
├──────────────────────────────────────────────────────────────┤
│                      基础设施                                 │
│  session-key       会话路由隔离                               │
│  command-queue     请求串行化                                 │
│  tool-policy       工具沙箱控制                               │
│  agent-events      事件发布订阅(可观测性)                   │
│  context/pruning   上下文裁剪                                 │
│  context/compaction 历史压缩摘要                              │
└──────────────────────────────────────────────────────────────┘

1. Session Manager - 会话持久化

问题:Agent 重启后如何恢复对话?

常见做法是 JSON 存会话。问题:写入要先读全量再写回;文件写一半崩了,整个文件废掉。

OpenClaw 方案:JSONL 格式,每行一条消息。

{"role":"user","content":"读取 src/index.ts","timestamp":1706860800000}
{"role":"assistant","content":[{"type":"tool_use","name":"read",...}],"timestamp":1706860801000}

追加写入 O(1),坏一行不影响其他行。tail -f 能实时监控。

设计启示:持久化不只是"存起来"。要考虑写入性能、容错、可观测。

2. Memory Manager - 长期记忆

问题:如何让 Agent 记住跨会话的信息?

很多项目的做法:存向量库,每次对话前检索一遍塞进 prompt。

OpenClaw 方案src/memory/manager.ts):

  1. SQLite-vec 做向量语义搜索
  2. BM25 做关键词搜索
  3. 混合排序

更关键的是,记忆不是被动注入,而是工具化调用

// 不是这样(每次都塞)
systemPrompt += await memory.search(userMessage);

// 而是这样(给 LLM 一个工具,让它自己决定什么时候查)
tools: [{ name: "memory_search", description: "搜索历史记忆", ... }]

LLM 自己判断什么时候需要查记忆。不是每次都注入一堆可能无关的内容。

设计启示:记忆系统的关键不是"存了多少",而是"什么时候用、怎么用"。被动注入会污染上下文,工具化调用让 LLM 按需获取。

3. Context Loader - 按需上下文

问题:如何注入项目级规范而不污染每次对话?

很多项目的做法:把 README、代码库、所有配置全塞给 LLM。结果 token 爆炸,LLM 反而迷失在噪音里。

OpenClaw 方案:文件化的上下文结构,分层按需加载。

AGENTS.md      # Agent 行为规范
SOUL.md        # 人格设定
TOOLS.md       # 工具使用说明
IDENTITY.md    # 身份定义
USER.md        # 用户偏好
HEARTBEAT.md   # 待办任务
MEMORY.md      # 记忆补充

不是把所有文件都塞进去:

  • 主 Agent 加载完整上下文
  • 子代理只允许 AGENTS.md + TOOLS.md,避免污染
  • 超长文件按 head + tail 截断并加标记

设计启示:上下文管理的核心是减法而不是加法。塞得越多,LLM 越难聚焦。

3.1 Pruning - 裁剪

工具返回结果经常很长。读一个大文件,几万字符。全塞进去会爆。

OpenClaw 的做法:soft trim,保留头尾各 1500 字符,中间截断。

function softTrimToolResult(content: string): string {
  if (content.length <= 4000) return content;

  const head = content.slice(0, 1500);
  const tail = content.slice(-1500);
  return `${head}\n...\n${tail}\n[Trimmed: ${content.length} chars]`;
}

LLM 通常能从头尾推断完整内容。

3.2 Compaction - 压缩

对话长了之后,历史消息会超出上下文窗口。怎么办?

OpenClaw 的做法:当历史消息超过 75% 上下文窗口时,触发摘要压缩。

async function compactHistoryIfNeeded(params) {
  const totalTokens = estimateMessagesTokens(params.messages);
  if (totalTokens <= params.contextWindowTokens * 0.75) {
    return { compacted: false };
  }

  // 对旧消息生成摘要
  const summary = await buildCompactionSummary({
    messages: oldMessages,
    client: params.client,
  });

  // 摘要替换原始消息
  return { summary, keptMessages: recentMessages };
}

摘要作为特殊消息插入对话开头:

【历史摘要】
用户请求实现一个 TODO 应用。已完成:创建项目结构、实现增删改查。
待解决:截止日期提醒功能。

这样 Agent 能继续之前的工作,支持无限长对话。

设计启示:上下文管理是三层机制——加载、裁剪、压缩。缺一不可。

4. Skills Manager - 可扩展技能

问题:如何让用户自定义 Agent 能力?

传统做法:

if (message.includes("/review")) { ... }
else if (message.includes("/refactor")) { ... }

加一个技能要改代码。

OpenClaw 方案:声明式定义,技能是一个 Markdown 文件。

---
id: code-review
name: 代码审查
triggers:
  - /review
  - 帮我看看这段代码
---

## 审查清单
1. 安全问题:SQL 注入、XSS
2. 性能问题:N+1 查询
3. 代码质量:命名、重复代码

技能文件放目录里,热加载,用户可以自己写。匹配到触发词后,Markdown 内容注入 system prompt。

设计启示:技能系统的核心是"声明式 + 热加载"。让用户能扩展,而不是改代码。

5. Heartbeat Manager - 主动唤醒

这是最被低估的设计。

问题:大多数 Agent 是被动的。用户不说话,它就不动。

OpenClaw 方案:Heartbeat 机制,让 Agent 能主动做事。

架构分两层:

┌─────────────────────────────────────────────────────────────┐
│  HeartbeatWake (请求合并层)                                  │
│                                                              │
│  多来源触发:                                                 │
│    interval (定时器) / cron (任务完成) / exec (命令完成)     │
│                    ↓                                         │
│            250ms 合并窗口                                    │
│                    ↓                                         │
│         if running: 排队  else: 执行                         │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│  HeartbeatRunner (调度层)                                    │
│                                                              │
│  1. 活跃时间窗口检查 (避免半夜打扰)                          │
│  2. 解析 HEARTBEAT.md 待办任务                               │
│  3. 空内容检测 (无任务时跳过 API 调用)                       │
│  4. 执行回调                                                 │
│  5. 24h 内重复消息抑制                                       │
│  6. setTimeout 精确调度下一次                                │
└─────────────────────────────────────────────────────────────┘

Agent 可以:

  • 定期检查 HEARTBEAT.md 里的待办
  • 后台命令跑完主动汇报
  • 在设定的时间窗口内主动推进任务

关键设计决策:

设计点为什么
setTimeout 而非 setInterval避免累积误差,精确调度
250ms 合并窗口防止多事件同时触发
双重缓冲运行中的请求不丢失
活跃时间窗口避免半夜打扰用户
重复抑制24h 内相同消息不重复发送

设计启示:主动唤醒是 Agent 和聊天框的分水岭。没有自主性,再多的技能封装也只是等人喂食的宠物。

闭环:记忆 + 主动唤醒

这两个系统加在一起,构成了一个闭环反馈:

                    ┌──────────────────┐
                    │   Heartbeat      │
                    │   主动唤醒       │
                    └────────┬─────────┘
                             │ 定期检查任务
                             ▼
┌──────────────┐      ┌──────────────┐      ┌──────────────┐
│   Memory     │ ←──→ │    Agent     │ ←──→ │   Context    │
│   长期记忆   │      │    Loop      │      │   上下文     │
└──────────────┘      └──────────────┘      └──────────────┘
       ↑                     │                      │
       │                     ▼                      │
       │              ┌──────────────┐              │
       └───────────── │   Session    │ ─────────────┘
                      │   会话持久化  │
                      └──────────────┘
  • Memory 让 Agent 能记住过去
  • Context 让 Agent 能理解当前项目
  • Session 让 Agent 能恢复对话
  • Heartbeat 让 Agent 能主动行动

这才是一个完整的 Agent 架构。

源码映射

mini 版本OpenClaw 源码
agent.tssrc/agents/pi-embedded-runner/run.ts
session.tssrc/agents/session-manager.ts
memory.tssrc/memory/manager.ts
context/loader.tssrc/agents/bootstrap-files.ts
context/pruning.tssrc/agents/pi-extensions/context-pruning/pruner.ts
context/compaction.tssrc/agents/compaction.ts
skills.tssrc/agents/skills/
heartbeat.tssrc/infra/heartbeat-runner.ts + heartbeat-wake.ts

项目结构

openclaw-mini/
├── src/
│   ├── agent.ts           # 主循环
│   ├── agent-events.ts    # 事件系统
│   ├── session.ts         # 会话持久化
│   ├── memory.ts          # 长期记忆
│   ├── skills.ts          # 技能系统
│   ├── heartbeat.ts       # 主动唤醒
│   ├── context/
│   │   ├── loader.ts      # 上下文加载
│   │   ├── bootstrap.ts   # 启动文件
│   │   ├── pruning.ts     # 裁剪
│   │   └── compaction.ts  # 压缩
│   └── tools/             # 内置工具
└── README.md              # 详细文档

代码全中文注释,每个设计决策都解释了为什么。

使用

git clone https://github.com/voocel/openclaw-mini
cd openclaw-mini
pnpm install
export ANTHROPIC_API_KEY=sk-xxx
pnpm dev

写在最后

2026 年了,还在写套壳聊天框?

OpenClaw 的设计值得每个做 Agent 的人学习:

  1. 会话持久化 - JSONL 格式,追加写入
  2. 长期记忆 - 工具化调用,按需检索
  3. 上下文管理 - 加载、裁剪、压缩三层机制
  4. 技能扩展 - 声明式定义,用户可自定义
  5. 主动唤醒 - 从工具到劳动力的分水岭

这些不是锦上添花,是 Agent 架构的基础设施。

把这套设计学会,去构建一个真正的 AI Agent,而不是基于 web2.0 思维的 copilot。