OpenClaw IM 消息通道逻辑架构分析
基于 github.com/openclaw/openclaw 源码与官方文档的技术分析
目录
- 总体架构概览
- Layer 0 — 外部 IM 平台接入
- Layer 1 — Channel Adapter 协议适配层
- Layer 2 — Channel Routing 消息路由层
- Layer 3 — Command Queue 并发控制层
- Layer 4 — Gateway Core 核心控制平面
- Layer 5 — LLM 推理与响应组装
- Layer 6 — Outbound 出站投递
- 完整消息生命周期时序
- 关键设计决策总结
1. 总体架构概览
OpenClaw 的核心设计是单 Gateway 进程统一管理所有 IM 通道,形成一个严格分层的消息处理流水线。
┌─────────────────────────────────────────────────────────────────┐
│ 外部 IM 平台 (Layer 0) │
│ WhatsApp Telegram Slack Discord Signal iMessage Teams ... │
└──────────────────────────┬──────────────────────────────────────┘
│ 平台原生协议事件
▼
┌─────────────────────────────────────────────────────────────────┐
│ Channel Adapter 适配层 (Layer 1) │
│ 消息规范化 · 安全门控 · 媒体处理 │
└──────────────────────────┬──────────────────────────────────────┘
│ 规范化 InboundMessage
▼
┌─────────────────────────────────────────────────────────────────┐
│ Channel Routing 路由层 (Layer 2) │
│ Agent 匹配 · Session Key 生成 · Broadcast │
└──────────────────────────┬──────────────────────────────────────┘
│ (AgentId, SessionKey, Message)
▼
┌─────────────────────────────────────────────────────────────────┐
│ Command Queue 并发层 (Layer 3) │
│ Lane-Aware FIFO · 队列模式 · Typing Indicator │
└──────────────────────────┬──────────────────────────────────────┘
│ 出队执行
▼
┌─────────────────────────────────────────────────────────────────┐
│ Gateway Core 核心平面 (Layer 4) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Agent │ │ Session │ │Streaming │ │ Tool │ │
│ │ Loop │ │ Manager │ │ Engine │ │ Engine │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ws://127.0.0.1:18789 (WS Control Plane) │
└──────────┬────────────────────────────┬────────────────────────┘
│ LLM API 请求 │ 内部 WS
▼ ▼
┌──────────────────┐ ┌───────────────────────┐
│ LLM Providers │ │ Clients / Nodes │
│ (Layer 5) │ │ CLI / macOS / iOS / │
│ Anthropic/OpenAI│ │ Android / WebChat │
└──────────┬───────┘ └───────────────────────┘
│ 响应流
▼
┌─────────────────────────────────────────────────────────────────┐
│ Outbound 出站投递 (Layer 6) │
│ 分块策略 · 流式预览 · 媒体处理 · Retry │
└──────────────────────────┬──────────────────────────────────────┘
│ 回写平台
▼
各 IM 平台 (收到回复)
2. Layer 0 — 外部 IM 平台接入
每个 IM 平台使用不同的底层协议和 SDK 接入,Gateway 对每种平台维护独立的长连接或事件监听。
┌─────────────────────────────────────────────────────────────────────┐
│ IM 平台接入方式一览 │
├─────────────────┬──────────────────┬──────────────────────────────┤
│ 平台 │ 接入库/方式 │ 连接模型 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ WhatsApp │ Baileys │ WhatsApp Web 逆向协议, │
│ │ │ messages.upsert 事件驱动 │
│ │ │ QR 码扫描 → creds.json 持久化 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ Telegram │ grammY │ Bot API 长轮询 / Webhook │
│ │ │ botToken 认证 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ Slack │ Bolt SDK │ Socket Mode (AppToken+BotToken)│
├─────────────────┼──────────────────┼──────────────────────────────┤
│ Discord │ discord.js │ Discord Gateway WebSocket │
│ │ │ Bot Token, 服务器长连接 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ Signal │ signal-cli │ 命令行工具桥接, 隐私优先 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ BlueBubbles │ REST + Webhook │ macOS BlueBubbles Server │
│ (推荐 iMessage) │ │ 服务端 REST API + Webhook 回调 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ iMessage legacy │ imsg CLI │ macOS 本地 Messages 集成 (弃用) │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ MS Teams │ Bot Framework │ Azure Bot Framework HTTP │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ Google Chat │ Chat API │ HTTP Webhook 入站 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ Matrix │ 插件 │ Matrix 协议 (单独安装) │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ WebChat │ Gateway WS 直连 │ 与内部 WS 控制平面共用端口 │
├─────────────────┼──────────────────┼──────────────────────────────┤
│ 扩展通道 │ 插件机制 │ Zalo/LINE/Feishu/Mattermost/ │
│ │ │ Nostr/Twitch/Tlon 等 │
└─────────────────┴──────────────────┴──────────────────────────────┘
关键设计:Gateway 是唯一拥有 WhatsApp Baileys Session 的进程——同一主机只允许一个 Gateway 实例运行。
3. Layer 1 — Channel Adapter 协议适配层
所有平台消息在进入路由层前,必须经过统一的规范化和安全门控流程。
3.1 消息规范化流水线
平台原生事件
│
▼
┌────────────────────────────────────────────────┐
│ Step 1: 过滤无效消息 │
│ · 忽略 Status / Broadcast 频道消息 │
│ · 忽略自身消息回显 (避免循环) │
│ · 过滤 Bot 自身发送的消息 │
└───────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ Step 2: DM Policy 安全门控 │
│ │
│ ┌──────────┐ 首次陌生发送者 │
│ │ pairing │─────────────────→ 发送短码(1h过期)│
│ │ (默认) │ 消息不处理 │
│ └──────────┘ │
│ ┌──────────┐ │
│ │allowlist │──→ 仅白名单 E.164 号码通过 │
│ └──────────┘ │
│ ┌──────────┐ │
│ │ open │──→ 需配合 allowFrom: ["*"] │
│ └──────────┘ │
│ ┌──────────┐ │
│ │ disabled │──→ 完全关闭该通道 │
│ └──────────┘ │
└───────────────────┬────────────────────────────┘
│ 通过门控
▼
┌────────────────────────────────────────────────┐
│ Step 3: 构造规范化 InboundMessage 对象 │
│ │
│ Body : 消息正文 │
│ SenderId : E.164 电话号码 / 用户ID │
│ ChatId : DM JID / 群组 JID │
│ Channel : "whatsapp" / "telegram" / ... │
│ AccountId : 多账号标识 │
│ MediaType : text / image / audio / video │
│ Timestamp : Unix 毫秒时间戳 │
└───────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ Step 4: 引用消息展开 │
│ │
│ 原始 Body: "好的" │
│ 展开后: │
│ "好的 │
│ [Replying to +8613812345678 id:ABC123XYZ] │
│ 你昨天说的那个方案 │
│ [/Replying]" │
│ │
│ 同时填充: │
│ ReplyToId = "ABC123XYZ" │
│ ReplyToBody = "你昨天说的那个方案" │
│ ReplyToSender = "+8613812345678" │
└───────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ Step 5: 媒体内容替换 │
│ │
│ 图片 → <media:image> │
│ 视频 → <media:video> │
│ 音频 → <media:audio> │
│ 文件 → <media:document> │
│ 贴纸 → <media:sticker> │
│ │
│ (媒体文件同时下载到临时目录供 Agent 使用) │
└───────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ Step 6: 群消息发送者标识注入 │
│ │
│ DM 消息: 无需注入 │
│ 群组消息: 在 Body 末尾追加 │
│ "[from: 张三 (+8613812345678)]" │
│ │
│ 群历史注入 (未处理的旧消息): │
│ "[Chat messages since your last reply │
│ - for context]" │
│ 当前消息: "[Current message - respond to │
│ this]" │
└────────────────────────────────────────────────┘
3.2 WhatsApp 专项处理
WhatsApp Baileys 事件循环
│
│ messages.upsert
▼
┌────────────────────────────┐
│ Inbox 监听器 │
│ (关闭时分离,防止 │
│ 事件处理器堆积) │
└────────────┬───────────────┘
│
├── status/broadcast? ──→ 丢弃
│
├── 自身消息 + selfChatMode=false? ──→ 丢弃
│
├── 群组 JID? ──→ 群组策略检查
│ └── groupPolicy: open/allowlist/disabled
│
└── DM E.164? ──→ DM Policy 检查
│
└── allowFrom 白名单匹配
│
├── 命中 ──→ 进入规范化流水线
└── 未命中 ──→ pairing 短码响应
3.3 设备信任链 (WS 客户端接入)
新 WS 客户端连接 Gateway
│
▼
┌────────────────────────────────────────────┐
│ connect 帧 (必须是第一帧) │
│ { │
│ role: "client" | "node", │
│ deviceId: "uuid-xxx", │
│ platform: "macos", │
│ deviceFamily: "desktop", │
│ auth: { token: "..." }, │
│ challenge_signature: "sig_v3..." │
│ } │
└──────────────────┬─────────────────────────┘
│
┌──────────┴──────────┐
│ │
▼ ▼
已配对设备 新设备 ID
(存在 device token) (首次连接)
│ │
▼ ▼
验证签名 nonce 需要配对审批
验证 platform/ openclaw pairing
deviceFamily approve <code>
(元数据变更需重配对) │
│ │
└──────────┬──────────┘
│
▼
loopback / tailnet?
├── 是 ──→ 自动审批
└── 否 ──→ 人工审批
│
▼
← hello-ok { health }
连接建立成功
4. Layer 2 — Channel Routing 消息路由层
消息路由决定哪个 Agent 处理该消息,并生成唯一的 Session Key。
4.1 Agent 路由规则 (优先级降序)
收到规范化 InboundMessage
│
▼
┌─────────────────────────────────────────────┐
│ 优先级 1: 精确 peer 匹配 │
│ bindings[].match.peer.kind == "direct" │
│ bindings[].match.peer.id == "+13125550123"│
│ → 命中 → 返回对应 agentId │
└──────────────────┬──────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────┐
│ 优先级 2: Guild 匹配 (Discord) │
│ bindings[].match.guildId == "12345678" │
└──────────────────┬──────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────┐
│ 优先级 3: Team 匹配 (Slack) │
│ bindings[].match.teamId == "T0123ABCD" │
└──────────────────┬──────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────┐
│ 优先级 4: Account 匹配 │
│ bindings[].match.accountId == "work" │
└──────────────────┬──────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────┐
│ 优先级 5: Channel 匹配 │
│ bindings[].match.channel == "whatsapp" │
└──────────────────┬──────────────────────────┘
│ 未命中
▼
┌─────────────────────────────────────────────┐
│ 优先级 6: 默认 Agent │
│ agents.list[].default == true │
│ → 否则取 agents.list[0] │
│ → 否则 fallback "main" │
└──────────────────┬──────────────────────────┘
│
▼
确定 AgentId
4.2 Session Key 生成规则
消息类型
│
├── DM (私信)
│ │
│ ├── dmScope=main (默认)
│ │ └── agent:<agentId>:<mainKey>
│ │ 示例: agent:main:main
│ │ (所有DM共享同一上下文)
│ │
│ ├── dmScope=per-peer
│ │ └── agent:<agentId>:dm:<peerId>
│ │
│ ├── dmScope=per-channel-peer (推荐多用户)
│ │ └── agent:<agentId>:<channel>:dm:<peerId>
│ │ 示例: agent:main:telegram:dm:123456789
│ │
│ └── dmScope=per-account-channel-peer (多账号)
│ └── agent:<agentId>:<channel>:<accountId>:dm:<peerId>
│
├── 群组消息
│ └── agent:<agentId>:<channel>:group:<groupId>
│ 示例: agent:main:whatsapp:group:120363012345@g.us
│
├── Telegram Topic (论坛频道)
│ └── agent:<agentId>:telegram:group:<id>:topic:<threadId>
│
├── Slack/Discord Thread
│ └── agent:<agentId>:<channel>:channel:<id>:thread:<threadId>
│
├── Cron Job
│ └── cron:<job.id>
│
└── Webhook
└── hook:<uuid>
4.3 Broadcast Groups (多 Agent 并行)
同一消息 → 匹配 broadcast 配置
│
▼
┌──────────────────────────────────┐
│ broadcast: │
│ strategy: "parallel" │
│ "+8613812345678": │
│ - "alfred" │
│ - "logger" │
└──────────────────────────────────┘
│
┌───────────┴───────────┐
│ │
▼ ▼
Agent "alfred" Agent "logger"
(独立 Session) (独立 Session)
(独立 Workspace) (独立 Workspace)
│ │
└───────────┬───────────┘
│ 各自独立回复
▼
回写平台
5. Layer 3 — Command Queue 并发控制层
防止多条消息同时触发 Agent 运行产生竞态,同时保证用户体验无感知。
5.1 Lane 并发模型
┌────────────────────────────────────────────────────────────────┐
│ Lane-Aware FIFO Queue │
├────────────────────────────────────────────────────────────────┤
│ │
│ Session Lane (每 session 一个 lane) │
│ ┌─────────────────────────────────────────┐ │
│ │ session:agent:main:main │ 并发上限: 1 │
│ │ [msg_A] → [msg_B] → [msg_C] (串行) │ │
│ └─────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────┐ │
│ │ session:agent:main:telegram:dm:123 │ 并发上限: 1 │
│ │ [msg_X] │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ▼ 出队后进入 │
│ Global Lane (跨 session 并行控制) │
│ ┌─────────────────────────────────────────┐ │
│ │ main lane │ 并发上限: 4 │
│ │ ├── run_A (session:main) │ │
│ │ ├── run_X (session:tg:dm:123) │ │
│ │ ├── run_Y (session:wa:group:xxx) │ │
│ │ └── (等待槽位...) │ │
│ └─────────────────────────────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ subagent lane │ │ cron lane │ │
│ │ 并发上限: 8 │ │ 独立运行 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘
5.2 队列模式 (Queue Mode)
新消息到达,当前 session 有正在运行的 Agent
│
┌────────┴────────┐
│ 队列模式配置 │
└────────┬────────┘
│
┌───────────┼───────────┬───────────┐
│ │ │ │
▼ ▼ ▼ ▼
collect steer followup steer-backlog
(默认)
│ │ │ │
合并所有 立即注入 等当前结束 立即注入
待处理消息 当前运行 后排队运行 + 保留
为单次运行 (取消待执 (保证顺序) followup
行工具调用) 副本
│
▼
debounceMs: 1000ms (防止连续消息各触发一次)
cap: 20 (队列上限)
drop: "summarize" (溢出时压缩为摘要)
5.3 Typing Indicator 即时性保证
消息入队 (Agent 还未开始处理)
│
├──→ 立即发送 Typing Indicator ← 用户无感知等待
│ (各平台: 正在输入...)
│
└──→ 等待队列 drain → Agent 开始运行
6. Layer 4 — Gateway Core 核心控制平面
Gateway 是整个系统的大脑,监听 ws://127.0.0.1:18789。
6.1 WebSocket 控制平面协议
┌──────────────────────────────────────────────────────────────┐
│ Gateway WebSocket 协议 (JSON over WS) │
├──────────────────────────────────────────────────────────────┤
│ │
│ 握手阶段: │
│ Client → { type: "connect", role, deviceId, auth } │
│ Gateway ← { type: "hello-ok", health: {...} } │
│ │
│ 请求/响应 (RPC): │
│ Client → { type: "req", id: "123", method: "agent", │
│ params: { message, sessionKey, ... } } │
│ Gateway ← { type: "res", id: "123", ok: true, │
│ payload: { runId, acceptedAt } } │
│ │
│ 服务端推送事件 (单向): │
│ Gateway → { type: "event", event: "agent", │
│ payload: { stream: "assistant", │
│ delta: "..." }, │
│ seq: 42, stateVersion: "v7" } │
│ │
│ 支持的事件类型: │
│ agent - Agent 运行状态与输出流 │
│ chat - 聊天消息 delta / final │
│ presence - 用户在线状态 │
│ health - Gateway 健康状态 │
│ heartbeat - 心跳保活 │
│ cron - 定时任务触发 │
│ │
│ 幂等性: │
│ send / agent 方法必须携带 idempotency key │
│ Gateway 维护短期去重缓存 (防止重试重复执行) │
│ │
└──────────────────────────────────────────────────────────────┘
6.2 Agent Loop (Pi Agent Core)
agent RPC 调用
│
▼
┌──────────────────────────────────────────────────────┐
│ agentCommand 入口 │
│ 1. 验证 params │
│ 2. 解析 sessionKey / sessionId │
│ 3. 持久化 session 元数据 │
│ 4. 立即返回 { runId, acceptedAt } │
└─────────────────────┬────────────────────────────────┘
│ 异步
▼
┌──────────────────────────────────────────────────────┐
│ runEmbeddedPiAgent │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 1. 解析 model + thinking 级别 │ │
│ │ (off/minimal/low/medium/high/xhigh) │ │
│ │ │ │
│ │ 2. 加载 Skills 快照 │ │
│ │ (~/.openclaw/workspace/skills/) │ │
│ │ │ │
│ │ 3. 构建 Pi Session │ │
│ │ (Auth Profile 选择 + Failover 配置) │ │
│ │ │ │
│ │ 4. 订阅 Pi 事件流: │ │
│ │ text_delta → stream: "assistant" │ │
│ │ tool_start → stream: "tool" │ │
│ │ tool_end → stream: "tool" │ │
│ │ lifecycle → stream: "lifecycle" │ │
│ │ │ │
│ │ 5. abort 保护: │ │
│ │ 超时 600s → AbortSignal 触发 │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
6.3 Session Manager (状态持久化)
Session 存储结构:
~/.openclaw/agents/<agentId>/
sessions/
sessions.json ← Session 索引 (key → metadata)
<SessionId>.jsonl ← 完整对话 Transcript
<SessionId>.jsonl.bak ← 备份
sessions.json 结构:
{
"agent:main:main": {
"sessionId": "sess_abc123",
"updatedAt": "2025-03-06T10:00:00Z",
"inputTokens": 12500,
"outputTokens": 3200,
"contextTokens": 15700,
"channel": "whatsapp",
"origin": {
"label": "张三的对话",
"provider": "whatsapp",
"from": "+8613812345678"
}
}
}
Session 生命周期管理:
┌──────────────────────────────────────────────┐
│ 重置策略 │
│ daily: 每天 04:00 (Gateway 所在主机本地时间) │
│ idle: idleMinutes 滑动窗口 │
│ 先触发者优先 │
│ 手动: /new 或 /reset 命令 │
├──────────────────────────────────────────────┤
│ 维护策略 (enforce 模式) │
│ pruneAfter: 30d (清理过期 Session) │
│ maxEntries: 500 (总数上限) │
│ rotateBytes: 10MB (sessions.json 轮换) │
│ maxDiskBytes: 可选硬限制 │
├──────────────────────────────────────────────┤
│ 上下文剪枝 (LLM 调用前) │
│ 裁剪过旧的 tool result │
│ 不修改 JSONL 历史文件 │
│ Auto-compaction: 上下文过长时自动压缩摘要 │
└──────────────────────────────────────────────┘
6.4 Streaming Engine (分块投递引擎)
LLM 输出流
│
▼
┌──────────────────────────────────────────────────────────┐
│ EmbeddedBlockChunker │
│ │
│ 模型输出: "好的,我来分析一下这个问题..." │
│ ↓ text_delta 事件 │
│ Buffer 累积 → 检查分块条件: │
│ │
│ 低水位 (minChars): buffer < 500字 → 继续累积 │
│ 高水位 (maxChars): buffer > 2000字 → 强制分块 │
│ │
│ 分块偏好 (breakPreference): │
│ paragraph > newline > sentence > whitespace > 硬切 │
│ │
│ 代码块保护: 不在 ``` 内部分块 │
│ 强制分块时关闭再重开 fence │
└──────────────────┬───────────────────────────────────────┘
│ 块输出
▼
┌──────────────────────────────────────────────────────────┐
│ Coalescer (合并防碎片) │
│ 等待 idleMs 空闲间隔 → 合并多个小块 │
│ maxChars 上限 → 超过立即发送 │
│ Slack/Signal/Discord: 默认 minChars=1500 │
└──────────────────┬───────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ humanDelay (可选) │
│ 每个块之间随机延迟 800~2500ms │
│ 模拟人类打字节奏 │
└──────────────────┬───────────────────────────────────────┘
│
▼
出站投递 (Layer 6)
各平台预览流式模式:
┌─────────────┬────────────────────────────────────────────┐
│ 平台 │ streaming 模式 │
├─────────────┼────────────────────────────────────────────┤
│ Telegram │ partial: sendMessage + editMessageText │
│ │ block: 分块 edit │
├─────────────┼────────────────────────────────────────────┤
│ Discord │ partial: send + edit 预览 │
│ │ block: append-style draft │
├─────────────┼────────────────────────────────────────────┤
│ Slack │ partial: native streaming API │
│ │ (chat.startStream / append / stop) │
│ │ progress: 状态预览 → 最终答案 │
└─────────────┴────────────────────────────────────────────┘
6.5 Tool Engine (工具执行)
Agent 决定调用工具
│
▼
┌─────────────────────────────────────────────────┐
│ Plugin Hook: before_tool_call │
│ 可拦截/修改工具参数 │
└──────────────────┬──────────────────────────────┘
│
┌───────────┼───────────┬────────────┐
│ │ │ │
▼ ▼ ▼ ▼
bash/exec browser canvas/A2UI sessions_*
(本地命令) (CDP Chrome) (可视画布) (跨Agent通信)
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────┐
│ Plugin Hook: after_tool_call │
│ 可处理/转换工具结果 │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ tool_result_persist │
│ 结果写入 JSONL transcript 前的最后转换机会 │
└──────────────────┬──────────────────────────────┘
│
▼
工具结果注入对话上下文
→ 继续 Agent Loop
6.6 Retry & Failover
出站 API 请求失败
│
├── HTTP 429 (Rate Limit)
│ └── 读取 retry_after header → 精确等待
│ 指数退避 (有 jitter 防雪崩)
│ 最多 3 次重试
│
├── 网络超时 / 连接重置
│ └── 仅 Telegram 支持重试
│ Discord 仅重试 429
│
├── Markdown 解析错误 (Telegram)
│ └── 降级为纯文本重发 (不重试)
│
└── Model API 失败
└── Model Failover:
Auth Profile 轮换
→ 备用 Provider 切换
→ 备用模型切换
默认配置:
attempts: 3
minDelayMs: 400 (Telegram) / 500 (Discord)
maxDelayMs: 30000
jitter: 0.1 (10%)
7. Layer 5 — LLM 推理与响应组装
7.1 Prompt 构建
┌──────────────────────────────────────────────────────┐
│ System Prompt 组装 │
│ │
│ ① 基础 Prompt │
│ SOUL.md - Agent 人格/价值观 │
│ IDENTITY.md - Agent 身份描述 │
│ AGENTS.md - Agent 行为规范 │
│ │
│ ② Skills Prompt │
│ ~/.openclaw/workspace/skills/<skill>/SKILL.md │
│ (自动发现并注入) │
│ │
│ ③ Bootstrap Context │
│ TOOLS.md - 可用工具说明 │
│ BOOTSTRAP.md - 启动上下文 │
│ USER.md - 用户偏好/信息 │
│ │
│ ④ Session History (JSONL transcript 剪枝后) │
│ [对话历史 - 经过 token 预算控制] │
│ │
│ ⑤ 当前 InboundMessage → user turn │
│ [群聊历史注入 (如有)] │
│ 当前消息 Body │
└──────────────────────────────────────────────────────┘
7.2 响应组装与过滤
Pi Agent Core 输出
│
▼
┌───────────────────────────────────────────────────────┐
│ 响应组装 (Reply Shaping) │
│ │
│ assistant text ─────────────────────────────┐ │
│ reasoning text (可选) ─────────────────────→ │ │
│ tool summaries (verbose模式) ─────────────────→│ │
│ │ │
│ payload[] │
│ │ │
│ 过滤规则: │ │
│ · "NO_REPLY" 令牌 → 静默丢弃 │ │
│ · messaging tool 确认消息 → 去重 │ │
│ · 无可渲染内容 + tool 错误 → fallback 错误回复 │ │
└───────────────────────────────────────────────────────┘
8. Layer 6 — Outbound 出站投递
8.1 各平台分块策略
┌───────────────┬──────────────────────────────────────────────┐
│ 平台 │ 出站策略 │
├───────────────┼──────────────────────────────────────────────┤
│ WhatsApp │ textChunkLimit: 4000字符/条 │
│ │ chunkMode: "length" 或 "newline"(段落分割) │
│ │ 音频: PTT 格式 (OGG/Opus) │
│ │ 图片: 自动压缩为 JPEG + 尺寸限制 │
│ │ 媒体上限: 5MB/条 (agents.defaults.mediaMaxMb) │
│ │ ackReaction: 收到消息立即发送 👀 表情 │
├───────────────┼──────────────────────────────────────────────┤
│ Telegram │ edit-in-place 预览流式 │
│ │ 429 → 读取 retry_after 精确等待 │
│ │ Markdown 失败 → 降级纯文本 │
├───────────────┼──────────────────────────────────────────────┤
│ Slack │ native streaming (chat.startStream) │
│ │ coalesce minChars: 1500 │
│ │ progress 模式: 状态 → 最终答案 │
├───────────────┼──────────────────────────────────────────────┤
│ Discord │ maxLinesPerMessage: 17 (防 UI 截断) │
│ │ send + edit 预览 / append-style block │
│ │ 429 only retry │
├───────────────┼──────────────────────────────────────────────┤
│ Signal │ coalesce minChars: 1500 │
├───────────────┼──────────────────────────────────────────────┤
│ BlueBubbles │ REST API 发送 / 支持 edit/unsend/reactions │
└───────────────┴──────────────────────────────────────────────┘
9. 完整消息生命周期时序
以 WhatsApp 群组 @提及 消息为例:
用户在 WhatsApp 群组发送 "@OpenClaw 帮我查一下天气"
│
│ [T+0ms] Baileys messages.upsert 事件触发
▼
Channel Adapter:
· 解析群组 JID: "120363012345@g.us"
· 检查 groupPolicy: allowlist → 群组在白名单
· 检查 activation: mention → 检测到 @OpenClaw
· 规范化 Body: "@OpenClaw 帮我查一下天气\n[from: 张三 (+8613812345678)]"
│
│ [T+50ms] 路由决策
▼
Channel Routing:
· SessionKey = "agent:main:whatsapp:group:120363012345@g.us"
· AgentId = "main"
│
│ [T+60ms] 入队
▼
Command Queue:
· 消息入 session lane 队列
· 立即发送 WhatsApp "正在输入..." 指示器 ← [用户看到]
· 等待 debounce 1000ms (防多条合并)
│
│ [T+1100ms] 出队执行
▼
Agent Loop:
· 加载 Skills
· 构建 Prompt (System + History + 当前消息)
· 调用 Anthropic Claude API (streaming)
│
│ [T+2000ms] LLM 开始返回 token
▼
Streaming Engine:
· text_delta 持续到来
· Buffer 累积到 minChars (500) → 开始输出
· 分块: "好的,我来查一下天气..."
│
│ [T+2500ms] 第一个块就绪
▼
Outbound:
· WhatsApp 发送第一条消息 ← [用户收到第一条]
· humanDelay: 随机等待 1200ms
│
Agent 继续调用 weather 工具
│
│ [T+5000ms] 工具返回结果
▼
LLM 继续生成最终回答
│
│ [T+6500ms] 最终消息块
▼
Outbound:
· WhatsApp 发送第二条消息 (天气详情) ← [用户收到第二条]
· 停止 Typing Indicator
│
Session Manager:
· 追加对话到 JSONL transcript
· 更新 sessions.json token 计数
· 检查是否需要 Auto-compaction
10. 关键设计决策总结
┌───────────────────────────────────────────────────────────────────┐
│ 核心设计决策 │
├─────────────────────┬─────────────────────────────────────────────┤
│ 决策 │ 理由 │
├─────────────────────┼─────────────────────────────────────────────┤
│ 单 Gateway 进程 │ 避免多进程竞争 WhatsApp Session; │
│ │ 统一控制面; 简化部署 │
├─────────────────────┼─────────────────────────────────────────────┤
│ WS 控制平面 │ 实时双向通信; 支持事件推送; │
│ (内部通信) │ 与 IM 平台协议解耦 │
├─────────────────────┼─────────────────────────────────────────────┤
│ Session Key 隔离 │ 群组/DM/账号完全独立上下文; │
│ │ 防止用户信息交叉污染 │
├─────────────────────┼─────────────────────────────────────────────┤
│ Lane-Aware Queue │ 同 session 串行防竞态; │
│ │ 跨 session 并行提升吞吐 │
├─────────────────────┼─────────────────────────────────────────────┤
│ Typing Indicator │ 入队即发送, 用户无感知队列等待 │
│ 即时发送 │ │
├─────────────────────┼─────────────────────────────────────────────┤
│ 分层分块策略 │ 适配各平台字符限制; │
│ │ humanDelay 模拟自然对话节奏 │
├─────────────────────┼─────────────────────────────────────────────┤
│ DM Pairing 机制 │ 陌生用户须配对, 防止未授权调用 AI; │
│ │ 保护 API 配额和隐私 │
├─────────────────────┼─────────────────────────────────────────────┤
│ TypeBox Schema │ 协议类型安全; 自动生成 JSON Schema; │
│ 驱动协议 │ Swift 客户端代码自动生成 │
├─────────────────────┼─────────────────────────────────────────────┤
│ 幂等性键 │ 网络重试不产生重复消息; │
│ │ 服务端短期去重缓存兜底 │
└─────────────────────┴─────────────────────────────────────────────┘
数据来源: github.com/openclaw/openclaw + docs.openclaw.ai

浙公网安备 33010602011771号