乐于分享
好东西不私藏

OpenClaw 源码解读(4): 多渠道接入

本文最后更新于2026-03-09,某些文章具有时效性,若有错误或已失效,请在下方留言或联系老夜

OpenClaw 源码解读(4): 多渠道接入

OpenClaw 源码解读(4): 多渠道接入

在上一篇中,我们探讨了 OpenClaw 的“多重宇宙”——通过 Workspace 和路由机制,让 Gateway 知道该把消息交给哪个 Agent 处理。但是,现实世界中,用户发消息的入口千奇百怪:有人爱用 WhatsApp,有人常驻 Telegram,团队协作离不开 Slack,甚至还有 Discord、微信等。

每家平台的 API 协议、鉴权方式、数据结构都完全不同。如果把这些逻辑和 AI 核心代码耦合在一起,整个项目很快就会变成一座难以维护的“屎山”。

今天,我们就来翻一翻 OpenClaw 的源码,看看它是如何通过优雅的通道抽象层(Channels Abstraction)群组调度逻辑,将这 20 多种不同的协议“驯服”成统一收发接口的。


化繁为简的适配器模式

OpenClaw 解决多渠道接入的核心思想非常经典:面向接口编程,底层使用适配器模式(Adapter Pattern)

在源码中,无论底层是 WhatsApp (基于 Baileys 库)、Telegram (基于 grammY 库) 还是 Slack (基于 Bolt 框架),它们在 OpenClaw 看来,统统只是一个实现了 IChannelProvider接口的黑盒。

我们先来看看这个抽象层的核心基类定义:

// src/core/channels/IChannelProvider.ts (源码概念简化版)

exportinterfaceIChannelProvider {
/** 渠道唯一标识 (如 'whatsapp_01', 'telegram_bot') */
channelIdstring;

/** 初始化并连接平台 */
connect(): Promise<void>;

/** 统一格式的发送消息接口 */
sendMessage(tostringcontentstringoptions?: SendOptions): Promise<MessageReceipt>;

/** 注册消息接收的回调函数 */
onMessageReceived(handler(msgNormalizedMessage) =>Promise<void>): void;
}

紧接着,各个平台的适配器只需要实现这个接口。以 Telegram 为例,OpenClaw 会在内部把 Telegram 的专属消息对象映射为全局通用的 NormalizedMessage

// src/packages/channels/telegram/TelegramAdapter.ts (片段)

import { Bot } from'grammy';
import { IChannelProviderNormalizedMessage } from'@openclaw/core';

exportclassTelegramAdapterimplementsIChannelProvider {
privatebotBot;

constructor(publicchannelIdstringtokenstring) {
this.bot = newBot(token);
  }

publicasyncconnect() {
this.bot.start(); // 启动长轮询或 Webhook
  }

publiconMessageReceived(handler: (msg: NormalizedMessage) => Promise<void>) {
this.bot.on('message:text'async (ctx) => {
// 核心动作:将 TG 特有数据「洗」成 OpenClaw 标准格式
conststandardMsgNormalizedMessage = {
id: ctx.message.message_id.toString(),
senderId: ctx.from.id.toString(),
channelIdthis.channelId,
content: ctx.message.text,
isGroup: ctx.chat.type === 'group' || ctx.chat.type === 'supergroup',
rawPayload: ctx.message// 保留原始数据以备高级调用
      };
awaithandler(standardMsg);
    });
  }

// ... sendMessage 实现略
}

这种设计把脏活累活都封在了各个 Adapter 包里。Gateway 的控制平面和 Agent 运行时根本不需要知道当前是在给 WhatsApp 发消息还是给 Slack 发消息,它们只需调用 sendMessage即可。这也是为什么 OpenClaw 能够快速扩展支持 20+ 个渠道的秘诀。


Agent 如何知道该“接话”了?

单聊很简单,收到消息就回复。但在几百人的大群里,如果 Agent 对每一句话都做响应,不仅会迅速耗尽 Token 额度,还会变成彻头彻尾的“复读机群宠”。

因此,对于 Non-main sessions(群组/频道),OpenClaw 设计了非常严谨的门控与追踪机制

@ 提及门控

这是最基础的一层防御。网关在收到群消息时,会首先通过网关拦截器进行判断:这条消息是不是专门说给 Agent 听的?

// src/core/router/MentionGating.ts

exportfunctionshouldProcessGroupMessage(msgNormalizedMessagebotIdentitystring[]): boolean {
const text = msg.content;

// 1. 显式 @提及
const isMentioned = botIdentity.some(id => text.includes(`@${id}`));

// 2. 唤醒词匹配 (比如 "Molty, 帮我查一下...")
const hasWakeWord = botIdentity.some(word => text.toLowerCase().startsWith(word.toLowerCase()));

return isMentioned || hasWakeWord;
}

回复标签追踪

如果群友没有 @ Agent,而是**直接引用(Reply)**了 Agent 之前发的一条消息,Agent 也应该能聪明地接上话茬。

OpenClaw 维护了一个会话上下文缓存。当 Agent 发送消息时,会将消息 ID 存入该群组的活跃上下文池。当接收到新消息时,即使没有 @ 提及,只要新消息的 replyToMessageId命中了 Agent 发过的消息,门控同样会放行。


长消息分块处理机制

用过大模型 API 的朋友都知道,LLM 动辄生成几千字的 Markdown 长文。如果直接把这几千字作为一个整块推送到 WhatsApp 或 Telegram,体验极差(部分平台甚至会直接截断报错)。人类在聊天软件里的阅读习惯是“一条一条看”。

OpenClaw 实现了一个非常巧妙的 Chunking(分块)策略,将大段文本拆解为符合人类呼吸节奏的短句。

// src/core/utils/MessageChunker.ts

exportclassMessageChunker {
/**
   * 将长文本智能切割为消息数组
   */

publicstaticsplitIntoChunks(textstringmaxLengthnumber = 2000): string[] {
constchunksstring[] = [];

// 1. 优先按双换行符(段落)切割
const paragraphs = text.split('\n\n');

let currentChunk = '';

for (const p of paragraphs) {
if ((currentChunk.length + p.length) < maxLength) {
        currentChunk += (currentChunk ? '\n\n' : '') + p;
      } else {
// 如果当前块满了,推入数组,开启新块
        chunks.push(currentChunk);
        currentChunk = p;
      }
    }
if (currentChunk) chunks.push(currentChunk);

return chunks;
  }
}

在实际的发送管道中,OpenClaw 还会在每个 Chunk 之间加入短暂的 delay(比如 1-2 秒的模拟打字停顿),甚至会在某些通道触发 typing...状态,让 Agent 表现得像一个真实的群成员在连续发报。


总结

化繁为简,是架构设计的最高境界。

OpenClaw 通过 IChannelProvider 接口将乱七八糟的平台协议收敛为统一的数据流;通过 Mention Gating 与回复追踪保护了群聊环境下的计算资源与用户体验;最后通过 智能 Chunking还原了拟真的人类交互节奏。

了解了 OpenClaw 是如何处理“文字和对话”后,下一篇,我们将进入一个更令人兴奋的领域。这只叫 OpenClaw 的龙虾不仅会聊天,它还拥有“眼睛”和“手”!老金带你看看 Agent 是如何操作界面的。我们下期见!


【作者介绍】

老金,曾在大厂工作10年,见证了移动互联网的跌宕起伏,现在专注于个人独立开发,追求技术自由。致力于学习和传播 AI 、软件工程和工程管理方面的知识。如果能引起你的共鸣,请关注我的公众号:

【往期热门文章】

如何入门 Agent Skills

Claude 官方给出的常用工作流

告别 AI 单兵作战:Claude Code Agent Teams 实战详解

OpenClaw 源码解读(1): 项目概览

OpenClaw 源码解读(2): Gateway 控制

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » OpenClaw 源码解读(4): 多渠道接入

评论 抢沙发

5 + 9 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮