源码导览:从 CLI 到 Agent
这是一份“自顶向下”的源码导览:不追求把所有细节一次看完,而是先建立一张可用的定位地图。
你要先记住的 6 个问题
- 程序从哪里启动?(CLI 入口、命令分发)
- Gateway 的“控制面”是什么?(连接、鉴权、方法调用、事件订阅)
- 消息怎么进来?(Channels → 统一入站信封)
- 路由怎么选?(agentId / sessionKey / DM 与群组隔离)
- 回复怎么生成?(agent loop:run → attempt → streaming)
- 工具怎么执行且可控?(sandbox + tool policy + approvals)
当你能把上面 6 个问题串成一条线,你就具备“顺着调用栈读源码”的能力了。
一句话端到端链路
Channel 收到消息 → Gateway 规范化并路由 → 进入按 sessionKey 排队的执行通道(lane)→ 触发 runEmbeddedPiAgent → 生成回复(可流式)→ 必要时调用工具(可能需要审批)→ 回写到原渠道。
对应的概念文档(建议按顺序读):
Gateway 的两层“平面”
1) 控制面(Control plane)
控制面负责“建立连接 + 调用方法 + 订阅事件”:
- 客户端先
connect - 之后可以
call方法(例如chat.send) - 并通过
subscribe接收事件流(例如 chat/agent/presence/tick)
入口位置通常从这里开始理解:
2) 数据面(Data plane)
数据面承载实际消息与运行时状态:
chat.send触发一次 run(非阻塞 ACK),结果通过事件流回传logs.tail用于 Control UI 跟踪文件日志
路由与隔离:为什么不会串线
路由的核心目标是两件事:
- 确定性:从哪个渠道进来,就回到哪个渠道(模型不“选渠道”)
- 隔离性:群组/频道用独立 sessionKey,避免和私信混在一起
你最需要掌握的是:如何从一条入站消息,得到 agentId 与 sessionKey,再映射到 “lane:session:<key>” 的队列语义。
参见:
工具执行:为什么“安全边界”分三层
OpenClaw 把风险拆成三层来管:
- Sandbox:隔离“在哪里跑”(文件系统/网络/进程边界)
- Tool policy:约束“允许跑什么”(允许列表、能力范围)
- Approvals:约束“什么时候需要人确认”(高风险动作、人类门控)
参见:
读源码的“最短路径”(实操)
- 跑一次可观察的对话:
openclaw dashboard(Control UI)或任一渠道收发一条消息。 - 开
openclaw logs --follow,记录一次chat.send的 runId。 - 回到文档按顺序读:TypeBox → Session tool → Agent loop → Queue。
- 需要定位具体实现时,再补:Gateway logging / troubleshooting / security。