OpenClaw 技术架构深度拆解
关于本文:这篇文章由 AI 自动分析 OpenClaw 开源代码库后生成,聚焦 HOW(实现细节)而非 WHAT(功能介绍)。Axton 对结构和关键判断做了审校,但主体内容来自 AI 的源码阅读。这本身就是"AI 辅助深度研究"的一个实际案例。
1. 整体架构概览
OpenClaw 是一个 TypeScript ESM 项目,运行在 Node.js 22+ 之上,使用 pnpm 构建,可选 Bun 执行。整个系统是一个三层架构:
Channel Adapters → Gateway (控制平面) → Agent Runtime (Pi Agent Core)
↑ ↑ ↑
消息标准化 会话路由/队列 LLM 推理 + 工具执行
核心设计模式:Hub-and-Spoke(轮毂-辐条)。Gateway 是中心轮毂,所有 Channel Adapter 和工具执行都是辐条。
源码目录结构(关键路径)
| 目录 | 职责 |
|---|---|
src/agents/ |
Agent 运行时逻辑 |
src/agents/pi-embedded-runner/ |
PiEmbeddedRunner 核心循环 |
src/agents/pi-tools.ts |
工具注册与创建 |
src/agents/system-prompt.ts |
系统提示词组装 |
src/agents/model-selection.ts |
模型选择与 failover |
src/agents/sandbox/config.ts |
沙箱配置解析 |
src/browser/ |
浏览器控制层 |
src/memory/ |
记忆系统(向量搜索 + FTS5) |
src/memory/manager-search.ts |
搜索核心实现 |
src/memory/hybrid.ts |
混合搜索合并逻辑 |
src/cron/ |
Cron/定时任务调度 |
src/telegram/ |
Telegram 适配器 |
src/discord/ |
Discord 适配器 |
src/slack/ |
Slack 适配器 |
src/signal/ |
Signal 适配器 |
src/imessage/ |
iMessage 适配器 |
src/web/ |
WhatsApp Web 适配器 |
src/channels/ |
通道共用逻辑 |
src/routing/ |
消息路由 |
src/config/sessions.ts |
Session Key 推导 |
src/hooks/ |
Hook 系统(内置 + 插件) |
src/media/ |
媒体处理管线 |
src/canvas-host/a2ui/ |
A2UI Canvas 渲染 |
extensions/ |
插件扩展(msteams, matrix, zalo 等) |
skills/ |
内置 Skills |
src/plugin-sdk/ |
插件 SDK(构建后输出到 dist/plugin-sdk/) |
2. Gateway:控制平面的核心
2.1 进程模型
Gateway 是一个 单进程 WebSocket 服务器,默认绑定到 127.0.0.1:18789。使用 ws 库,所有 WebSocket frame 通过 JSON Schema(由 TypeBox 生成)验证。
关键约束:
- 单 Gateway per host(防止 WhatsApp session 冲突)
- 事件驱动,非轮询
- 所有副作用操作需要幂等键(idempotency keys),保证安全重试
- 非 loopback 绑定时需要 token 或 password 认证
2.2 Session Router(会话路由器)
Session Key 的格式是层级化的:
agent:<agentId>:<rest>
<rest> 的格式因会话类型和 scope 策略而异:
具体例子:
agent:main:main— 操作者主会话(完整权限),格式agent:<agentId>:<mainKey>agent:main:whatsapp:direct:+15555550123— WhatsApp 私聊(per-channel-peerscope)agent:main:direct:+15555550123— 跨通道合并 DM(per-peerscope)agent:main:telegram:group:-1234567890— Telegram 群聊agent:work:slack:direct:U0123ABC— 多 Agent 的 Slack 私聊
Session key 的段数不固定——DM 会话根据 dmScope(main/per-peer/per-channel-peer/per-account-channel-peer)生成不同层级的 key。
核心函数:
deriveSessionKey(src/config/sessions.ts):从 channel/message 上下文推导 session keyresolveSessionKey:标准化并验证 session key 格式
Session 状态以 append-only JSONL 格式持久化到 ~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl,支持分支(branching),可用于恢复和对话树检查。
2.3 Lane Queue(车道队列):并发控制核心
这是 OpenClaw 最精巧的设计之一。队列采用 lane-aware FIFO 架构,纯 TypeScript + Promises 实现,无外部依赖、无后台线程。
Lane 类型与默认并发上限:
| Lane | 默认并发数 | 用途 |
|---|---|---|
session:<key> |
1 | 每个会话严格串行 |
main |
4 | 主聊天 + 心跳 |
cron |
(独立) | 定时任务 |
subagent |
8 | 子 Agent 生成 |
nested |
(独立) | 嵌套工具调用 |
核心保证:"Only one agent run touches a given session at a time"——通过 per-session lane 实现。
消息处理模式(inbound message 如何与正在运行的 agent turn 交互):
| 模式 | 行为 |
|---|---|
steer |
立即注入当前 run,在下一个 tool boundary 后取消待执行工具;如果非 streaming 则回退到 followup |
followup |
排队到当前 run 结束后的下一轮 |
collect(默认) |
合并排队消息为单个 followup;不同 channel 的消息分开路由 |
steer-backlog |
立即 steer 并保留 followup 备份(可能导致 streaming 中重复响应) |
interrupt |
中止当前 run,执行最新消息 |
队列参数:
debounceMs(默认 1000ms):等待无新消息后再启动 followup turncap(默认 20):每 session 最大排队消息数drop(默认 "summarize"):溢出策略——old/new/summarize(从被丢弃的消息生成合成摘要)
用户可通过 /queue <mode> 动态切换。

3. Agent Runtime:Pi Agent Core
3.1 核心循环
OpenClaw 内嵌了 @mariozechner/pi-agent-core(简称 Pi),通过 runEmbeddedPiAgent 函数驱动完整的 agentic loop。
循环的 4 个阶段:
- Session Resolution — 确定哪个 session 处理消息
- Context Assembly — 加载历史、构建动态 system prompt、通过语义搜索拉取记忆
- Model Invocation — 流式调用配置的 provider(Anthropic/OpenAI/Google/本地模型)
- State Persistence — 将更新后的对话状态写回磁盘
循环终止条件:LLM 发送了纯文本响应(没有 tool_use block)= 任务完成。仓库层无 max-steps 限制,仍受 timeout 等运行时约束。

3.2 关键抽象类型
| 类型 | 职责 |
|---|---|
EmbeddedPiAgentMeta |
Agent 配置(workspace, model, tools, sandbox) |
EmbeddedPiRunMeta |
每个 turn 的元数据(session key, message, channel context) |
EmbeddedPiRunResult |
执行结果(success/error, usage, timing) |
SubscribeEmbeddedPiSessionParams |
流式回调,用于实时输出 |
3.3 System Prompt 组装
buildAgentSystemPrompt(src/agents/system-prompt.ts)组装多个 section,有三种模式:
| 模式 | 用途 | 包含的 Sections |
|---|---|---|
full |
主 Agent(默认) | 全部 |
minimal |
子 Agent | Tooling, Workspace, Runtime |
none |
基础身份 | 仅核心身份 |
Prompt 组件(按注入顺序):
AGENTS.md— 操作指令和记忆规则SOUL.md— 人格、边界、语调TOOLS.md— 用户维护的工具使用指南IDENTITY.md— Agent 命名和身份USER.md— 用户资料BOOTSTRAP.md— 一次性初始化(完成后删除)- Skills 注入(动态 XML 列表)
- Memory 语义召回结果
- 消息规则 / TTS 提示 / Reply Tags
- 自动生成的工具定义(内置 + 插件)
- Runtime 环境信息
关键设计:空文件被跳过;大文件被裁剪并加截断标记。这种"文件即配置"模式让行为变更无需改源码——编辑 Markdown 文件即可。
3.4 Model Selection 与 Failover
resolveDefaultModelForAgent(src/agents/model-selection.ts):
模型引用格式:provider/model(按第一个 / 分割)。
Failover 策略:
| 错误类型 | 策略 |
|---|---|
auth_error(401, invalid_api_key) |
标记 profile bad,轮换 auth |
billing_error(402, insufficient_quota) |
长 cooldown(默认 5h,指数增长至 24h 上限) |
rate_limit(429) |
临时 cooldown |
context_overflow |
自动 compact 并重试 |
timeout / overloaded / unknown |
各种重试策略 |
Auth Profile 轮换:resolveAuthProfileOrder 确定轮换顺序,isProfileInCooldown 检查冷却状态。
冷却参数(默认值):
billingBackoffHours:5h(billing 错误的基础回退时间,指数增长)billingMaxHours:24h(billing 回退上限)failureWindowHours:24h(错误计数重置窗口)
非 billing 错误的回退曲线:1min → 5min → 25min → 最大 1h(指数增长,5^n 分钟)。
3.5 Streaming 架构
- Assistant deltas 从 pi-agent-core 作为
assistant事件流出 - Block streaming 在
text_end或message_end时发出部分回复 - Reasoning 单独 stream 或作为 block replies
- Chat channel 将 deltas 缓冲为
delta消息,lifecycle 完成时发出final - 关键:外部消息通道(WhatsApp/Telegram)永远只发送最终回复,不发 streaming/partial
3.6 Compaction(上下文压缩)
当 session 接近 context window 上限时触发自动压缩。
触发阈值:contextWindow - reserveTokensFloor - softThresholdTokens
- 以 200K context window 为例:200K - 20K reserve - 4K soft = 约 176K tokens 时触发
Memory Flush(压缩前的记忆冲刷):
这是 OpenClaw 最巧妙的设计之一。在满足触发条件的情况下,compaction 发生前系统触发一个 silent agentic turn(对用户不可见),提醒模型将可持久信息写入 memory/YYYY-MM-DD.md(必要时再整理到 MEMORY.md)。模型通常以 NO_REPLY 开头回复,OpenClaw 的投递层会过滤掉这个前缀。
防重机制:session state 中跟踪 memoryFlushCompactionCount,防止同一 compaction 周期重复 flush。
核心函数:compactEmbeddedPiSession(src/agents/pi-embedded-runner/compact.ts)
4. Tool 系统
4.1 工具注册
createOpenClawCodingTools(src/agents/pi-tools.ts)将 Pi 核心工具与 OpenClaw 特有工具合并:
Pi 核心工具(来自 pi-agent-core):
read— 读文件write— 写文件edit— 编辑文件exec/process— 执行命令(替换了 Pi 原生的bash)
OpenClaw 扩展工具:
browser— 浏览器自动化canvas— Canvas 渲染nodes— 节点操作cron— 定时任务管理sessions— 会话管理(list, history, send, spawn)message— 消息发送memory_search— 语义搜索记忆memory_get— 读取记忆文件web_fetch/web_search— 网络工具
工具定义使用 TypeBox(JSON Schema with TypeScript types)声明。每个 tool result 携带 output(文本给 LLM)和 details(结构化数据给 UI 渲染)。
4.2 Tool Policy 层级
权限按 pipeline 顺序逐层过滤(每一层都可以收窄工具集):
1. Profile Policy (tools.profile)
2. Provider-Profile Policy (tools.byProvider.profile)
3. Global Policy (tools.allow/deny)
4. Global-by-Provider Policy (tools.byProvider.allow)
5. Agent Policy (agents.<id>.tools.allow)
6. Agent-by-Provider Policy (agents.<id>.tools.byProvider.allow)
7. Group Policy (group tools.allow)
→ 再叠加 Sandbox 限制 + Subagent 限制
Tool 分组:
group:fs:read, write, edit, apply_patchgroup:runtime:exec, processgroup:sessions:sessions_list, sessions_history, sessions_send, sessions_spawn, subagents, session_statusgroup:memory:memory_search, memory_get
默认 Sandbox Policy(DEFAULT_TOOL_ALLOW):允许 exec, process, read, write, edit, apply_patch, image, sessions_list, sessions_history, sessions_send, sessions_spawn, subagents, session_status;禁止 browser, canvas, nodes, cron, gateway 及各 channel 工具。注意:memory_search/memory_get 不在默认允许列表中。
4.3 Plugin Hooks
Hook 是 TypeScript 模块,每个 Hook 目录包含 HOOK.md(文档)和 handler.ts(实现)。通过 jiti(运行时 TypeScript 加载器)加载,无需预编译。
生命周期 Hook:
onSessionStart— 会话开始onBeforeTurn— 每轮推理前onToolCall/before_tool_call— 工具调用前拦截onToolResult/after_tool_call— 工具结果后处理before_compaction/after_compaction— 压缩前后tool_result_persist— 结果持久化
内置 Hook 示例:
session-memory(src/hooks/bundled/session-memory/handler.ts):/new时将 session 上下文保存到<workspace>/memory/YYYY-MM-DD-slug.mdcommand-logger(src/hooks/bundled/command-logger/handler.ts):命令日志boot-md(src/hooks/bundled/boot-md/handler.ts):引导文件处理
5. Memory 系统(持久记忆)
5.1 存储架构
OpenClaw 的记忆哲学是 "文件即真理"——只有写入磁盘的内容才会被保留。
文件结构:
MEMORY.md— 策展的长期记忆(仅在 private session 加载,group 中不加载以保护隐私)memory/YYYY-MM-DD.md— 每日 append-only 日志(session 开始时加载今天 + 昨天的)- 格式:纯 Markdown,人类可读可编辑
Session 日志:
~/.openclaw/agents/<agentId>/sessions/*.jsonl— append-only 事件日志- DM 会话历史限制:默认无上限
- Group 会话历史限制:默认 100 turns
5.2 索引管线
索引存储:~/.openclaw/memory/<agentId>.sqlite(per-agent SQLite 数据库)
Chunking 策略:
- 每 chunk 约 400 tokens
- 80 tokens 滑动窗口重叠
- 存储在
chunks表,包含文件路径、行范围、hash 等元数据
同步触发器:
- Session 开始时
- 搜索发生时
- 定时间隔
- Session transcript 达到 delta 阈值(100KB 或 50 行 JSONL)
文件监听:MEMORY.md 和 memory/ 目录的 watcher,1.5s debounce。
如果 embedding provider/model/endpoint 指纹或 chunking 参数变化,整个索引重建。
5.3 混合搜索实现
这是记忆系统的核心引擎。两路搜索并行执行,结果合并。
Vector Search(searchVector() in src/memory/manager-search.ts:18-90):
- Backend:
sqlite-vec扩展,使用vec_distance_cosine()计算相似度 - 索引类型:vec0 虚表(sqlite-vec 原生格式,精确搜索而非近似索引)
- 加载超时:30 秒探测超时
- 候选池策略:获取
4 × maxResults候选,再排序取 Top-K - Snippet 截断:700 字符(SNIPPET_MAX_CHARS)
- Fallback:如果 sqlite-vec 不可用,加载候选 chunks 到内存,用纯 JS 计算 cosine similarity(余弦相似度)
Keyword Search(searchKeyword() in src/memory/manager-search.ts:92-148):
- Backend:SQLite FTS5(全文搜索引擎),
chunks_fts表 - 排名:FTS5 原生 BM25 评分,通过
bm25RankToScore()转换为标准化分数 - 查询解析:
buildFtsQuery()处理引号短语、AND/OR 运算 - Snippet:FTS5 内置
snippet()函数
混合合并(mergeHybridResults() in src/memory/hybrid.ts:33-108):
finalScore = vectorWeight × vectorScore + textWeight × textScore
默认权重:vector 0.7, text 0.3。低于 minScore(0.35)的结果被过滤。最终返回 Top maxResults(默认 6)。

5.4 Embedding Provider 链
自动选择顺序:
- Local GGUF(如果
memorySearch.local.modelPath存在) - OpenAI(如果 API key 可用)
- Gemini(如果 API key 可用)
- Voyage(如果 API key 可用)
- 禁用
超时设置:
- 远程 Provider(OpenAI/Gemini):60 秒
- 本地 Provider(node-llama-cpp):5 分钟
Embedding 缓存:chunk embedding 缓存在 SQLite embedding_cache 表,最多 50,000 条,避免重索引时重复调用 API。
5.5 实验性功能
QMD Backend(memory.backend = "qmd"):
- Local-first Bun + node-llama-cpp sidecar
- 结合 BM25 + 向量 + reranking,无需 Ollama
- 自包含 XDG home:
~/.openclaw/agents/<agentId>/qmd/ - 自动从 HuggingFace 下载 GGUF 模型
Session Memory Indexing(实验性):
- 将 User/Assistant turns 独立索引
memory.memorySearch.experimental.sessionMemory = true- 异步索引,带 delta 阈值防止阻塞
5.6 Agent 工具接口
memory_search(src/agents/tools/memory-tool.ts):执行混合搜索,返回 JSON 文本格式结果(通过jsonResult()包装,包含文件路径、行号、分数等结构化数据)memory_get(src/agents/tools/memory-tool.ts):读取特定 Markdown 文件,支持行范围切片。默认限制在MEMORY.md/memory/路径内,但可通过配置extraPaths扩展允许读取的额外路径
6. Skills 系统
6.1 Skill 结构
每个 Skill 是一个目录,核心文件是 SKILL.md(Markdown + YAML frontmatter):
必需 frontmatter 字段:
name:技能标识符description:简要描述
可选 frontmatter 字段:
homepage,user-invocable,disable-model-invocation,command-dispatch,command-tool,command-arg-mode
metadata.openclaw 控制资格检查:
always: true— 强制注入os— 平台过滤(darwin/linux/win32)requires.bins/requires.anyBins— 二进制路径检查requires.env— 环境变量检查requires.config—openclaw.json路径真值检查primaryEnv— 关联的 API key 环境变量install— 安装器规格(brew/node/go/uv/download)
注意:parser 只支持 单行 frontmatter key,metadata 是 单行 JSON 对象。
6.2 发现与优先级
三个加载位置,优先级从高到低:
- Workspace skills(
<workspace>/skills)— 最高优先级 - Managed/local skills(
~/.openclaw/skills) - Bundled skills(npm 包 / OpenClaw.app)— 最低优先级
额外路径通过 skills.load.extraDirs 加载,优先级最低。插件在 openclaw.plugin.json 中声明 skills 目录。
6.3 注入逻辑
- 加载时通过 metadata gates 过滤 skills
- 运行开始时,将
skills.entries.<key>.env或apiKey注入process.env formatSkillsForPrompt将可用 skills 格式化为 compact XML list 注入 system prompt- 运行结束后恢复原始环境
Session Snapshot:session 开始时快照 eligible skills,后续 turns 复用。Skills watcher(默认开启)监听 SKILL.md 文件变化,触发中途刷新。配置:skills.load.watch、watchDebounceMs。
6.4 Token 开销
- Base:195 字符(当 >= 1 skill 时)
- Per skill:97 字符 + escaped
name,description,location长度 - 约 24 tokens/skill(按 4 chars/token 估算)
6.5 环境变量隔离
{
skills: {
entries: {
"skill-name": {
enabled: true,
apiKey: "KEY_VALUE",
env: { VAR_NAME: "value" },
config: { custom: "fields" }
}
}
}
}
环境变量 仅在未设置时注入,作用域是 per agent run,不是全局。运行结束后通过 applySkillEnvOverridesFromSnapshot() 的 restore 函数恢复 process.env。
7. Channel Adapters(通道适配器)
7.1 统一接口
每个 Channel Adapter 实现相同的接口:
- 认证:各平台特有方式
- Inbound 解析:标准化文本、媒体、线程、reactions
- Access 控制:allowlist、DM pairing、group mention requirements
- Outbound 格式化:Markdown 转换、消息分块、媒体上传
7.2 具体实现
| Channel | 库 | 认证方式 | 源码 |
|---|---|---|---|
@whiskeysockets/baileys |
QR code pairing | src/web/ |
|
| Telegram | grammY |
Bot token (TELEGRAM_BOT_TOKEN) |
src/telegram/ |
| Discord | discord.js |
Bot token (DISCORD_BOT_TOKEN) |
src/discord/ |
| Slack | — | OAuth / token | src/slack/ |
| Signal | — | — | src/signal/ |
| iMessage | AppleScript / native macOS | macOS Messages.app | src/imessage/ |
| MS Teams | — | — | extensions/msteams/ |
| Matrix | — | — | extensions/matrix/ |
| Zalo | — | — | extensions/zalo/ |
| Voice Call | — | — | extensions/voice-call/ |
WhatsApp 深入:Baileys 实现了 WhatsApp Web 协议的逆向工程——通过 WebSocket 直接与 WhatsApp 服务器通信,模拟网页端客户端。凭证存储在 ~/.openclaw/credentials/,使用多文件认证状态持久化。
iMessage 深入:需要 macOS,使用 AppleScript 与 Messages.app 交互。需要合适的签名权限。读取 Messages 数据库获取消息事件。
7.3 扩展通道(Plugin)
插件通过 openclaw.plugin.json 声明,Gateway 管理插件生命周期:
- Discovery:扫描
extensions/*的openclaw.extensionsmanifest - Validation:manifest schema 验证
- Loading:通过 jiti 导入插件模块
- Initialization:调用 plugin setup hooks
- Runtime:注册到 Gateway 子系统
Plugin SDK(dist/plugin-sdk/)提供类型定义、验证工具和辅助函数。插件通过 api.registerTool(toolName, toolDefinition) 注册新工具。
8. DM Policy 与权限系统
8.1 DM Policy 四种模式
| 模式 | 行为 |
|---|---|
pairing(默认) |
未知发送者收到限时配对码(1h 过期),消息被阻止直到审批通过。每 channel 最多 3 个 pending 请求 |
allowlist |
直接阻止未知发送者,不提供配对握手 |
open |
允许任何人 DM。配置校验要求 allowFrom 必须包含 "*"(否则校验失败),运行时则直接放行,不再逐条检查 allowlist |
disabled |
完全忽略入站 DM |
配对审批:
openclaw pairing list <channel> # 查看待审批
openclaw pairing approve <channel> <code> # 审批
审批数据存储在 ~/.openclaw/credentials/<channel>-allowFrom.json,与配置中的 allowlist 合并。
8.2 Group Policy
- WhatsApp/Telegram/Signal/iMessage:
groupPolicy="allowlist"+groupAllowFrom - Discord/Slack:per-surface channel allowlists(
channels.discord.guilds/channels.slack.channels) - 群内可额外通过
requireMention: true分层控制
8.3 Tool 权限控制
Per-agent 的 allow / deny 列表:
{
agents: {
list: [{
id: "family",
tools: {
allow: ["read"],
deny: ["write", "edit", "apply_patch", "exec", "process", "browser"]
}
}]
}
}
高风险工具(exec, browser, web_fetch, web_search)应限制给受信 agent。
8.4 安全审计
openclaw security audit 命令检查:
- 入站访问策略(DM、group、allowlist)
- 宽松房间中的工具爆炸半径
- 网络暴露(binding、认证、token 强度)
- 浏览器控制暴露
- 本地磁盘卫生(权限、symlinks)
- 插件安全
- Policy drift 和误配置
--deep 启用实时 Gateway 探测;--fix 自动应用安全护栏。
9. Sandbox(沙箱隔离)
9.1 Docker 隔离架构
沙箱针对的是 工具执行,而非 Gateway 本身。
Container 参数:
--read-only:只读根文件系统--memory/--memory-swap:内存限制--cpus:CPU 限制--network none(默认):无网络访问-v <host>:/workspace:workspace 挂载
9.2 Scope 模式
| Scope | 容器生命周期 | 隔离度 |
|---|---|---|
session |
每会话创建/销毁 | 最强 |
agent(默认) |
每 agent 共享 | 防止跨 agent 访问 |
shared |
所有 agent 共享 | 最高效 |
9.3 Workspace 访问控制
| 模式 | 行为 |
|---|---|
none(默认) |
workspace 不可访问,工具在隔离的 ~/.openclaw/sandboxes 下运行 |
ro |
只读挂载在 /agent,禁用 write/edit/apply_patch |
rw |
读写挂载在 /workspace |
9.4 容器生命周期
核心函数:
ensureSandboxWorkspaceForSession— 创建 workspace 目录buildSandboxCreateArgs— 构建docker run参数resolveSandboxConfigForAgent(src/agents/sandbox/config.ts)— 解析沙箱配置resolveSandboxContext— 构建沙箱上下文
容器在 session 终止或 Gateway 重启时清理。Exec 工具通过 docker exec 将命令路由到容器。
9.5 Sandbox Policy 对工具的限制
沙箱化 session 无法访问:
- 宿主浏览器控制(除非
browserAllowHostControl: true) - Canvas hosts
- Paired nodes
- Host-only cron jobs
10. Browser 自动化
10.1 双层架构
Agent → browser tool → Control Server (HTTP) → CDP → Chromium
↑
Playwright (高级操作)
底层使用 Chrome DevTools Protocol (CDP) 连接 Chromium 浏览器。Playwright 作为 CDP 之上的抽象层处理高级交互(click, type, snapshot, PDF)。
当 Playwright 不可用时:基本 screenshot 和 ARIA snapshot 仍然可用,但交互操作返回 501 错误。
10.2 Browser Profiles
| Profile | 描述 |
|---|---|
openclaw-managed |
专用 Chromium 实例,隔离 user data dir,CDP port 18800-18899 |
chrome |
Extension relay 模式,指向个人 Chrome(本地 relay 127.0.0.1:18792) |
remote |
显式 CDP URL,连接远程浏览器 |
Port 架构:
- Control server:
18791(= gateway port + 2) - Relay:
18792(= gateway port + 3) - 自定义
gateway.port时,derived ports 同比偏移
10.3 Snapshot 系统
Agent 理解网页的方式——不是通过 CSS selector,而是通过 snapshot 生成的 numeric refs(数字引用)。
AI Snapshot(默认,需 Playwright):
12: button "Submit"
23: input "Email"
Agent 使用 openclaw browser click 12 操作元素。
Role Snapshot:
- 基于 accessibility tree(无障碍树),refs 如
e12 - 支持
--interactive,--compact,--depth,--labels
关键约束:refs 在页面导航后不稳定,必须重新生成 snapshot。
10.4 Chrome Extension Relay 模式
驱动你现有的 Chrome tabs:
- 本地 relay server 在
127.0.0.1:18792监听 - 需要手动 per-tab attach(点击 extension icon)
- Badge 显示
ON表示接管中 - 远程 Gateway 需要在浏览器机器上运行 node host 做代理
10.5 Wait 机制
支持组合等待条件:
- URL 模式:
--url "**/dash"(Playwright glob 语法) - 加载状态:
--load networkidle - JS 断言:
--fn "window.ready===true" - Selector 可见性:
wait "#main" - 可与
--timeout-ms组合
11. Cron / Heartbeat(定时与心跳)
11.1 Heartbeat(心跳)
执行模型:在 main session 中按固定间隔(默认 30 分钟)触发一次 agent turn。
{
agents: {
defaults: {
heartbeat: {
every: "30m",
target: "last",
activeHours: { start: "08:00", end: "22:00" }
}
}
}
}
HEARTBEAT.md:Agent 每次心跳时检查的 Markdown checklist。保持精简以减少 token 开销。
HEARTBEAT_OK 信号:如果没有需要注意的事项,agent 回复 HEARTBEAT_OK,Gateway 静默丢弃,不推送消息。
Rotating Heartbeat 模式:用单个心跳轮转检查(邮件、日历、任务对账、git 状态),根据每项的逾期程度决定优先级,替代多个独立 cron job。
11.2 Cron Jobs(精确定时任务)
使用 5-field cron 表达式 + timezone 支持,在精确时间触发。
openclaw cron add \
--name "Morning briefing" \
--cron "0 7 * * *" \
--tz "America/New_York" \
--session isolated \
--message "Generate today's briefing..." \
--model opus \
--announce
Session 类型:
isolated:干净 context,无历史记录;支持 model/thinking 覆盖;直接 announce 摘要main:整合到现有 session 历史;system events 在下次心跳时投递
One-shot Reminder(--at):
openclaw cron add \
--name "Meeting reminder" \
--at "20m" \
--session main \
--system-event "Reminder: standup in 10 minutes." \
--wake now \
--delete-after-run
11.3 系统事件队列
Cron(main session)通过 system events 集成——事件排队等待下次心跳投递,而非触发独立 run。这保持了 main session 的上下文连贯性。
11.4 成本对比
| 方面 | Heartbeat | Cron (Isolated) |
|---|---|---|
| 时间精度 | 近似间隔(~30m) | 精确时间戳 |
| 历史 | 共享 session 历史 | 每次全新 |
| 输出 | 有条件(HEARTBEAT_OK 时无输出) | 默认 announce 摘要 |
| Token 成本 | 单次 batched turn | 每 job 完整 agent turn |
12. Canvas / A2UI
12.1 技术栈
Canvas 是 Gateway 直接服务的动态 Web 界面。通过 WebSocket 推送 UI 更新。
A2UI(Agent-to-UI)是开源格式,针对 agent 生成的可更新 UI 优化。当前版本 v0.8(Public Preview)。
渲染方式:
- macOS:WKWebView(原生 WebKit)
- iOS:SwiftUI 嵌入 WebView
- Android:WebView
- Web:浏览器标签页
12.2 工作流程
- Agent 调用 canvas update 方法
- Canvas server 接收 HTML,解析 A2UI attributes
- Server 通过 WebSocket 推送到已连接的客户端
- 客户端渲染为交互式界面
源码:src/canvas-host/a2ui/,bundle hash 由 pnpm canvas:a2ui:bundle 生成。
13. Multi-Agent 架构
13.1 Agent 隔离层
| 层 | 隔离方式 |
|---|---|
| Workspace | 每 agent 独立目录 |
| Auth | 每 agent 独立 auth-profiles.json |
| Sessions | Session key 包含 agent ID |
| Tools | Per-agent tool policies |
| Model | Per-agent model 配置 |
13.2 Agent 配置
{
agents: {
defaults: {
workspace: "~/.openclaw/workspace",
model: { primary: "anthropic/claude-sonnet-4-20250514" },
sandbox: { mode: "off" },
queue: { mode: "collect" }
},
list: [
{
id: "work",
workspace: "~/work-workspace",
model: { primary: "openai/gpt-4o" },
sandbox: { mode: "all", workspaceAccess: "ro" }
}
]
}
}
关键函数:
resolveSessionAgentIds(src/agents/agent-scope.ts):session key → agent ID 映射resolveSandboxConfigForAgent(src/agents/sandbox/config.ts):合并沙箱配置resolveDefaultModelForAgent(src/agents/model-selection.ts):合并模型配置
14. 关键设计哲学总结
以下 3 个设计决策最能体现 OpenClaw 的工程取向。
14.1 "No Magic" 哲学
OpenClaw 的设计刻意避免复杂的隐藏状态:
- No max-steps:仓库层无 max-steps,仍受 timeout 等运行时约束
- No plan mode:未内置 plan mode,通常可通过工作区文件外显计划
- No built-in to-do tracking:未内置 to-do tracking
- 文件即配置:行为配置主要通过 Markdown 文件控制,改文件就改行为,不需要碰源码
14.2 "Trust Boundary as Session Key"
Session key 的拓扑结构(如 agent:main:main vs agent:main:telegram:dm:xxx)天然地编码了"谁在说话"和"它从哪里来"。实际权限由 sandbox mode 和工具策略(allow/deny 列表)共同决定,session key 提供的是会话拓扑信息,而非直接授权。这套设计让权限控制有了多层结构,而不需要一个独立的中心化 ACL 系统。
14.3 "Markdown as LLM-Native Interface"
Markdown 是核心的行为接口,涵盖了大部分跟 LLM 直接交互的配置:
AGENTS.md:操作指令SOUL.md:人格TOOLS.md:工具指南SKILL.md:技能定义HEARTBEAT.md:心跳检查清单MEMORY.md:长期记忆HOOK.md:Hook 文档
系统级配置(并发、沙箱、工具策略等)走 openclaw.json,系统提示词也包含代码层与配置层生成的内容。但 Markdown 的优势在于 LLM 天然擅长读写它,用它做行为配置比 JSON 或 YAML 对 Agent 更友好。
14.4 Lane Queue 的精巧
纯 TypeScript + Promise 实现的并发控制,没有 Redis,没有 RabbitMQ,没有 Worker Threads。通过 lane-aware FIFO 就解决了多 session 并发问题。这是工程品味的体现——能用简单方案解决的问题,不引入外部依赖。
14.5 关于 Memory Flush 和 Markdown 注入
OpenClaw 在 context window 快满时,会先触发一个 silent turn 让 agent 把可持久信息写入 memory 文件,然后再压缩。这个「先存档再遗忘」的思路值得了解,但需要说明:这不是 OpenClaw 的独创——Claude Code 和 Codex 都采用了类似的压缩前保存机制,这更像是行业趋同的工程实践。
同样,Markdown 文件(AGENTS.md、SOUL.md 等)作为 bootstrap context 一次性注入系统提示词,靠字符数上限截断——这个策略 Claude Code 对 MEMORY.md 的处理方式也基本相同(前 200 行注入,其余按需读取)。Skills 部分 OpenClaw 已经做了渐进式加载(元数据列表 + 按需读取 SKILL.md),与 Claude Code 的 Agent Skills 思路一致。
参考来源
- OpenClaw GitHub Repository
- OpenClaw README
- AGENTS.md (Core System Prompt)
- OpenClaw Architecture, Explained - Paolo Perazzo
- Agent Loop Documentation
- Memory Documentation
- Skills Documentation
- Browser Documentation
- Cron vs Heartbeat Documentation
- Security Documentation
- Command Queue Documentation
- Compaction Documentation
- Agent Runtime Documentation
- DeepWiki: Agent System
- DeepWiki: Skills System
- DeepWiki: Tool Security & Sandboxing
- DeepWiki: Memory Search
- OpenClaw DM Policy Access Control Guide
- OpenClaw Sandboxing Docker Guide
Responses