OpenClaw 是怎么工作的?一条消息的旅程讲清楚
如果你把 AI 助手跑在自己的设备上,再接进 Telegram、WhatsApp、Discord 这些入口,你很快会撞上一个事实:
难点往往不在"它会不会答",而在"它会不会把系统搞乱"。多条消息同时涌进来,工具执行有副作用,会话上下文随时可能串——这些问题,光靠提示词是兜不住的。
最近把 OpenClaw 的官方概念文档和源码从头到尾过了一遍,最大的感受只有一句话:
OpenClaw 把 Agent 当成基础设施在做。队列、会话边界、工具权限、持久化,每一层都是显式的工程机制,不是靠提示词"暗示"模型去遵守。
今天我们来聊聊这个问题:OpenClaw 到底是怎么跑起来的,以及它靠哪些"工程护栏"让系统不乱。
对架构和原理有兴趣可以看下之前的文章: 深度拆解 Clawdbot(OpenClaw)架构与实现
太长不看版(7 条结论)
-
• OpenClaw 的基本链路很清晰:通道接入 → Gateway(鉴权/路由)→ 命令队列 → Agent Loop → 模型 Provider → 回写通道。
-
• 官方把系统拆成两块:Gateway 负责接入与调度,Agent 负责思考与执行,边界清楚,扩展渠道不会把核心跑偏。
-
• "不乱"的关键在于:并发默认按会话串行,再在全局层面做可控并行,而不是到处
async/await。 -
• 命令队列不只是排队:它定义了新消息如何进入正在运行的会话,并提供
collect/steer/followup这种可解释的策略。 -
• 会话键是双重边界:既是上下文边界,也是权限边界;多人 DM 不隔离就会出现隐私串台。
-
• 工具与上下文必须被治理:沙箱/允许列表、compaction/pruning、技能按需注入,本质是在控制"副作用"和"模型能看到什么"。
-
• 模型故障不是终点:认证配置文件轮换 + 模型回退链 + 指数退避冷却,让系统在密钥失效或限速时自动切换。
先建一个直觉:工单调度中心
在往下拆细节之前,先建一个直觉。
想象一个工单调度中心。你的每条消息就是一张工单,可能来自 Telegram,也可能来自 Discord 或 WebChat。Gateway 像派单台,做鉴权、决定这张工单归属哪个会话、什么时候处理、最后把结果送回原入口。Agent Runtime 像执行单元,组装上下文、问模型、调工具、把过程与结果落盘。模型 Provider 更像外部专家——你咨询它,但状态和副作用必须留在你自己的系统里管住。
这个比喻天然强调两件事:调度和审计。
一旦你把 Agent 当成一条会产生副作用的作业流,而不是一个"聊天窗口",很多工程问题就变得清晰了。
OpenClaw 的组件边界:Gateway / Agent / Provider
官方源码导览文档把端到端链路写成了一句话:
Channel 收到消息 → Gateway 规范化并路由 → 进入按
sessionKey排队的执行通道(lane)→ 触发runEmbeddedPiAgent→ 生成回复(可流式)→ 必要时调用工具(可能需要审批)→ 回写到原渠道。
更工程的说法是:OpenClaw 是一个消息驱动的 Agent 运行时。它把复杂度收敛到几块稳定的边界里:
-
• Channels(通道):负责把不同平台的消息接进来,并把回复发回去。支持 WhatsApp(通过 Baileys)、Telegram(通过 grammY)、Slack、Discord、Signal、iMessage、WebChat。
-
• Gateway(网关):接入与调度中心。做鉴权/配对、路由、会话解析、队列与并发控制。它是一个长期运行的守护进程,在默认
127.0.0.1:18789上暴露类型化的 WebSocket API。 -
• Agent Runtime(智能体运行时):运行一个源自 pi-mono 的嵌入式运行时,组装上下文、调用模型、执行工具、流式输出与持久化。
-
• Provider(模型提供商):Anthropic / OpenAI / Google / 本地模型等。OpenClaw 负责调用与管理(包括认证轮换和故障转移),但模型不拥有你的状态。
图 1:OpenClaw 的高层结构(抽象后)

这张图里最关键的是两条边界:
-
• 通道接入层尽量"无脑",只做标准化与路由,不把"智能体能力"塞进去。
-
• Agent Runtime把"模型推理"与"工具副作用"串成一条可控链路,并把结果落盘。
Gateway 不是"中转站",它是唯一事实源
这一点很多人会踩坑,所以单独拎出来说。
官方文档对 Gateway 的定位非常明确:所有会话状态都由 Gateway 拥有。UI 客户端——不管是 macOS 应用还是 WebChat——必须向 Gateway 查询会话列表和 token 计数,而不是自己去读本地文件。换句话说,只要你把网关部署到远端,你关心的会话和状态就一定在那台网关主机上。
几个容易被忽略但很关键的事实:
-
• 每台主机一个 Gateway:它是唯一打开 WhatsApp 会话(Baileys)的位置。
-
• 控制台与 WS 复用同一端口:默认
http://127.0.0.1:18789/。 -
• Canvas 单独起服务:默认端口
18793,把"画布/UI 能力"从网关主端口拆出来。 -
• 远程访问不是"暴露端口":官方推荐 SSH 隧道或 Tailscale,Gateway 只监听本机。
工程上你可以把它拆成两层"平面"来理解:
-
• 控制面(Control plane):建立连接、鉴权、调用方法、订阅事件流。第一帧必须是
connect,握手后才允许调用方法;有副作用的方法(比如send、agent)需要幂等键,便于安全重试。 -
• 数据面(Data plane):承载真实的消息路由、会话状态、队列与运行时事件流。UI 看到的会话列表与 token 计数来自 Gateway 的存储字段(
inputTokens/outputTokens/contextTokens),而不是客户端自己解析 JSONL 去"纠错"。
Gateway 的连接生命周期在架构文档里写得很直观:

连接失败或非 JSON 的第一帧直接硬关闭。如果设置了 OPENCLAW_GATEWAY_TOKEN,connect.params.auth.token 必须匹配,否则关闭。事件不会重放,客户端必须在出现间隙时刷新。
一条消息从进来到出去,到底经历了什么
理解了组件边界之后,下一个问题就很自然了:一条消息从用户嘴里说出来,到最后回复出去,中间到底经历了什么?
如果你要做工程化复盘,把它拆成 4 个问题就够了:
-
1. 这条消息属于哪个会话?
-
2. 这次运行要读哪些上下文?
-
3. 工具怎么执行,副作用怎么约束?
-
4. 这次运行的结果怎么持久化,便于追溯与恢复?
这些问题在官方文档里都有对应的"权威落点":
-
• 会话键怎么构建、DM 怎么隔离、JSONL 落在哪里:看「会话管理」。
-
• 入站消息怎么进队列、为什么默认
collect、怎么steer:看「命令队列」。 -
• 一次运行有哪些生命周期事件、
agent.wait的等待语义:看「智能体循环」。
Agent Loop:系统到底跑到了哪一步
很多团队做 Agent 时,真正让人抓狂的不是"模型不会想",而是"系统不知道自己跑到了哪一步"。出了问题你连 debug 的抓手都没有。
OpenClaw 把一次运行画成事件链,出了问题就沿着 runId 查。官方智能体循环文档对此的定义是:接收 → 上下文组装 → 模型推理 → 工具执行 → 流式回复 → 持久化,称之为"将消息转化为操作和最终回复的权威路径"。
图 2:一次运行的交互时序(简化)

在源码层面,这条链路的关键函数是 runEmbeddedPiAgent,它通过每会话 + 全局队列序列化运行,解析模型与认证配置,构建 pi 会话,订阅事件并流式传输 assistant/tool/lifecycle 三类事件。
如果嵌入式循环没有发出生命周期结束/错误事件,Gateway 的 agentCommand 会补齐——生命周期事件(start/end/error)是可靠性的基线,否则你会到处出现"半条回复"或"工具跑完了但 UI 没更新"。
更加具体的分析,可以看昨天的文章: 聊聊 Agent Loop 是如何让 Agent 有了人格的
为什么它不容易乱(1):把并发关进笼子里
很多 Agent 系统的第一个大坑,不是模型不够聪明,而是你以为自己在写"异步 I/O",实际在写"并发状态机"。
OpenClaw 的做法很像传统系统里那句老话:先把并发关进笼子里,再谈性能。
官方命令队列文档说得很直白:
我们通过一个小型进程内队列序列化入站自动回复运行(所有渠道),以防止多个智能体运行发生冲突,同时仍允许跨会话的安全并行。
具体来说,是两层串行化策略:
-
• 同一会话键(session key)只允许一个活跃运行,通过
session:<key>通道实现,避免会话文件、日志、CLI stdin 之类共享资源争用。 -
• 在全局层面,按通道设置可控并行度:未配置的渠道并发默认为 1;
main通道默认为 4,subagent默认为 8(用于后台作业不阻塞入站回复),整体受agents.defaults.maxConcurrent限制。
整个实现是纯 TypeScript + promises,无外部依赖或后台工作线程。
但队列不只是"排队"。更实际的问题是:新消息进来时,正在跑的智能体怎么办? OpenClaw 给了五种模式:
-
•
collect(默认):将短时间内堆进来的多条消息合并成一次后续轮次。如果消息针对不同渠道/线程,它们会单独排空以保留路由。做过群聊 Bot 的人会知道,这个模式能省掉大部分"连续追问炸裂"的问题。 -
•
followup:等当前运行结束后,再跑下一轮。严格"一问一答"。 -
•
steer:把新消息"导向"当前运行,在下一个工具边界处切入(取消待处理的工具调用)。如果未在流式传输中,则回退为 followup。适合你想打断模型继续跑下去的场景。 -
•
steer-backlog:引导当前运行并保留消息用于后续轮次。注意这可能导致流式界面出现类似重复的回复。 -
•
interrupt(旧版):中止该会话的活动运行,然后运行最新消息。
队列还有三个参数,默认值写得很死:
-
•
debounceMs=1000:在开始后续轮次前等待静默期,防止"继续,继续"。 -
•
cap=20:每个会话的最大排队消息数。 -
•
drop=summarize:溢出策略,保留被丢弃消息的简短要点列表,并作为合成的后续提示注入。
更实用的是,队列模式支持按会话覆盖:在聊天中发送 /queue collect debounce:2s cap:25 即可为当前会话单独设定策略,发 /queue default 清除覆盖。
如果你做过客服 Bot 或群聊助手,会立刻知道这件事的价值:策略可解释,行为可预测,用户体验也能配合。
为什么它不容易乱(2):会话键既是上下文边界,也是权限边界
很多系统把 Session 当成一个 ID,一个标识符,仅此而已。但 OpenClaw 的会话管理文档把话说得更重:DM 不隔离会导致用户间隐私串台。
它通过 session.dmScope 来决定 DM 怎么分组,官方提供了四种粒度:
-
•
main(默认):所有 DM 共享主会话,连续性最好,但只适合单用户。 -
•
per-peer:跨渠道按发送者 ID 隔离。 -
•
per-channel-peer:按通道 + 发送者隔离,适合多用户收件箱。 -
•
per-account-channel-peer:多账户场景下进一步隔离(每账户 + 每通道 + 每发送者)。
会话键的映射规则是确定性的。直接聊天折叠为 agent:<agentId>:<mainKey>,群组聊天隔离为 agent:<agentId>:<channel>:group:<id>,Telegram 论坛话题还会在群组 ID 后追加 :topic:<threadId> 做进一步隔离。
跨渠道身份统一也考虑到了:通过 session.identityLinks 可以把带提供商前缀的对等 ID(如 telegram:123、discord:987654)映射到同一个规范身份,让同一个人跨渠道共享 DM 会话。
会话的生命周期管理
会话不是"创建了就一直在",它有明确的重置策略:
-
• 每日重置:默认 Gateway 主机本地时间凌晨 4:00,会话的最后更新早于此时间即为过期。
-
• 空闲重置(可选):
idleMinutes添加滑动空闲窗口。同时配置每日和空闲时,先过期者强制新会话。 -
• 按类型覆盖:
resetByType允许你对dm、group、thread会话设置不同策略。 -
• 手动重置:精确发送
/new或/reset启动新会话,/new <model>还可以同时切换模型。
"可追溯"不是一句口号。会话存储位置在文档里写得很具体:每个智能体都有 sessions.json(索引)和按会话追加写入的 .jsonl 对话记录,默认都落在 ~/.openclaw/agents/<agentId>/sessions/ 下。
为什么它不容易乱(3):执行链条可审计
前面时序图画了大概的流程,这里展开看看 Agent Loop 内部到底做了什么。官方智能体循环文档把一次运行拆得很细:
-
1. Gateway 的
agentRPC 验证参数,解析会话,立即返回{ runId, acceptedAt } -
2.
agentCommand运行智能体:解析模型 + 思考/详细模式默认值、加载 Skills 快照、调用runEmbeddedPiAgent -
3.
runEmbeddedPiAgent:通过每会话 + 全局队列序列化运行、构建 pi 会话、订阅事件并流式传输、强制执行超时 -
4.
subscribeEmbeddedPiSession把 pi-agent-core 事件桥接到 OpenClaw 的三类事件流:工具事件 →stream: "tool",助手增量 →stream: "assistant",生命周期 →stream: "lifecycle"
两个超时默认值,建议直接抄进自己系统的设计稿里:
-
• 网关侧
agent.wait如果不传timeoutMs,默认就是 30 秒(只影响等待,不会把智能体停掉)。 -
• 智能体运行时还有一层更长的总超时(默认 600 秒),由
runEmbeddedPiAgent强制执行。
还有一个值得一提的设计:钩子系统。OpenClaw 提供了两套钩子,让你在不碰核心代码的情况下拦截执行链:
-
• 内部钩子(Gateway 网关钩子):事件驱动脚本,包括
agent:bootstrap(系统提示词最终确定之前,用于添加/删除引导上下文文件)、命令钩子(/new、/reset、/stop)。 -
• 插件钩子:在智能体/工具生命周期中的扩展点,包括
before_agent_start(注入上下文或覆盖系统提示词)、before_tool_call/after_tool_call(拦截工具参数/结果)、message_received/message_sending(入站 + 出站消息钩子)等。
为什么它不容易乱(4):上下文是被设计出来的,不是任由它膨胀
这一点可能是整个系统里最容易被低估的部分。
官方上下文文档把"上下文"定义为 OpenClaw 在一次运行中发送给模型的所有内容——系统提示词、对话历史、工具调用和结果、附件,甚至压缩摘要和修剪产物,全算在里面。
OpenClaw 的做法不是幻想模型能自己管理好上下文,而是主动控制模型能看到什么。具体做了四件事:
第一,技能按需注入。 系统提示词只包含一个紧凑的 Skills 列表(名称 + 描述 + 文件路径),Skill 指令默认不包含在上下文中。模型在需要时才通过 read 加载对应的 SKILL.md。
第二,压缩(compaction)。 当会话接近上下文窗口限制时,OpenClaw 自动将较早的对话总结为一条紧凑的摘要条目,保持近期消息不变。摘要会持久化到 JSONL 历史中。压缩前还会触发一次静默记忆刷写轮次,提醒模型将持久性笔记写入磁盘,避免重要信息被压缩丢失。
第三,会话修剪(pruning)。 在每次 LLM 调用之前,从内存上下文中修剪旧的工具结果,但不会重写 JSONL 历史。修剪分两级:软修剪只保留头部 + 尾部并插入省略标记,硬清除直接替换整个工具结果为占位符。默认保护最后 3 条助手消息涉及的工具结果不被修剪。
第四,向量记忆搜索。 OpenClaw 可以在记忆文件上构建小型向量索引,支持语义查询。更进一步,它实现了混合搜索(BM25 + 向量):向量搜索擅长"这意味着同一件事"的语义匹配,BM25 擅长精确的高信号 token(ID、代码符号、错误字符串),两者加权合并,同时覆盖自然语言查询和"大海捞针"场景。
如果你在做"长期对话 + 工具"的产品,这四件事决定了你能不能跑到第 200 轮。在聊天中发 /context list 可以查看当前上下文的组成,/context detail 能看到每个文件和工具 schema 的大小——排查"为什么模型忘了刚才说的话"时特别有用。
为什么它不容易乱(5):工具权限与沙箱不是"以后再说"的事
你给 Agent 开了工具,就等于给它开了副作用。这件事不能等上线之后再想。官方文档把工具安全拆成三层:
-
1. Sandbox(沙箱):隔离"在哪里跑"——文件系统/网络/进程边界。每个智能体可以有自己的沙箱配置(
mode: "off"/"all"),非主会话可以在~/.openclaw/sandboxes下使用按会话隔离的沙箱工作区。 -
2. Tool policy(工具策略):约束"允许跑什么"——通过
tools.allow/tools.deny设置允许列表和拒绝列表,支持*通配符,拒绝优先。 -
3. Approvals(审批):约束"什么时候需要人确认"——高风险动作(如
rm、sudo)需要显式批准。
配对(pairing)机制也是安全体系的一部分:新设备连接 Gateway 时需要配对批准,本地连接(loopback)可以自动批准,非本地连接必须签名 connect.challenge nonce 并明确批准。Gateway 为后续连接颁发设备令牌。
审计也不是空话。审计日志支持 JSON 格式输出,记录 tool_exec、tool_result、approval_request、security_violation 等事件。出了事能查,查了能解释,这才是生产环境的底线。
工作区:智能体的"家"
官方对工作区的定位很有意思——它叫"智能体的家"。工作区与 ~/.openclaw/(配置、凭证、会话)分开,默认位置是 ~/.openclaw/workspace。
里面每个文件都有明确的职责,不是随便扔的:
|
文件 |
职责 |
加载时机 |
|---|---|---|
AGENTS.md |
操作指南 + 如何使用记忆 |
每个会话开始 |
SOUL.md |
人设、语气与边界 |
每个会话开始 |
USER.md |
用户是谁、如何称呼 |
每个会话开始 |
IDENTITY.md |
智能体的名称/风格/表情 |
引导仪式 |
TOOLS.md |
本地工具和惯例的说明(不控制工具可用性) |
每个会话开始 |
memory/YYYY-MM-DD.md |
每日记忆日志 |
读取今天 + 昨天 |
MEMORY.md
(可选) |
精选的长期记忆 |
仅主私密会话 |
大文件会按 agents.defaults.bootstrapMaxChars(默认 20000 字符)截断后注入。缺失文件会注入一行"文件缺失"标记,不会阻断运行。
有一句话容易被忽略但很重要:工作区是默认 cwd,不等于硬隔离沙箱。 绝对路径仍然可以访问主机上的其他位置,除非你显式启用了沙箱隔离。
这也带来了一个很好的实践路径:把工作区文件当成可审核的文本资产,变更走 review,线上出了问题可以回溯到"当时注入了哪些规则和记忆"。官方直接建议把工作区放入私有 git 仓库做备份——你会发现,这其实是在把"提示词工程"升级成"配置工程"。
模型故障转移:密钥挂了怎么办
这是很多自建 Agent 系统会忽略的一环。API 密钥限速、额度耗尽、提供商临时故障——这些不是"万一",是"迟早"。OpenClaw 的做法是把故障转移拆成两个阶段:
-
1. 认证配置文件轮换:当一个配置文件因速率限制或认证错误失败时,标记冷却(指数退避:1min → 5min → 25min → 1h 上限),自动切换到同提供商的下一个配置文件。OAuth 配置文件优先于 API 密钥,最旧的优先使用。
-
2. 模型回退:如果某个提供商的所有配置文件都失败,按
agents.defaults.model.fallbacks回退链切换到下一个模型。
为了提升缓存命中率,OpenClaw 还做了会话粘性:为每个会话固定所选的认证配置文件,不在每个请求时轮换。固定的配置文件在会话重置或压缩完成时才可能切换。
账单/额度失败(如 "insufficient credits")会被标记为禁用,退避从 5 小时开始,上限 24 小时。
多智能体路由:一个 Gateway,多个"大脑"
OpenClaw 不只能跑单个智能体。一个 Gateway 可以同时托管多个完全隔离的智能体,每个 agentId 拥有独立的工作区、认证配置文件和会话存储——真正的隔离,不是共享上下文然后假装分开。
路由规则是确定性的,最具体的优先:先匹配 peer(精确 DM/群组 ID),再匹配 guildId(Discord)/ teamId(Slack),再匹配渠道 accountId,最后回退到默认智能体。
这打开了很多实际场景:
-
• 用不同的 WhatsApp 号码路由到不同智能体(比如"Home"和"Work"两个人格)
-
• 按渠道分割:WhatsApp 跑 Sonnet 做日常快速回复,Telegram 跑 Opus 做深度工作
-
• 把特定群组绑定到专用智能体,配上更严格的工具策略和沙箱隔离
什么时候值得上这种"工程底盘"
说了这么多,OpenClaw 的架构偏好其实很明确:它更关心"可控、可审计、可恢复",而不是"把吞吐跑到极限"。不是所有场景都需要这套东西,但如果你的场景命中了下面几条,值得认真看看:
|
你的场景 |
典型信号 |
更像 OpenClaw 的解法 |
|---|---|---|
|
个人助理或小团队助手 |
需求多变,工具副作用多,容错比极限性能重要 |
Gateway + 会话隔离 + 队列策略 |
|
多通道接入 |
同一任务会从不同入口涌入 |
通道适配层薄,核心路由与会话统一 |
|
多人 DM 或群聊 |
最怕上下文串台与隐私泄露 |
dmScope
默认隔离 + |
|
工具执行频繁 |
出一次事故就很难解释 |
Sandbox 三层隔离 + 工具 allow/deny + exec 审批 |
|
长期对话 + 大量工具输出 |
上下文窗口容易爆 |
自动压缩 + 会话修剪 + 向量记忆搜索 |
|
多模型 / 多密钥 |
密钥限速或失效是常态 |
认证配置文件轮换 + 模型回退链 + 指数退避 |
|
高并发 API 服务 |
QPS 高、延迟硬指标 |
需要更偏服务端的 worker 架构,Agent Loop 只是一环 |
一个最小的"可抄配置片段"
下面这段只是示意,重点在于 OpenClaw 把关键策略都做成了配置面:
// ~/.openclaw/openclaw.json(示意)
{
messages: {
queue: {
mode: "collect",
debounceMs: 1000,
cap: 20,
drop: "summarize",
},
},
session: {
dmScope: "per-channel-peer",
reset: {
mode: "daily",
atHour: 4,
idleMinutes: 120,
},
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
},
agents: {
defaults: {
model: {
primary: "anthropic/claude-sonnet-4-5",
fallbacks: ["openai/gpt-4.1"],
},
},
},
}
如果你的系统也能把这些"默认行为"写成配置,而不是散落在业务逻辑里,后续你做灰度、做回滚、做排障,都会轻很多。
反推自己的系统:一份可以直接抄的清单
最后整理一份清单。如果你在做自己的 Agent 系统,这些点每条都能写进架构图里:
-
1. 默认每会话串行:先让系统可预测,再谈吞吐。
-
2. 队列策略产品化:
collect/steer/followup加上debounceMs/cap/drop,能减少 80% 的体验争议。 -
3. 会话键即安全边界:多人输入必须默认隔离,跨渠道身份通过
identityLinks统一。 -
4. 事件流统一:把
assistant/tool/lifecycle统一到一条可追踪的 runId 流上。 -
5. 上下文有管道:技能按需加载、压缩持久化、修剪不重写历史、向量 + BM25 混合搜索——这是工程,不是"优化项"。
-
6. 工具副作用可控:Sandbox + Tool policy + Approvals 三层分治,审计日志兜底。
-
7. 模型故障自愈:认证配置文件轮换 + 模型回退链 + 会话粘性 + 指数退避冷却。
-
8. 把工作区当资产:规则、记忆、工具约定可版本化,放私有 git 仓库备份。
只要你进入"多人输入 + 有工具副作用"的场景,就别再用纯 async/await 拼运气了。你需要一个能把并发、会话、权限讲清楚的底座。
希望这篇对你有帮助。
引用链接
[1] https://openclawcn.com
最后
从0到1!大模型(LLM)最全学习路线图,建议收藏!
想入门大模型(LLM)却不知道从哪开始? 我根据最新的技术栈和我自己的经历&理解,帮大家整理了一份LLM学习路线图,涵盖从理论基础到落地应用的全流程!拒绝焦虑,按图索骥~~

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取