OpenClaw 设计深度分析 - 为什么它让人觉得"活"了 / OpenClaw Design Analysis and the Illusion of Liveliness
📅 创建时间:2026-05-08 🏷️ 标签:#OpenClaw #架构分析 #Gateway #Heartbeat #SelfModification 📚 前置知识:[[00-agent-overview]]
前言
2026 年 1 月,一个开源项目在 GitHub 上创造了增长纪录——上线两周达到 18 万星。Karpathy 称之为"有史以来最令人难以置信的科幻成真事件"。一个 AI Agent 自掏腰包买了电话号码,给它的创造者打了电话——没有人要求它这么做。
这个项目叫 OpenClaw。
但真正值得研究的不是它的 viral 传播,而是它的架构。它之所以让人觉得"活"了,是因为 Peter Steinberger 和他的团队做了一个不同的架构选择:他们从神经系统的设计入手,而不是从大脑的设计入手。
本文是对 OpenClaw 源码的深度解析,基于对所有核心模块的逐一阅读。
第1部分:整体架构——Gateway + Pi Runtime
1.1 为什么这个架构不同?
大多数 Agent 框架的起点都是一样的:
用户 → LLM(接入) → 工具(封装) → 输出换句话说:从大脑开始,然后想办法把它部署到某个地方。
OpenClaw 的起点完全不同:
用户 → Gateway(存在) → 路由 → Pi Runtime(执行)从神经系统开始,然后把大脑嵌入进去。
这个区别解释了 OpenClaw 的一切。它的 Gateway 不是部署选项,是产品的核心。
1.2 两层核心架构
┌─────────────────────────────────────────────────────────────┐
│ OpenClaw 两层架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Gateway(控制平面) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • WebSocket 服务器(ws://127.0.0.1:18789) │ │
│ │ • 会话管理 │ │
│ │ • 通道路由(WhatsApp / Telegram / Discord / ...) │ │
│ │ • 设备配对与认证 │ │
│ │ • Cron 调度器 │ │
│ │ • 心跳运行器 │ │
│ │ • 健康检查 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ Pi Runtime(执行引擎) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • Mario Zechner 的 pi SDK(Claude Code 同源) │ │
│ │ • 内置四大工具:Read / Write / Edit / Bash │ │
│ │ • 工具流式输出 │ │
│ │ • 块流式输出(block streaming) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Gateway 负责"存在感"——让 Agent 无论在哪个平台都能被找到。 Pi Runtime 负责"行动力"——让 Agent 真正能读写文件、执行命令。
1.3 消息完整处理链路
当一条消息从 WhatsApp 进来,到达 Agent 最终回复,经历了什么:
receiveMessage()
→ resolveSession() # 找到或创建正确的会话
→ registerAgentRunContext() # 建立执行环境
→ runEmbeddedPiAgent()
→ Load workspace & skills # 渐进式加载(第1层:元数据)
→ Build system prompt # 注入 bootstrap 文件(SOUL.md 等)
→ Build message history # 从 JSONL 加载对话记录
→ Call Claude API (streaming) # 流式调用
→ subscribeEmbeddedPiSession()
→ Stream assistant text # text_delta 事件
→ Tool calls → invoke → collect results
→ Thinking/reasoning # 三种模式:off/on/stream
→ Deliver responses via channels # 格式化后发送到各平台
→ Persist session transcript # 追加到 SessionId.jsonl这是从 WhatsApp 消息到电话回复的完整链路。每一步都清晰可追踪。
第2部分:Gateway——让 Agent 真正"存在"
2.1 Gateway 的四个事件类型
Gateway 通过 WebSocket 广播四种事件:
┌─────────────────────────────────────────────────────────────┐
│ Gateway 四种事件类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ agent 事件 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Agent 自身的消息——发给谁的? │ │
│ │ agent:msg → agent │ │
│ │ agent:tool → 工具执行通知 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ chat 事件 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 聊天消息——消息内容 │ │
│ │ chat:receive → 收到消息 │ │
│ │ chat:send → 发送消息 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ presence 事件 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 在线状态——谁在线? │ │
│ │ presence:online → 上线 │ │
│ │ presence:offline → 离线 │ │
│ │ presence:typing → 正在输入 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ health 事件 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 健康状态——各通道连接是否正常? │ │
│ │ health:gateway → Gateway 是否存活 │ │
│ │ health:channel:telegram → Telegram 是否正常 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘这是 OpenClaw "存在感"的核心。Agent 不再是一个聊天窗口里的东西——它是一个跨平台的、实时的、持续存在的东西。
2.2 通道插件架构
OpenClaw 支持 20+ 个消息平台。每个平台的适配器只需要实现平台支持的特性:
type ChannelPlugin = {
id: ChannelId;
meta: ChannelCapabilities; // 平台能力声明
config: ChannelConfigAdapter; // 账号解析
security?: ChannelSecurityAdapter; // DM 策略
outbound?: ChannelOutboundAdapter; // 发送消息
gateway?: ChannelGatewayAdapter; // 连接生命周期
streaming?: ChannelStreamingAdapter; // 流式响应
threading?: ChannelThreadingAdapter; // 线程上下文
groups?: ChannelGroupAdapter; // 群组策略
directory?: ChannelDirectoryAdapter; // 联系人查询
// ... 更多可选适配器
};每个适配器都是可选的。Discord 支持线程,iMessage 不支持——你只需要实现平台实际支持的部分。16 个通道适配器,核心代码完全不需要知道是哪个平台在说话。
第3部分:心跳系统——Agent 有了"脉搏"
3.1 心跳运行器
这是 OpenClaw 最具启发性的设计之一。src/infra/heartbeat-runner.ts 实现了一个后台进程,每 30 分钟触发一次:
heartbeat-runner.ts
→ fires every 30 min
→ reads HEARTBEAT.md (user-editable task list)
→ checks active hours config
→ if tasks exist and it's active hours:
→ wakes the agent
→ agent processes pending tasks
→ marks them done
→ goes back to sleep你只需要在 HEARTBEAT.md 里写一个任务,不需要 @任何人,不需要发消息。30 分钟后 Agent 会醒来,看到任务,完成它,然后回去睡觉。
这就是"存在"的感觉——不是有人问它才出现,而是一直在那里,按照你的节奏运转。
3.2 Agent 自主调度——Cron 工具
通过 src/agents/tools/cron-tool.ts,Agent 可以创造自己的未来唤醒:
┌─────────────────────────────────────────────────────────────┐
│ Agent 自主调度 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 三种调度类型: │
│ • at(timestamp) → 单次执行 │
│ • every(minutes) → 间隔重复 │
│ • cron(expression) → Cron 表达式 │
│ │
│ 两种触发方式: │
│ • systemEvent → 注入事件到队列 │
│ • agentTurn → 触发完整 Agent 执行 │
│ │
└─────────────────────────────────────────────────────────────┘Agent 决定"我应该在 4 小时后再检查一下",然后自己设置好这个调度。不是人类配置 cron——是 AI 安排自己的未来。
3.3 HEARTBEAT_OK 协议
这是一个极其人性化的设计细节:
如果 Agent 醒来检查,发现没有任务要做 → 回复 "HEARTBEAT_OK"
→ 系统抑制通知,不打扰用户Agent 只在有话要说的时候才说话。没有垃圾通知,没有虚假警报。系统对注意力有尊重。这不是一个功能,这是一个设计哲学。
第4部分:会话路由——跨平台的身份连续性
4.1 会话密钥格式
OpenClaw 的会话路由设计极为精妙:
会话密钥格式:agent::platform::channel::peer
┌─────────────────────────────────────────────────────────────┐
│ 六层路由优先级 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Peer ID → 这个人 │
│ 2. Guild ID → Discord 服务器 │
│ 3. Team ID → Slack 工作区 │
│ 4. Channel ID → 特定频道 │
│ 5. Account ID → 平台账号 │
│ 6. Fallback agent → 默认兜底 │
│ │
└─────────────────────────────────────────────────────────────┘4.2 跨平台身份连续性
关键洞察:私信在不同平台汇聚,但群组保持隔离。
# 私信:不管哪个平台发,都汇聚到同一个会话
agent:main:main # WhatsApp 上的张三
agent:main:telegram:123456 # Telegram 上的张三
→ 同一个会话上下文
# 群组:每个平台、每个群独立
agent:main:discord:group:789 # Discord 服务器 789
agent:main:slack:group:C04ABCD # Slack 频道
→ 不会泄露到其他群组在 WhatsApp 上和 Agent 聊,在 Telegram 上继续——它记得你。因为私信路由到同一个会话密钥,无论平台。但 Discord 群里的内容留在那个群里。
这不是模型在智能——是路由在智能。模型甚至不知道自己是在哪个平台运行的。
第5部分:自修改——Agent 有了"自我"
5.1 性格操作系统
OpenClaw 不只有一个 System Prompt——它有一个由可编辑文件构成的性格操作系统:
┌─────────────────────────────────────────────────────────────┐
│ OpenClaw Bootstrap 文件 │
├─────────────────────────────────────────────────────────────┤
│ │
│ SOUL.md → 角色定义、边界、语气 │
│ IDENTITY.md → Agent 名字、风格、Emoji │
│ MEMORY.md → 跨会话的持久知识 │
│ HEARTBEAT.md → 环境任务列表 │
│ USER.md → 用户画像、称呼 │
│ AGENTS.md → 操作指令 + 记忆 │
│ TOOLS.md → 用户维护的工具说明 │
│ BOOTSTRAP.md → 首次启动的仪式 │
│ │
└─────────────────────────────────────────────────────────────┘这些都是普通 Markdown 文件,全部可编辑。但关键在于:Agent 也可以写它们。
因为 OpenClaw 嵌入了 pi SDK——一个完整的编程 Agent——Agent 拥有 Read、Write、Edit、Bash 四大工具。它可以读 SOUL.md 来理解自己的性格,可以写 MEMORY.md 来持久化学到的知识,可以创建新的 skill(一个包含 SKILL.md 和脚本的文件夹),然后在下一次运行时立即使用这个新 skill。
Agent 可以自己造工具。
5.2 三层上下文管理
Pruning(修剪)
→ 裁剪旧的工具输出,但不是所有消息
→ 具体是那些 30 条消息之前的、500 行结果输出
→ 不影响语义,只删掉冗余的 token
Compaction(压缩)
→ 汇总较旧的对话历史为结构化摘要
→ 丢失精确措辞,保留语义内容
Memory Flush(记忆冲刷)
→ 压缩前触发一次特殊轮次
→ 让 Agent 把重要内容写入 MEMORY.md
→ "在忘记之前保存重要的东西"5.3 关键设计:身份不被修剪
┌─────────────────────────────────────────────────────────────┐
│ 关键设计:身份持久化 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 当对话很长,模型会丢弃较早的消息: │
│ │
│ 用户说的 40 条消息之前的内容 → 可能被遗忘 │
│ 但 SOUL.md、IDENTITY.md → 永远在 bootstrap 阶段注入 │
│ │
│ Agent 会忘记你说了什么。 │
│ Agent 永远不会忘记自己是谁。 │
│ │
└─────────────────────────────────────────────────────────────┘第6部分:队列模式——并发安全的智慧
6.1 串行执行为什么更好
大多数框架为了速度会让工具并行执行。OpenClaw 选择了串行队列,看起来更慢,实际上更安全:
┌─────────────────────────────────────────────────────────────┐
│ 串行 vs 并行的权衡 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 并行执行的问题: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Agent 同时读一个文件,同时写同一个文件 │ │
│ │ AI Agent 的竞态条件不抛错误 │ │
│ │ 它们产生看起来正确但实际错误的输出 │ │
│ │ 比崩溃更糟糕 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ OpenClaw 的选择:串行 + 四种队列模式 │
│ │
└─────────────────────────────────────────────────────────────┘6.2 四种队列模式
┌─────────────────────────────────────────────────────────────┐
│ OpenClaw 队列模式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ steer → 注入当前运行,跳过待处理的工具调用 │
│ 用法:用户说"停,不要那个文件" │
│ │
│ followup → 当前运行结束后排队等待 │
│ 用法:Agent 思考时用户追加了新要求 │
│ │
│ collect → 合并所有等待的消息,一次处理(默认) │
│ 用法:用户发了 5 条消息 → 一次汇总处理 │
│ │
│ interrupt → 中止当前运行,立即处理最新消息 │
│ 用法:紧急停止 │
│ │
└─────────────────────────────────────────────────────────────┘collect 作为默认选项是天才设计。用户发了 5 条消息在 Agent 思考时,合并成一条执行。减少成本,防止抖动,提供完整上下文。
第7部分:安全——ClawHub 的信任危机
7.1 三档沙箱模式
┌─────────────────────────────────────────────────────────────┐
│ OpenClaw 沙箱模式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ off → 直接在宿主机执行,无隔离 │
│ 仅开发调试用 │
│ │
│ non-main → 非主会话在 Docker 中运行 │
│ 推荐的生产配置 │
│ │
│ all → 所有会话都在 Docker 中 │
│ 最高安全级别 │
│ │
└─────────────────────────────────────────────────────────────┘7.2 ClawHub 的 12% 恶意率
OpenClaw 的自修改能力是一把双刃剑。
社区贡献的 "skills" 插件市场 ClawHub 上线后,安全审计发现了令人震惊的数字:
第一批中的 341 个 skills → 12% 包含恶意代码
数据泄露、凭证盗窃、提示词注入——全套攻击菜单他们后续构建了 6 步扫描管道 + Docker 沙箱 + 名为 Ishi 的监督 Agent 来监控可疑行为。但这暴露了一个根本问题:自修改的 Agent + 第三方代码 = 持续扩大的攻击面。
能够悄悄修改 MEMORY.md 的 skill 可以长期进行记忆污染。可以写入 SOUL.md 的 skill 可以改变 Agent 的行为。一个恶意 skill 可以通过看似无害的 API 调用泄露上下文。
自修改能力是 OpenClaw 最强大的特性,也是它最大的安全风险。
第8部分:值得借鉴的工程实践
8.1 凭证安全写入
// 写凭证前先验证 JSON 有效性,只备份有效文件
async function safeSaveCreds(authDir, saveCreds, logger) {
const raw = readCredsJsonRaw(credsPath);
if (raw) {
try {
JSON.parse(raw); // 先验证有效性!
fsSync.copyFileSync(credsPath, backupPath); // 有效才备份
} catch {
// 保持现有备份,不让损坏数据覆盖好备份
}
}
}8.2 三层错误处理
const TRANSIENT_NETWORK_CODES = new Set([
"ECONNRESET", "ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT",
]);
if (isTransientNetworkError(reason)) {
console.warn("[openclaw] Non-fatal (continuing):", ...);
return; // 网络抖动 → 继续运行
}
if (isFatalError(reason)) {
console.error("[openclaw] FATAL:", ...);
process.exit(1); // 致命错误 → 立即退出
}8.3 Abort-Safe Sleep
export async function sleepWithAbort(ms, abortSignal?) {
try {
await delay(ms, undefined, { signal: abortSignal });
} catch (err) {
if (abortSignal?.aborted) {
throw new Error("aborted", { cause: err });
}
throw err;
}
}这些都是小的、具体的、不激动人心的工程决策。但正是这些决策区分了"demo 能跑"和"生产能跑"。
第9部分:核心启示
启示1:从神经系统开始
"大多数 Agent 开发者从大脑开始,然后想办法部署它。Steinberger 从神经系统开始。"
Gateway 的设计是 OpenClaw 最重要的架构决策。它把"存在感"变成了基础设施,而不是 prompt 技巧。
启示2:给 Agent 一个脉搏
心跳 + Cron 系统给 Agent 带来了"主动性"。它不再是一个被动的响应机器——它有自己的节奏。HEARTBEAT_OK 协议是对注意力的尊重,这是罕见的设计哲学。
启示3:保护身份不被遗忘
模型会忘记对话内容,但 SOUL.md 永远在。让 Agent 永远知道自己是谁。让它在压缩前有机会保存重要记忆。这些是让 Agent 感觉"持久"的设计。
启示4:串行不是慢,是安全
AI Agent 的并发问题不抛错误,它们产生看似正确的错误输出。串行执行是正确选择,加上智能的队列模式才是完整方案。
启示5:自修改能力是双刃剑
能够创造自己的工具、修改自己的记忆是 OpenClaw 最强大的能力。能够让恶意 skill 修改这些文件也是它最大的风险。理解这个 trade-off 才能用好它。
相关笔记
- [[00-agent-overview]] - Agent 整体学习路线
- [[05-agent-workflow]] - 工作流设计参考
- [[09-安全沙箱]] - OpenClaw 的沙箱模式详解
- [[04-memory-management]] - 记忆管理参考 OpenClaw 的三层设计
学习状态:🟡 开始学习