OpenClaw 技术架构深度解析

OpenClaw 技术架构深度解析
Asaakii本文的架构脉络参考了 hesamation 的英文 thread,以及 Cell细胞的中文译文。但本文不是译文,也不是源码审计:我按 2026 年 7 月的公开文档重新核对了运行时、记忆和
exec的行为,并补上了初学者读原文时最容易缺失的因果链。
OpenClaw 迭代很快。端口、目录、默认策略、是否启用 sandbox,都会随版本和配置而变。本文解释的是架构和判断方法;部署时请再查看当前的官方文档与 release notes。特别是安全相关结论,不能把“功能支持”读成“你的实例已安全配置”。
先给结论:它到底是什么
OpenClaw 不是一个“会聊天的模型”。它是一个把聊天渠道、模型 API、文件与浏览器工具、会话记录放进同一套运行时的个人 Agent 系统。模型只负责根据眼前的上下文决定下一步;OpenClaw 负责把消息送到模型、把模型要求的动作执行掉,并把结果再交还给模型。
这一区分很重要。一个普通聊天窗口大致是“输入文本,得到文本”。OpenClaw 多了一条循环:
1 | 用户提出任务 → 模型决定要不要调用工具 → 系统执行工具 → 结果回到模型 → 模型继续判断 |
比如你在 Telegram 里说:“读一下下载目录,把昨天的发票列出来。”模型本身没有你的文件。它会先请求一个读目录的工具,拿到文件名后再筛选日期、读取候选文件,最后把结论发回 Telegram。能做事的不是模型的“记忆力”,而是这套循环和它被允许使用的工具。
读完本文,如果你能回答下面四个问题,就算真正掌握了主干:
- 一条 Telegram 消息为什么会进入某个特定会话,而不是直接交给模型?
- 模型为什么能“看见”文件和网页,又为什么有时会遗忘先前的约定?
- 同一条 shell 命令为什么可能在容器、Gateway 主机或另一台已配对的机器上运行?
- 为什么允许模型调用工具,并不等于应该让它拥有无限权限?
阅读前先补齐五个概念
后文有不少英文名词。它们不是五个神秘组件,先用一句话记住即可。
| 术语 | 初学者可以怎样理解 | 它不是什么 |
|---|---|---|
| LLM | 根据已有文字预测下一段文字的模型 | 不会直接读本机文件,也没有永久记忆 |
| Agent | 让 LLM 在“思考、调用工具、读取结果”之间循环的程序 | 不是另一种模型 |
| 工具(tool) | 受参数约束的能力接口,例如读文件、搜索、执行命令 | 不是自然语言提示词 |
| 上下文(context) | 当前一次模型调用真正收到的材料 | 不是完整历史的同义词 |
| 会话(session) | 一段对话及其运行状态、记录和默认设置 | 不等于一个用户或一个聊天软件 |
“上下文”和“记忆”最容易混。上下文像你摊在桌上的资料,模型只能看到桌上的这些。记忆是被写进磁盘的笔记,需要时再挑片段放上桌。聊天记录则更像录音:它可以留存,但不代表每次都会原样塞进模型的上下文窗口。
一条消息走完全程
假设你在 Slack 对 OpenClaw 说:“把仓库里今天改动的 Markdown 文件列出来,并告诉我哪篇还没有参考资料。”这条消息会经历下面的链路。
flowchart LR U["Slack 消息"] --> C["渠道适配器\n解析、鉴权、标准化"] C --> G["Gateway\n路由会话、管理连接与队列"] G --> R["Agent Runner\n拼上下文、调用模型、执行循环"] R --> M["LLM\n文本或工具调用"] M -->|"请求工具"| T["工具策略与执行面\nSandbox / Gateway / 配对 Node"] T -->|"文件或命令结果"| R M -->|"最终回复"| G G --> C --> O["Slack 回复"]
这张图里最需要把握的是职责边界:渠道适配器只负责“听懂某个平台的消息格式”;Gateway 管理系统里的连接、会话与调度;Agent Runner 管模型调用和工具循环;真正会触及文件、命令或浏览器的,是工具执行面。不要把这些全称作“AI”。
第一步:渠道适配器把不同聊天软件翻成同一种消息
Telegram、Slack、WhatsApp 的消息格式和鉴权方式并不一样。渠道适配器要做四类工作:验证 bot token 或登录状态,解析文字和附件,检查发送者或群聊规则,把最终回复转换成该平台能显示的格式。
因此,消息刚进系统时,最重要的信息不只是“用户说了什么”,还包括“它来自哪个渠道、哪个聊天、哪个已认证的发送者、是否带有附件”。这些元数据决定后续是否允许执行命令、该归入哪段对话,以及回复要发回哪里。
第二步:Gateway 决定这是谁的任务
Gateway 可以把它理解成常驻的调度服务。它维护渠道连接,识别这条消息要送给哪个 agent 和 session,也保存一部分会话与运行状态。默认监听地址常见为 127.0.0.1:18789,但端口和监听地址应以自己的配置为准。
“路由到会话”听起来抽象,实际很朴素。假设你同时在私聊和项目群里使用同一个 agent:私聊里讨论的是个人待办,项目群讨论的是发布计划。两处对话不应混成一锅。Gateway 用渠道、聊天标识和配置规则找到对应 session,Agent Runner 才能读到正确的历史与工作区指令。
Gateway 也是信任边界的一部分。它一头接外部渠道和 WebSocket 客户端,另一头能调度带工具权限的 agent。把它直接放到公网,等于把一个可能触及本机资源的控制入口暴露给陌生网络。是否“有 token”并不能替代网络隔离、访问控制和更新。
第三步:Agent Runner 把“该给模型看什么”组装出来
Agent Runner 不是模型本身。它为每次模型调用准备材料,选定提供方和模型,处理流式响应、失败重试或回退,并把工具定义交给模型。官方运行时把这部分放在内嵌 runner、session 管理和 provider transport 等模块中;插件只能通过公开 SDK 接口接入,而不应依赖内部目录结构。
一次调用的上下文通常由下表几类内容组成。实际顺序、预算和覆盖规则会随版本和 agent 配置变化,所以把它当作心智模型,而不是不可变的加载清单。
| 上下文材料 | 它回答的问题 | 常见载体 |
|---|---|---|
| 系统规则 | “我是谁,哪些事不能做?” | 内置系统提示词、策略配置 |
| 工作区说明 | “这个 agent 的工作方式和人格是什么?” | AGENTS.md、SOUL.md、TOOLS.md 等 |
| 相关记忆 | “以前已经确认过什么?” | MEMORY.md、每日笔记、检索片段 |
| 当前会话 | “刚刚聊到哪里?” | session 转录和摘要 |
| 工具定义 | “我能调用什么,参数怎么填?” | 内置或插件提供的 schema |
这里有两个常见误解。第一,SOUL.md 不是安全控制器,它只是模型会读到的一段指令文本。第二,工具说明进入上下文,不代表模型绕过工具策略就能执行。模型只能提出结构化请求,程序仍应在工具层检查这个请求。
第四步:模型在工具循环里工作
模型每次返回的东西通常有两种:最终文本,或工具调用。前者可以直接发回渠道;后者需要 Agent Runner 执行工具,把结果作为新消息追加到上下文,然后再问一次模型。
用上面的“检查 Markdown 参考资料”任务举例,内部过程可能接近这样:
1 | 用户:检查今天改动的 Markdown 文件和参考资料 |
模型不会像人一样在后台持续思考。每一轮都得重新把足够的上下文和上轮工具结果给它。为防止死循环或成本失控,运行时会设置工具轮数、超时、上下文预算等限制。出现“它一直在重复搜索”时,先别急着怪模型笨:工具结果可能不完整、任务描述不够可验证、或循环上限和错误处理不合适。
第五步:工具结果和最终答复回到原渠道
工具输出不会直接等于用户可见的答案。它先回到模型,模型可能据此继续行动,也可能写出解释。最终文本再经 Gateway 和渠道适配器返回原聊天软件;长回复还可能被分片,Markdown 会按平台规则转换。
同时,系统会保存会话转录。它常采用追加式记录,便于追踪用户消息、工具请求、工具结果和模型回复。不要执着于某个固定目录名:当前版本的会话与 agent 状态会按 agent 的状态目录组织,路径是可配置的。排查问题时应使用状态命令或配置,而不是照抄旧文章里的 ~/.openclaw/sessions/。
lane 队列:先保证同一会话不会互相踩脚
假设用户先发“把 README 标题改成 v2”,紧接着又发“把刚才改动撤销”。如果两条消息完全并行,后发任务可能先读取旧文件、先执行撤销,结果就会和用户看到的对话顺序相反。更糟的是,两个工具调用会同时写同一个文件。
OpenClaw 使用 lane 来表达这种调度关系。可以把 lane 想成单车道:进入同一条 lane 的工作按顺序走,后一个任务等前一个任务完成或让出位置。需要独立处理的定时任务或专门任务可以放到另一条 lane。它并不神奇地消灭所有并发问题,但把“默认串行”放在了靠近调度的位置。
这比到处给业务代码补锁更适合对话式任务。因为对用户而言,“我刚说完 A,又说 B”天然带有顺序含义。只有当任务确实独立,例如一个 cron 汇总和一段私聊,才值得显式并发。
不过不要把 lane 理解成事务。两个 lane 仍可能碰同一份外部资源,例如同一个 Git 工作树或同一张在线表格。开发者仍要选好隔离范围、幂等操作和冲突处理。lane 解决的是常见的会话内顺序问题,不是数据库级一致性保证。
记忆:磁盘笔记、检索和上下文压缩是三件事
“它记得我喜欢 TypeScript”背后,至少有三层机制,混在一起就容易把问题看错。
- 会话转录保存发生过什么。
- Markdown 记忆文件保存以后仍值得使用的事实、偏好和决定。
- 检索与上下文管理决定这次模型调用实际看到哪一部分。
当前官方文档把默认记忆工作区写为 ~/.openclaw/workspace,但多 agent 或自定义部署会有不同的 agent workspace。最常见的文件是:
| 文件 | 适合保存什么 | 是否会自动出现在新会话上下文 |
|---|---|---|
MEMORY.md |
稳定偏好、长期决定、短摘要 | 会,但有引导文件预算 |
memory/YYYY-MM-DD.md |
当天观察、过程记录、临时线索 | 不会整份注入,会供检索使用 |
DREAMS.md |
可选 Dreaming 机制的整理记录,供人审阅 | 不是常规长期记忆入口 |
这套设计的优点是可读、可编辑、可备份。你可以直接修改 Markdown,而不用猜一个黑箱数据库保存了什么。代价也很明确:如果把十万字日记塞进 MEMORY.md,它会挤占每一次模型调用的上下文;文件虽然仍在磁盘上,进入模型的副本可能被截断。
检索不是“把所有记忆都喂给模型”
当 embedding 提供方配置好后,memory_search 会将向量相似度和关键词匹配结合起来。向量检索适合找“语义相近”的内容,关键词对 API 名、订单号、代码符号更可靠。它们命中的片段再进入上下文,而不是整座记忆库被一次性搬进提示词。
这也解释了一个现象:模型可能“记得”你偏好 TypeScript,却忘了某个昨天提过的文件名。前者被提炼进长期记忆,后者也许只在每日笔记里,而且这次查询没有成功召回。需要精确找回的标识符,应保留清晰关键词和结构化上下文,而不是只写一句模糊感想。
压缩、修剪和记忆整理各自解决什么
长对话会塞满上下文窗口。OpenClaw 的三种机制不要混为一谈:
| 机制 | 处理对象 | 对磁盘记录的影响 | 目的 |
|---|---|---|---|
| Context pruning | 较旧、过大的工具结果 | 仅本次调用的内存视图,不改原始转录 | 减少无用工具输出占 token |
| Compaction | 较长的对话历史 | 用摘要替代部分历史的会话视图 | 让对话继续进行 |
| Memory flush | 压缩前的重要上下文 | 尝试写入记忆文件 | 降低摘要丢失关键事实的概率 |
官方文档还提供了可选的 Dreaming:它会按计划把短期记忆候选做筛选、整理和提升,并把过程写入 DREAMS.md 供人检查。它默认关闭,不能据此假定每个实例都会自动“遗忘旧记忆”。即便开启,记忆也只是给模型的提示材料,不能替代审批、sandbox 或其他硬性策略。
Pre-compaction memory flush 默认开启,作用是在会话被总结前给 agent 一个静默回合,把值得保留的内容写到文件。它有用,但不是保险箱。模型可能判断错重点、写入失败,或把没有授权边界的旧约定理解错。因此,“删除邮件前必须确认”这类约束应该同时进入权限策略,不能只依赖一段记忆或聊天历史。
这一节只搭建架构地图。记忆文件的分工、混合检索与压缩细节,可以接着读《OpenClaw 记忆系统深度解析》。
Computer Use:模型没有手,工具才是它的手
“Computer Use”常被理解为模型看截图、点鼠标。实际范围更广:文件读写、shell 命令、浏览器控制、后台进程都可能属于 agent 的行动能力。每种工具的风险不同,也不应共用一套粗糙权限。
| 能力 | 典型任务 | 主要风险 | 更合适的默认态度 |
|---|---|---|---|
read / write / edit |
阅读和修改工作区文件 | 覆盖重要内容、读取敏感文件 | 限定工作区和可写范围 |
exec |
调用 Git、构建、脚本 | 任意命令和凭据泄露 | sandbox 或审批优先 |
| browser | 查询、表单、网页操作 | 提示注入、误提交、登录态泄露 | 使用独立浏览器 profile |
| process | 长时间构建或服务 | 遗留进程、资源消耗 | 限制时长并追踪状态 |
浏览器尤其值得单独说。OpenClaw 管理的浏览器可以使用一个专供 agent 的 Chrome、Brave、Edge 或 Chromium profile,和个人浏览器资料隔离。它能用文本化的可访问性树来表示页面,例如按钮、输入框、标题和它们的引用编号。对多数填表、搜索、点链接任务,语义快照比反复截图更轻,也更容易让模型定位控件。
1 | - textbox "搜索关键词" [ref=2] |
但“看得懂网页结构”不等于“懂得网页内容是否可信”。网页里可以有诱导 agent 忽略规则的文字,也可能把删除、支付、授权伪装成普通按钮。涉及资金、发布、账户授权和删除数据的动作,仍应要求人工确认。
执行面与 sandbox:同一个 exec,可能落到三处
这部分是初学者最容易产生危险误解的地方。exec 是一个会修改环境的 shell 能力。禁用 write、edit 等文件工具,并不会让 exec 自动只读,因为 shell 自己就可以写文件或发网络请求。
当前 exec 的 host 可以是 auto、sandbox、gateway 或 node:
| 执行位置 | 它是什么 | 适合什么场景 |
|---|---|---|
| sandbox | 隔离运行时中的命令 | 默认处理不完全可信的任务 |
| Gateway | 运行 OpenClaw 服务的那台主机 | 必须访问该主机资源的受控维护任务 |
| Node | 已配对的伴侣设备或 Node Host | 明确需要操作另一台指定设备时 |
| auto | 有 sandbox 时选 sandbox,否则选 Gateway | 方便,但必须先确认实际解析结果 |
官方文档明确写着:sandbox 默认关闭;它关闭时,host=auto 会解析到 Gateway。更容易被忽略的是,未显式收紧时,Gateway 和 Node 的 host 策略默认是 security=full、ask=off。这不代表所有部署都会这样运行,但足以说明不要把“我没配置任何东西”误当成“它会弹窗问我”。
如果你刚开始使用,先做两件事:启用 sandbox,并把 host 执行设为需要审批或 allowlist。下面的配置只展示思路,字段和可用模式仍应与当前版本文档核对:
1 | { |
mode: "ask" 的意思通常是 allowlist 命中的命令直接通过,其余命令请求人工批准;deny 则完全禁用执行。不要为了“少弹几个框”把一长串复杂 shell 放进永久 allowlist。安全策略要识别的是可执行程序、参数和执行位置,而不是只看一段看起来无害的自然语言。
为什么 exec 的安全问题很难靠黑名单补完
早期安全设计常把“允许什么命令”写成命令名或路径的模式匹配,再配合人工批准。它对简单命令有用,但 shell 会解释重定向、变量、转义、子命令和解释器参数。策略层看到的文本,未必等于 shell 最终执行的语义。
例如,批准“某个程序”不一定等于批准它调用的子解释器;拒绝一个完整选项名,也不等于覆盖同一行为的所有写法。更近的 OpenClaw 文档已经为 allowlist 模式增加了多段命令、重定向、内联解释器等限制和审批回退,但这类边界仍需要持续审计,不能把 allowlist 当作沙箱的替代品。
一篇 arXiv 预印本收集并分类了 OpenClaw 相关 advisory。其中的价值不在于某个数字能代表今天的漏洞总数,而在于它把风险按接口拆开:Gateway WebSocket、渠道输入、工具分发、exec 策略、容器边界和技能分发会相互叠加。单点看似中等的问题,串起来可能变成越权或远程命令执行。
flowchart LR A["外部输入或不可信内容"] --> B["影响会话、模型或 Gateway"] B --> C["取得更高权限的工具路径"] C --> D["读取数据、改策略或执行命令"]
这张图不是某个漏洞的复现步骤,而是威胁建模方法:每次新增渠道、插件、浏览器登录态或配对 Node,都问一遍“谁能提供输入”“输入会进入哪里”“它能影响什么权限”“这个权限能否再跳到别处”。
Skills 也应放进这个模型里。SKILL.md 往往会进入 agent 的上下文,因而它既可以教会 agent 一个可靠流程,也可能夹带恶意指令,诱导模型下载、执行或泄露内容。安装社区 skill 前先读文件、确认来源和依赖;对不可信网页、邮件和附件,把它们当作数据,不要让它们改写系统规则。
给初学者的部署核对表
理解架构的目的,是能做判断,而不是背组件名。如果你已经运行了 OpenClaw,下面的检查比继续调 prompt 更优先:
- Gateway 是否只监听本机或受控内网?若必须远程访问,是否经过认证和安全网络入口?
- sandbox 是否真的已启用?当前会话的
/exec状态里,host=auto最终会落在哪里? - Gateway 与 Node 的
tools.exec是否显式设为ask、allowlist或deny,而不是依赖默认值? - 渠道 allowlist 是否使用平台稳定的用户或聊天 ID,而不是可修改的显示名和用户名?
- 浏览器是否使用独立 profile?是否避免把主力邮箱、密码管理器和金融账户直接暴露给 agent?
- 记忆中是否把“需要确认后才能执行”的约束写清触发条件、失效条件和负责人?更重要的是,是否有权限策略来强制它?
- 安装的 plugin 与 skill 是否来自可追溯来源,并且更新后重新检查过权限?
可以把这张表当作一次小练习。你不必先理解 TypeScript 或 WebSocket,先能在自己的实例里查到“这条命令将在哪执行、谁可以触发它、需要谁批准”,就已经掌握了 OpenClaw 架构最实用的部分。
小结
OpenClaw 把 LLM 放进一个会话驱动的运行时:渠道适配器接消息,Gateway 找到正确的会话并安排任务,Agent Runner 把上下文和工具定义交给模型,模型通过工具循环完成任务,执行面在策略约束下触及真实环境。
这套架构有几个很朴素的取舍。lane 把同一会话的顺序放在默认路径上;语义快照尽量先提供结构化网页信息,再考虑昂贵的视觉输入;Markdown 记忆让人能查看和修改 agent 保存的事实。另一方面,记忆检索会漏召回,压缩会损失细节,shell 的语义也比字符串规则复杂得多。把安全交给提示词、记忆或一次“允许”都不够。
所以,OpenClaw 最适合被看作一套“把模型接到现实世界”的运行时,而不是一个无所不能的聊天机器人。模型负责提出下一步,系统设计负责决定它看得到什么、做得了什么,以及做错时损失有多大。











