openclaw 架构

openclaw gateway

基本

gateway整体架构

渠道

统一的 ChannelProvider 接口集成多个消息平台。

go 复制代码
interface ChannelProvider {

  name: string;

  // 启动通道连接

  start(): Promise<void>;

  stop(): Promise<void>;

  // 发送消息

  sendMessage(params: SendMessageParams): Promise<Result>;

  sendMedia(params: SendMediaParams): Promise<Result>;

  // 订阅事件(消息、状态等)

  on(event: string, handler: Function): void;

  // 查询通道能力

  capabilities(): ChannelCapabilities;

}

interface ChannelCapabilities {

  text: boolean;        // 📝 文本消息

  images: boolean;      // 🖼️ 图片

  videos: boolean;      // 🎥 视频

  audio: boolean;       // 🎵 音频

  documents: boolean;   // 📄 文档

  reactions: boolean;   // ❤️ 反应

  threads: boolean;     // 🧵 线程

  mentions: boolean;    // @ 提及

  formatting: boolean;  // 🎨 Markdown/富文本

}
  • 接口隔离原则: ChannelProvider 定义统一接口,各平台实现具体逻辑,确保代码的可维护性和可扩展性。
  • 能力查询机制: 通过 ChannelCapabilities 动态查询通道支持的功能,避免硬编码判断。
  • 事件驱动模式: 使用 on(event, handler) 订阅消息、媒体、在线状态等事件,解耦事件处理逻辑。
  • 异步操作模式: 所有核心方法返回 Promise,支持异步操作,不阻塞主线程。
  • 依赖注入: 各 Provider 依赖平台特定的库,通过构造函数注入。

规则解析

主流程

ts 复制代码
function startGatewayServer(){
	// 1. 读、校验修正配置
	// 2. 启用插件
	// 3. 鉴权相关
	// 4. 监听线程:管理gateway 的生命周期,监听终止/重启/升级命令和执行他们
	
	// 创建网络对象
	createGatewayRuntimeState()
	
	// 启动渠道管理模块
	// 广播服务
	// 保活程序
	startGatewayMaintenanceTimers()
	
	// 创建一些模块对象
	// 设置 skills 服务器
	// canvas服务器
	// 浏览器控制模块
	// cron 定时任务模块
	// log 对象
	// 配对加入/登录校验等
	
	// 将这些对象绑定到 websocket 接口,在请求到达时调用
	attachGatewayWsHandlers()
	// 配置热更新机制

	//注册安全退出函数
}
ts 复制代码
function startGatewayMaintenanceTimers(){
	// 向连接对象广播 tick 保活
	// 记录健康快照
	// 内存清理(清过期会话等)
	
}

openclaw 启动的守护进程Gateway,本质上是个 rpc 的网关,单一线程,不区分 server 和 agent,由事件驱动 agent 的执行,agent 所需的资源多为全局变量

消息

agent事件event

event 用于实时推流给控制界面

  1. 用于协调网关内部流程(waitForAgentJob、subagent 生命周期、run 清理)。
  2. 观测与调试(日志、监控可消费这些事件)。
ts 复制代码
// 单个事件结构
export type AgentEventStream = "lifecycle" | "tool" | "assistant" | "error" | (string & {});

export type AgentEventPayload = {
	runId: string;
	seq: number;
	stream: AgentEventStream;
	ts: number;
	data: Record<string, unknown>;
	sessionKey?: string;
};

事件运行机制:初始化时往全局对象里添加回调函数,agent 需要发送事件时遍历数组选择触发指定类型的回调

事件类型:

  • 把 agent 事件转成 agent/chat 推给 WS/会话客户端
  • subagent、agent job生命周期监听
  • 流式转发, 把 assistant + lifecycle(end/error) 组合成 chat delta/final 发给前端

rpc 服务

主要服务

初始阶段 连接鉴权
网关相关 健康检查/配置热更新
业务相关 会话管理/聊天/agent 执行/
接入 渠道/设备/浏览器代理/节点配对
工具 工具/插件

服务的注册逻辑

通过配置文件创建句柄对象

由 rpc 管理对象

请求时通过 rpc 路由到对应模块,调用相关的句柄的接口实现功能

对每个模块都注册了关闭接口

http

功能类到 gateway ws 的 rpc 请求

加载的插件合并注册到 rpc 里

探活就绪等走 http单独处理

心跳拷贝的数据:

  • Agent 维度信息:默认 agent、每个 agent 的 heartbeat 配置摘要、session 存储摘要(路径/数量/最近会话)
  • Channel 维度信息:每个 channel/account 的 configured/linked/probe 结果、最后探测时间
  • 统计字段:ts、durationMs、channelOrder、channelLabels 等

意义在于,多渠道请求心跳时,直接返回提前生成好的心跳快照

agent 循环

并发队列

每个会话一个队列,新建一个会话新建一个队列

上下文组装

如果是沙箱隔离运行,创建工作区

基础提示、Skills 提示、引导上下文和每次运行的覆盖构建

压缩

工具

会话管理

memory

gateway 启动时,初始化 memory 对象和环境,放在全局对象中,通过get 和 query 方法获取记忆

记忆写入文件系统,在会话结束时(例如/new)执行压缩

后台线程定期读取文件系统,构件 sqlite 对象,查询时查询 sqlite

hooks

可扩展的事件驱动系统,允许在会话的一些时机做一些事情:

  • 第一次创建时启动引导程序时
  • 用户的每次命令时

插件钩子

  • before_agent_start:在运行开始前注入上下文或覆盖系统提示。
  • agent_end:在完成后检查最终消息列表和运行元数据。
  • before_compaction / after_compaction:观察或注释压缩周期。
  • before_tool_call / after_tool_call:拦截工具参数/结果。
  • tool_result_persist:在工具结果写入会话记录之前同步转换它们。
  • message_received / message_sending / message_sent:入站 + 出站消息钩子。
  • session_start / session_end:会话生命周期边界。
  • gateway_start / gateway_stop:Gateway 网关生命周期事件。

大致分为:入口 → 会话 → Agent推理 → 工具执行 → 记录压缩 → 出站

Webhooks

在事件发生时主动发 HTTP 回调通知"的机制

一个典型场景是,用户传了个链接,数据在链接里

沙箱策略

浏览器、工具执行可以选择是否用沙箱执行

gateway 本身不会被沙箱隔离

插件系统

在 gateway 启动时候,调用每个插件的 run 函数,每个插件的运行、交互姿态都不一样

  • api.registerService({...}) 做常驻后台任务
  • api.registerHttpRoute({...}) 暴露 HTTP endpoint
  • api.registerGatewayMethod(...) 暴露 gateway 方法,hook
  • Tool 插件

famou webagent VS openclaw gateway

我们和 openclaw 的不同在于,我们是在服务端上跑,面向公网服务足量的用户,openclaw 是个人电脑轻量级部署,服务个人,细化差异

openclaw webagent
语言 ts openclaw 起源个人项目,前后端用 ts 统一便于快速开发, 服务端为支持并发和资源利用,使用go
渠道 多 少 简化这部分
鉴权 少量少频 高频多量 单独的登录系统
并发 低 高 消息队列移到 server 层、高频调用组件解耦
用户自定义 高 低 简化这部分
持久化 agent 内写入文件 一个 agent 在 sandbox 里,不能持久化 agent 通过 rpc 上传记忆,server 存储记忆

openclaw 代码质量低的原因

  • 函数是功能的堆叠,没有最小功能原则,主函数 700 行代码,
  • Composition Root 与运行时 Service 边界不清,缺少明确模块协议。
  • 生命周期状态机没有显式建模
  • 没有组织数据,函数入参出参都是一堆变量
  • 变量、函数的定义和使用类似 c 风格,不方便追踪
  • 使用了大量的匿名函数,代码耦合度极高

openclaw gateway

基本

gateway整体架构

Pasted image 20260304111834.png

渠道

统一的 ChannelProvider 接口集成多个消息平台。

go 复制代码
interface ChannelProvider {

name: string;


// 启动通道连接


start(): Promise<void>;


stop(): Promise<void>;


// 发送消息


sendMessage(params: SendMessageParams): Promise<Result>;


sendMedia(params: SendMediaParams): Promise<Result>;


// 订阅事件(消息、状态等)


on(event: string, handler: Function): void;


// 查询通道能力


capabilities(): ChannelCapabilities;


}


interface ChannelCapabilities {


text: boolean;        // 📝 文本消息


images: boolean;      // 🖼️ 图片


videos: boolean;      // 🎥 视频


audio: boolean;       // 🎵 音频


documents: boolean;   // 📄 文档


reactions: boolean;   // ❤️ 反应


threads: boolean;     // 🧵 线程


mentions: boolean;    // @ 提及


formatting: boolean;  // 🎨 Markdown/富文本

`}`
`
`
  • **接口隔离原则**: ChannelProvider 定义统一接口,各平台实现具体逻辑,确保代码的可维护性和可扩展性。
  • **能力查询机制**: 通过 ChannelCapabilities 动态查询通道支持的功能,避免硬编码判断。
  • **事件驱动模式**: 使用 on(event, handler) 订阅消息、媒体、在线状态等事件,解耦事件处理逻辑。
  • **异步操作模式**: 所有核心方法返回 Promise,支持异步操作,不阻塞主线程。
  • **依赖注入**: 各 Provider 依赖平台特定的库,通过构造函数注入。

规则解析

Pasted image 20260304112030.png

主流程

ts 复制代码
function startGatewayServer(){
	// 1. 读、校验修正配置
	// 2. 启用插件
	// 3. 鉴权相关
	// 4. 监听线程:管理gateway 的生命周期,监听终止/重启/升级命令和执行他们

    // 创建网络对象
    createGatewayRuntimeState()

    // 启动渠道管理模块
    // 广播服务
    // 保活程序
    startGatewayMaintenanceTimers()

    // 创建一些模块对象
    // 设置 skills 服务器
    // canvas服务器
    // 浏览器控制模块
    // cron 定时任务模块
    // log 对象
    // 配对加入/登录校验等

    // 将这些对象绑定到 websocket 接口,在请求到达时调用
    attachGatewayWsHandlers()
    // 配置热更新机制

    //注册安全退出函数




}
ts 复制代码
function startGatewayMaintenanceTimers(){
	// 向连接对象广播 tick 保活
	// 记录健康快照
	// 内存清理(清过期会话等)
	
}

openclaw 启动的守护进程Gateway,本质上是个 rpc 的网关,单一线程,不区分 server 和 agent,由事件驱动 agent 的执行,agent 所需的资源多为全局变量

消息

agent事件event

event 用于实时推流给控制界面

  1. 用于协调网关内部流程(waitForAgentJob、subagent 生命周期、run 清理)。
  2. 观测与调试(日志、监控可消费这些事件)。
ts 复制代码
// 单个事件结构
export type AgentEventStream = "lifecycle" | "tool" | "assistant" | "error" | (string & {});
`export type AgentEventPayload = {`
`
runId: string;`
`
seq: number;`
`
stream: AgentEventStream;`
`
ts: number;`
`
data: Record<string, unknown>;`
`
sessionKey?: string;`
`
};`
`
`

事件运行机制:初始化时往全局对象里添加回调函数,agent 需要发送事件时遍历数组选择触发指定类型的回调

事件类型:

  • 把 agent 事件转成 agent/chat 推给 WS/会话客户端
  • subagent、agent job生命周期监听
  • 流式转发, 把 assistant + lifecycle(end/error) 组合成 chat delta/final 发给前端

rpc 服务

主要服务

初始阶段 连接鉴权
网关相关 健康检查/配置热更新
业务相关 会话管理/聊天/agent 执行/
接入 渠道/设备/浏览器代理/节点配对
工具 工具/插件

服务的注册逻辑

通过配置文件创建句柄对象

由 rpc 管理对象

请求时通过 rpc 路由到对应模块,调用相关的句柄的接口实现功能

对每个模块都注册了关闭接口

http

功能类到 gateway ws 的 rpc 请求

加载的插件合并注册到 rpc 里

探活就绪等走 http单独处理

心跳拷贝的数据:

  • Agent 维度信息:默认 agent、每个 agent 的 heartbeat 配置摘要、session 存储摘要(路径/数量/最近会话)
  • Channel 维度信息:每个 channel/account 的 configured/linked/probe 结果、最后探测时间
  • 统计字段:ts、durationMs、channelOrder、channelLabels 等

意义在于,多渠道请求心跳时,直接返回提前生成好的心跳快照

agent 循环

并发队列

每个会话一个队列,新建一个会话新建一个队列
Pasted image 20260305165657.png

上下文组装

如果是沙箱隔离运行,创建工作区

基础提示、Skills 提示、引导上下文和每次运行的覆盖构建

压缩

工具

会话管理

Pasted image 20260305201537.png

memory

gateway 启动时,初始化 memory 对象和环境,放在全局对象中,通过get 和 query 方法获取记忆

记忆写入文件系统,在会话结束时(例如/new)执行压缩

后台线程定期读取文件系统,构件 sqlite 对象,查询时查询 sqlite

hooks

可扩展的事件驱动系统,允许在会话的一些时机做一些事情:

  • 第一次创建时启动引导程序时
  • 用户的每次命令时

插件钩子

  • before_agent_start:在运行开始前注入上下文或覆盖系统提示。
  • agent_end:在完成后检查最终消息列表和运行元数据。
  • before_compaction / after_compaction:观察或注释压缩周期。
  • before_tool_call / after_tool_call:拦截工具参数/结果。
  • tool_result_persist:在工具结果写入会话记录之前同步转换它们。
  • message_received / message_sending / message_sent:入站 + 出站消息钩子。
  • session_start / session_end:会话生命周期边界。
  • gateway_start / gateway_stop:Gateway 网关生命周期事件。

大致分为:入口 → 会话 → Agent推理 → 工具执行 → 记录压缩 → 出站

Webhooks

在事件发生时主动发 HTTP 回调通知"的机制

一个典型场景是,用户传了个链接,数据在链接里

沙箱策略

浏览器、工具执行可以选择是否用沙箱执行

gateway 本身不会被沙箱隔离

插件系统

在 gateway 启动时候,调用每个插件的 run 函数,每个插件的运行、交互姿态都不一样

  • api.registerService({...}) 做常驻后台任务
  • api.registerHttpRoute({...}) 暴露 HTTP endpoint
  • api.registerGatewayMethod(...) 暴露 gateway 方法,hook
  • Tool 插件

famou webagent VS openclaw gateway

我们和 openclaw 的不同在于,我们是在服务端上跑,面向公网服务足量的用户,openclaw 是个人电脑轻量级部署,服务个人,细化差异

openclaw webagent
语言 ts openclaw 起源个人项目,前后端用 ts 统一便于快速开发, 服务端为支持并发和资源利用,使用go
渠道 多 少 简化这部分
鉴权 少量少频 高频多量 单独的登录系统
并发 低 高 消息队列移到 server 层、高频调用组件解耦
用户自定义 高 低 简化这部分
持久化 agent 内写入文件 一个 agent 在 sandbox 里,不能持久化 agent 通过 rpc 上传记忆,server 存储记忆

openclaw 代码质量低的原因

  • 函数是功能的堆叠,没有最小功能原则,主函数 700 行代码,
  • Composition Root 与运行时 Service 边界不清,缺少明确模块协议。
  • 生命周期状态机没有显式建模
  • 没有组织数据,函数入参出参都是一堆变量
  • 变量、函数的定义和使用类似 c 风格,不方便追踪
  • 使用了大量的匿名函数,代码耦合度极高