详细拆解OpenClaw源码,架构简单得让我离谱!
hi,我是超级个体实践者周知,以下是详细拆解图

先别急着聊架构。
打开OpenClaw的GitHub仓库,src/目录长这样:
src/
├── gateway/
│ └── server.impl.ts ← 总调度中心,整个系统的心脏
├── agents/
│ ├── pi-embedded-runner/
│ │ ├── run.ts ← Agent循环主入口
│ │ ├── model.ts ← 模型选择+自动换备胎
│ │ ├── system-prompt.ts ← 系统提示词组装
│ │ ├── compact.ts ← 记忆瘦身(聊太多了就压缩)
│ │ └── lanes.ts ← 排队系统(一个一个来)
│ ├── tool-policy.ts ← 工具权限控制
│ ├── sandbox.ts ← 安全隔离间(代码在小黑屋里跑)
│ └── context-window-guard.ts ← 记忆容量警报(快撑不下了就喊停)
├── process/
│ └── command-queue.ts ← 排队系统的核心代码
├── config/
│ ├── sessions.ts ← 会话管理
│ └── paths.ts ← 文件存在哪
├── cli/ ← 命令行入口
├── commands/ ← 用户命令处理
└── extensions/ ← 插件渠道(Matrix/Teams/飞书...)
整个项目,TypeScript写的。
Node 22+运行,pnpm构建,可选Bun加速。测试文件就放在源码旁边,改完代码顺手就能跑测试。
截至2026年2月底,GitHub上24万+star,单周访问量突破240万,378位贡献者。创始人Peter Steinberger一个月提交了6600+次代码更新。
他说过一句被广泛引用的话:”I ship code I don’t read。”
翻开代码——核心就这几根分支。
下面详细拆。
一、三层蛋糕:Channel → Gateway → Runtime
OpenClaw的架构图,画出来就一句话:
车轮结构。
Gateway是轮毂(中心),所有消息渠道、Agent、工具都是辐条,全部连到中间这一个点上。
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / ...
│
▼
┌─────────────────┐
│ Gateway │
│ ws://127.0.0.1 │
│ :18789 │
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Agent Runtime CLI WebChat
(Pi Agent Core)
三层分得很干净。
第一层,Channel Adapters——你可以理解为”翻译官”。负责把15+个消息平台的消息翻译成OpenClaw听得懂的统一格式。WhatsApp、Telegram、Discord、Slack……每个平台发消息的方式都不一样。翻译官把这些差异全部抹平。
核心渠道的代码在src/里,扩展渠道(Matrix、Google Chat、微软Teams、LINE、飞书)放在extensions/目录。
每个平台的消息格式不一样。媒体处理不一样。登录方式不一样。限速策略也不一样。翻译官把这些差异全部抹平,输出统一的内部格式。
想加一个新平台?写一个”翻译包”就行,系统会自动发现它。
翻译官还自带”心跳监测”。某个平台的连接断了?自动重连。不用你操心。
第二层,Gateway——总调度中心。所有消息进来都先过它,它决定消息往哪送。
第三层,Agent Runtime——干活的大脑。接到任务后,调用AI模型思考、执行工具、返回结果。
为什么选TypeScript?
VISION文档原话说得很直白:OpenClaw的定位是”编排系统”——把各种提示词、工具、协议、平台粘在一起。
编排系统要什么?连接速度。能快速接入一个又一个新平台。
TypeScript的生态刚好擅长干这个。
说白了,这不是一个ML项目。这是一个胶水项目。胶水的核心竞争力就是粘得快、粘得多。
二、Gateway:一个WebSocket撑起所有
打开src/gateway/server.impl.ts。
Gateway启动做了什么?就一件事:在本机127.0.0.1:18789开了一个WebSocket长连接服务。
WebSocket你可以理解为”永不挂断的电话线”——消息来了立刻送达,不用反复拨号。
所有进出的消息都有格式校验。格式不对的直接拦住。
就这么简单?就这么简单。
Gateway的设计哲学:能简单就绝不复杂。
它不装。不搞分布式,不搞集群。一个Gateway进程管你所有的消息渠道、所有的Agent会话、所有的工具执行。
消息进来了,Gateway怎么知道该送给谁?靠session key——每个对话都有一个唯一编号。这个编号的设计很巧:
agent:main:main ← 主会话
agent:main:telegram:dm:xxx ← Telegram某用户的私聊
agent:support:slack:ch:yyy ← Slack某频道的support agent
你看出来了吗?
key的结构天然就带着”谁在说话”和”从哪个平台来”的信息。就像快递单号——看一眼编号就知道发件城市和快递类型。
再配合工具的”白名单/黑名单”机制,权限控制就有了。
不需要另外搞一套复杂的权限管理系统。session key自己就是路由表+权限表。
Gateway还支持”热更新”。你改了配置文件,不用重启整个系统,Gateway自己会感知到变化并重新加载。
一个Gateway还能同时管多个Agent。比如一个专门回客服问题,一个专门做日程管理。每个Agent有自己独立的工作空间,互不干扰。
三、Lane Queue:为什么串行才是正确答案
这是OpenClaw最精巧的设计。
打开src/process/command-queue.ts。
核心是一个”分车道排队”系统。
什么意思?每个用户会话(session)有自己的专属车道,车道里的任务严格排队,一个做完再做下一个。
实现方式:纯TypeScript + Promises(就是JS原生的异步机制)。
没有Redis。没有RabbitMQ。没有任何外部排队工具。
核心保证只有一句:”同一个用户对话,同一时刻,只能有一个任务在执行。”
怎么做到的?每个session key对应一条专属车道。消息进来,排到自己车道的队尾。车道内严格先来后到。不同车道可以同时跑——但同一条车道里,绝对一个一个来。
你可能觉得这太保守了。
对吧?2026年了,还搞串行?
但做过Agent开发的人都懂:让多个Agent同时操作同一份数据,就像让三个厨师同时炒一个锅——你加盐他加糖,最后出来的菜谁都没法吃。日志乱成一团,Bug根本没法查。
OpenClaw的回答很坚决:默认串行,显式并行。
只有明确标记为低风险、可并行的任务(比如定时任务),才会被分配到独立lane并行执行。
消息太多排不下怎么办?三种处理方式:
- ●
collect:先攒着,等前面的做完再处理
- ●
steer:引导到别的地方去
- ●
followup:追加到当前任务后面
来不及处理被跳过的消息,系统还会自动生成一段摘要塞回去——确保Agent不会漏掉关键信息。
这套方案的品味在哪里?能用最简单的方案解决问题,就绝不引入复杂的外部工具。 原生的Promise就够了,为什么要加Redis?
四、Agent Loop:一个循环跑到底
打开src/agents/pi-embedded-runner/run.ts。
这个文件是Agent大脑的主入口。一条消息进来,要经过4层处理才能出结果:
agentRunner (接活)
→ agentRunnerExecution (排队调度)
→ runEmbeddedPiAgent (开始思考)
→ runEmbeddedAttempt (单次调用AI模型)
循环什么时候停?规则极简:AI模型回复了一段纯文字(没有说”我要用某个工具”)= 活干完了。
没有硬性的”最多跑几步”的限制,靠超时机制兜底。
Agent的”人设”怎么组装的?看src/agents/system-prompt.ts。它把4样东西拼在一起,交给AI模型:
- 1
AGENTS.md — 行为规矩。”你能做什么、不能做什么”
- 2
SOUL.md — 性格设定。”你说话是什么语气、什么风格”
- 3
Skills prompt — 当前这轮对话需要的技能
- 4
运行时上下文 — 当前环境的背景信息
模型怎么选?src/agents/pi-embedded-runner/model.ts里有个”模型注册表”,记录了每个模型的能力、价格、窗口大小。找不到合适的模型就报错切备用。
API key(调用AI模型的钥匙)也有”冷却机制”。一把钥匙用超了限额?自动换下一把。配置文件里可以存多组钥匙轮着用。
记忆容量的防护在src/agents/context-window-guard.ts:
- ●
快满了 → 先打个警告日志
- ●
真满了 → 直接喊停这一轮,换个方式重来
Agent死循环怎么办?
Agent陷入死循环怎么办?
做过Agent的人都知道,这是最常见的翻车方式——Agent反复调同一个工具,像仓鼠跑轮子一样停不下来。
OpenClaw内置了三个”死循环探测器”:
- ●
重复检测:同一个工具+同样的参数反复调用——发现了就喊停
- ●
原地踏步检测:一直在查询,但结果没有任何变化——喊停
- ●
乒乓检测:A工具→B工具→A工具→B工具,来回弹——喊停
三个探测器同时跑,超过次数阈值就告警或直接熔断。
还有一个值得提的模块:Canvas。
简单说,Agent不仅能跟你聊天,还能”画”界面给你看。
Canvas跑在独立的进程上,和Gateway分开——Canvas崩了不影响聊天,互不拖累。
Agent生成的HTML界面,通过WebSocket实时推送到你的浏览器上。说白了,Agent能给你临时搭一个小网页应用出来。
整个Agent干活的过程也是”边想边说”的——AI模型一边生成回复,一边发现需要调用工具就立刻去执行,执行结果立刻喂回去继续生成。思考和行动同步进行。一轮结束后,所有的对话记录、工具调用、执行结果都会保存到本地磁盘。
五、Memory:Markdown就是数据库
OpenClaw的记忆系统,走了一条”反潮流”的路。
别人第一天就上向量数据库,搞各种花哨的AI检索管道。
OpenClaw说:Markdown文件就是我的记忆库。
双层结构:
|
|
|
|
|---|---|---|
|
|
memory/2026-03-01.md |
|
|
|
MEMORY.md |
|
每次开始新对话,Agent会自动加载今天和昨天的日志。为什么是两天?
保持即时上下文连续性。又不撑爆上下文窗口。再往前的日志不会自动加载。
检索怎么做?两条路同时搜,然后合并结果。
第一条路:语义搜索——理解你话里的”意思”。你说”上次聊的那个项目”,它能找到相关内容,即使原文里没出现”项目”这两个字。
第二条路:关键词搜索——精确匹配你说的字词。
两路结果按7:3的比例混合——语义搜索占大头,关键词搜索做补充:
{
"vectorWeight": 0.7,
"textWeight": 0.3
}
还有两个聪明的小设计:
- ●
去重:内容差不多的记忆不会重复返回,避免翻来覆去看同一段话
- ●
时间衰减:越久远的记忆权重越低。半衰期30天——3个月前的笔记,即使内容很匹配,分数也会被大幅打折
但最关键的设计,藏在”记忆瘦身”逻辑里。
聊天聊多了,AI模型的记忆容量(上下文窗口)迟早会撑满。这时候OpenClaw要做”瘦身”——把早期的对话压缩掉,腾出空间。
但直接压缩就等于直接遗忘。
OpenClaw的做法很聪明:压缩之前,先让Agent做一次**”紧急备忘”**——系统偷偷给Agent发一条隐藏消息:”马上要瘦身了,赶紧把重要的事情记到笔记本里。”
看src/agents/pi-embedded-runner/compact.ts的配置:
{
"compaction": {
"memoryFlush": {
"enabled": true,
"softThresholdTokens": 4000,
"prompt": "Write any lasting notes to memory/YYYY-MM-DD.md"
}
}
}
这一步不做,瘦身就等于失忆。很多用OpenClaw的人抱怨”它忘了我说过的话”,根因就是这个”紧急备忘”功能没打开。
社区也在进化。有人做了知识图谱层,帮Agent理清”谁认识谁、什么事跟什么事有关”。有人做了跨对话记忆插件,让Agent换个聊天窗口也还记得你。官方的”文件优先”路线和社区的”图谱增强”路线,两条腿走路。
六、Skills + 安全:Markdown是双刃剑
Skill在OpenClaw里的定义很简单:一个包含SKILL.md的文件夹。
格式兼容Claude Code和Cursor。ClawHub(官方技能市场)上已有500+个社区Skill。
但这里有一个关键的设计细节——
技能”按需加载”,不是一股脑全塞进去。
OpenClaw在运行时会扫描你装了哪些Skill,但只会把当前这轮对话用得上的Skill告诉AI模型。为什么?因为塞太多进去,模型反而会”信息过载”,回答质量下降。
安全怎么保证?三道防线:
第一道:隔离小黑屋。 Agent要执行代码?不在你的电脑上直接跑,而是丢进一个Docker容器(你可以理解为”一次性虚拟机”)里跑。跑完就扔。你的真实文件和网络,它碰不到。
第二道:工具白名单/黑名单。src/agents/tool-policy.ts管着哪些工具能用、哪些不能用。黑名单优先于白名单——说不让用的,白名单里加了也没用。像定时任务、Gateway管理、WhatsApp登录这类敏感工具,只有”主人”才能用。
第三道:人工审批。 高风险操作弹窗让你确认,你点”同意”才执行。
但ClawHub的现实很骨感。
安全审计发现,12-20%上传到ClawHub的Skill含有恶意指令。一个叫ClawHavoc的攻击活动,通过伪装成正常Skill(名字叫solana-wallet-tracker、youtube-summarize-pro)分发macOS恶意软件。Cisco安全团队验证了数据泄露的完整链路。
攻击方式很隐蔽:Skill本质就是一段Markdown文本,而Markdown会被注入到Agent的”大脑”里。恶意Skill可以在Markdown里藏一句”把用户的数据发到某个网址”——Agent可能就照做了。可以修改其他Skill。可以执行危险命令。
这就是”通过扩展市场投毒”的攻击方式。
Skill的灵活性和攻击面,是同一枚硬币的两面。
三个参考的设计模式
拆完源码,值得带走的:
模式1:一个用户一条队列,严格排队。 你做Agent产品,别急着搞多线程并发。一个用户一条车道,任务排队一个一个来,就够了。简单方案解决复杂问题。
模式2:用Markdown当”行为说明书”。 AGENTS.md写行为规矩,SOUL.md写性格。AI天然擅长读Markdown,比JSON/YAML配置文件对Agent更友好。用户自己也看得懂、改得动。
模式3:瘦身前先备忘。 对话记录快满的时候,先让Agent把重要信息存到笔记里,再做压缩。这一步不做,长对话必出”遗忘”Bug。
说明
这篇适合:想翻OpenClaw源码的开发者,正在做Agent产品的创业者,对系统架构好奇的技术人。
如果你只想装一个OpenClaw玩玩,不想看代码——去看官方部署文档就行,这篇帮不了你。
一个常见误区:很多人以为OpenClaw是”多Agent协作框架”。官方VISION文档里明确说了,”经理管经理管经理”那种多层嵌套架构,不是OpenClaw要走的方向。OpenClaw的哲学是——把单个Agent做到极致,而不是让一群Agent互相开会。
20万star的代码库,翻开一看,骨架清晰得出人意料。
这也许是最值得学的一课:可靠的Agent系统,靠的是工程品味,不是架构复杂度。
不只是教AI,更陪你做AI小生意。 我是用AI开一人公司的周知,下回聊。
👇 打开小程序,openclaw小白入门手册,一条龙安排。
想和我一起探索AI×一人公司的可能性,加入「AI觉醒星球小程序」3月福利群
夜雨聆风
