先来聊聊 OpenClaw 里的通道(Channel)概念。简单说,它就是连接不同平台的一种抽象方式——让机器人的消息收发变得统一、干净,不用为每个平台写一堆重复代码。
1. 概念解析
1.1. 通道
所谓通道,就是管理平台的方法类。比如负责处理命令行输入的 CLIChannel、管理 Telegram 会话的 TelegramChannel、以及对接飞书会话的 FeishuChannel。在 OpenClaw 中,每个平台都有自己的通道实现,但它们都继承自同一个抽象基类 Channel:
class Channel(ABC):
@abstractmethod
def receive(self) -> InboundMessage | None: ...
@abstractmethod
def send(self, to: str, text: str, **kwargs: Any) -> bool: ...
核心就是两个方法:receive 负责从平台收取消息,send 负责把回复发回去。不管底层是 HTTP 轮询、WebSocket 还是长连接,对外暴露的接口就这两个,简洁到极致。
1.2. 统一消息格式
为了让所有通道都能处理同一套消息,OpenClaw 定义了一个统一的消息结构 InboundMessage:
@dataclass
class InboundMessage:
text: str # 消息文本
sender_id: str # 发送者ID
channel: str # 来源平台("cli"/"telegram"/"feishu")
account_id: str # Bot账号标识(支持同平台多账号)
peer_id: str # 会话唯一标识(私聊为用户ID,群聊为群ID)
is_group: bool # 是否为群聊
media: list # 附件信息
raw: dict # 平台原始数据(用于调试)
其中几个关键字段:
text:消息内容,就是用户说了什么。sender_id:发送者的唯一标识,比如account_xxx。channel:标明消息来源,是 CLI、Telegram 还是飞书。
有了这个统一结构,后续的消息处理完全不用关心“这条消息是从哪里来的”,只看字段就能干活。
2. 流程设计
加上流程图来看,整个数据流就非常清晰了:
- 通道层各自监听平台:CLIChannel、TelegramChannel、FeishuChannel 分别与各自的平台保持通信和会话。
- 收到消息后统一打包:每条消息都会被包装成
InboundMessage格式,放入消息队列中。这一步实现了“异构平台 -> 统一协议”的转换。 - 循环消费消息:系统不断从队列里取出消息,交给
run_agent_turn处理。在这里会读取历史消息记录、绑定 tools 方法,然后发给大模型做理解和工具调用。 - 把回复送回对应通道:大模型返回的结果,根据
InboundMessage.channel字段找到正确的 Channel,调用它的send方法发回去。
这样一来,新增一个平台时,只需要实现一个 XXChannel(继承 Channel 并实现 receive/send),其他所有逻辑(消息处理、多轮对话、tool 调用)完全复用——这才是架构设计的价值所在。
