:Channel 与 Skills——连接 25+ 平台的适配魔法)
OpenClaw 源码剖析四Channel 与 Skills——连接 25 平台的适配魔法写在前面前三篇我们拆完了 OpenClaw 的骨架全局架构、神经中枢Gateway和大脑Agent Loop。今天进入两个最接地气的子系统——Channel和Skills。Channel 解决的问题是如何让同一个 AI 助手同时跑在 Telegram、Discord、微信、飞书、Slack、WhatsApp、iMessage 等 25 个平台上而且消息不串、格式不错、能力不丢Skills 解决的问题是如何让 AI 助手的能力无限扩展而不需要改一行框架代码这两个系统看似独立实则共享同一个设计哲学——适配器模式 插件化架构。理解了它们你就理解了 OpenClaw 为什么能一套框架多个通道无限技能。 文章目录 一、Channel 系统25 平台一套抽象️ 二、三层架构Agent → 抽象层 → 平台实现 三、Dock vs Plugin轻量注册与重量加载 四、消息管道Inbound 与 Outbound 的完整旅程 五、平台能力矩阵不是所有通道都生而平等⚡ 六、Skills 系统AI 的技能树是怎么长的 七、SKILL.md 详解一个技能的完整解剖 八、ClawHub从开发到发布的完整闭环 九、源码导航 十、系列预告 一、Channel 系统25 平台一套抽象1.1 问题的本质让 AI 助手接入一个消息平台不难——写个 Telegram Bot调几个 API半天搞定。难的是接入 25 个平台而且每个平台的 API 风格、消息格式、能力集、速率限制、认证方式都完全不同。如果每个平台都写一套独立的消息处理逻辑代码会变成一个巨大的 if-else 地狱维护成本指数级增长。OpenClaw 的解法是经典的适配器模式Adapter Pattern——定义一套统一的 Channel 抽象接口每个平台实现自己的适配器。上层代码Gateway、Agent只依赖抽象接口不依赖任何平台特定代码。新增一个平台写一个适配器注册到 PluginRegistry完事。1.2 Channel 系统的设计目标目标实现方式平台无关统一的 ChannelPlugin 接口上层代码零平台依赖按需加载Dock 轻量注册 Plugin 懒加载不用的平台不占内存能力声明capabilities 显式声明每个平台支持什么Agent 据此调整行为安全隔离每个 Channel 有独立的 allowlist、mention 规则、DM 策略热插拔通道可以运行时启停不影响其他通道️ 二、三层架构Agent → 抽象层 → 平台实现OpenClaw 的 Channel 系统采用经典的三层架构每一层都有明确的职责边界2.1 顶层Agent / LLM 层这是消息的消费者。Agent Loop 接收到标准化的MsgContext后不关心消息来自哪个平台——它只看到一个统一的对话上下文。同样Agent 生成回复时也不需要知道回复会发到哪个平台——它只输出标准文本由下层负责格式化。这种设计的好处是显而易见的Agent 的代码完全不需要if (platform telegram)这样的分支判断。你换一个平台Agent 的行为完全不变。2.2 中间层Channel 抽象层这是整个系统的翻译官。它定义了三个核心抽象ChannelPlugin 接口每个平台必须实现的标准方法集outbound、security、status 等MsgContext统一的消息上下文封装了文本、媒体、元信息、平台 IDChannelOutboundAdapter出站消息的统一发送接口处理分块、格式化、发送抽象层还负责能力协商——通过capabilities字段每个平台声明自己支持什么DM、群组、线程、反应、图片、音频、文档、投票、流式输出。Agent 在生成回复时会参考这些能力来决定输出格式。比如如果平台不支持流式输出Agent 就不会尝试逐 token 推送。2.3 底层平台实现层每个平台一个独立模块实现 ChannelPlugin 接口。这是唯一需要处理平台特定逻辑的地方——Telegram 用 grammY、Discord 用 discord.js、WhatsApp 用 Baileys、Slack 用 Bolt SDK、iMessage 用 BlueBubbles、Signal 用 signal-cli、飞书用 WebSocket API。每个平台实现都像一个翻译官——把平台特定的 API 调用翻译成统一的 MsgContext把统一的 SendContext 翻译成平台特定的 API 调用。 三、Dock vs Plugin轻量注册与重量加载这是 OpenClaw Channel 系统中最精妙的设计之一——两级加载策略。3.1 为什么需要两级加载想象一下你有 25 个 Channel 配置但用户只启用了 Telegram 和 Discord。如果启动时就把所有 25 个平台的 SDK 都加载进来不仅浪费内存WhatsApp 的 Baileys 就很重还会拖慢启动速度。OpenClaw 的解法是先注册元信息Dock再按需加载实现Plugin。3.2 Dock轻量注册Docksrc/channels/dock.ts在 Gateway 启动时运行只注册每个通道的元信息// Dock 注册的内容极轻量{id:telegram,label:Telegram,capabilities:{chatTypes:[direct,group],threads:true,reactions:true,...},allowlistFormat:comma-separated,mentionRules:{groupRequireMention:true},threadingDefaults:{enabled:true}}Dock 不加载任何 SDK不建立任何连接。它的唯一目的是让 Gateway 知道有这个通道可用以便在配置界面显示、在路由时查找。类比电话簿里的名字——知道谁在但不拨号。3.3 Plugin重量加载Pluginsrc/channels/plugins/*在通道实际启动时才加载包含完整的 ChannelPlugin 实现// Plugin 实现的内容完整功能interfaceChannelPlugin{meta:{id,label,selectionLabel,docsPath,blurb,aliases};capabilities:{chatTypes,media,threads,reactions};config:{listAccountIds,resolveAccount};outbound:{deliveryMode,sendText,sendMedia};setup?:SetupWizard;// 可选配置向导security?:SecurityPolicy;// 可选安全策略status?:HealthChecker;// 可选健康检查gateway?:GatewayManager;// 可选Gateway 守护进程mentions?:MentionHandler;// 可选提及处理threading?:ThreadingHandler;// 可选线程管理streaming?:StreamingHandler;// 可选流式输出actions?:MessageActions;// 可选按钮/卡片}Plugin 通过 PluginRegistry 注册支持懒加载和缓存// 懒加载 缓存exportasyncfunctionloadChannelPlugin(id:ChannelId){constcachedcache.get(id);if(cached)returncached;// 命中缓存直接返回constentryregistry.channels.find(ee.plugin.idid);if(entry){cache.set(id,entry.plugin);// 缓存供下次使用returnentry.plugin;}returnundefined;}缓存会在 PluginRegistry 变更时自动失效比如热重载确保开发时的体验流畅。 四、消息管道Inbound 与 Outbound 的完整旅程4.1 Inbound平台事件 → Agent每条消息从平台到达 Agent都要经过一条标准化的管道Platform Event → Monitor/Handler → Normalize → Gate → Dispatch → Agent LoopStep 1: Monitor/Handler— 平台特定的事件监听器捕获原始事件Telegram Update、Discord Message Create 等。Step 2: Normalize— 将平台特定的事件格式转换为统一的MsgContext。这是适配器最核心的工作——提取文本内容、解析媒体附件、统一用户 ID 格式、识别消息类型DM/群组/频道。Step 3: Gate— 三道安全门AllowList 检查该用户/群组是否在白名单内Mention 检查群组消息是否 了机器人群组默认需要 才响应Command 检查是否是斜杠命令如/help、/skillStep 4: Dispatch— 通过resolveRoute确定目标 Agent 和 SessionKey然后通过 Lane Queue 串行化投递第二篇讲过的。4.2 OutboundAgent 回复 → 平台Agent 生成回复后出站管道同样标准化Agent Response → resolveTarget → chunk text → format → sendStep 1: resolveTarget— 解析目标地址。每个平台的地址格式不同Telegram 用telegram:chatIdDiscord 用 Snowflake IDWhatsApp 用 E.164 JIDSlack 用 Channel ID。Step 2: chunk text— 将长文本按平台限制分块。Telegram 单条消息上限 4096 字符Discord 2000 字符WhatsApp 65536 字符。分块逻辑会尽量在句子边界切分保持语义完整。Step 3: format— 平台特定的格式化。Telegram 支持 MarkdownV2Discord 支持 MarkdownWhatsApp 支持简单的加粗和斜体Slack 有自己的 mrkdwn 格式。格式化器会做必要的转义和降级。Step 4: send— 调用平台 API 发送。这里有三种投递模式模式说明使用平台direct进程内直接调用 APITelegram、Discord、Slack、Signal、iMessagegateway通过 Gateway 守护进程路由WhatsAppBaileys 在 Gateway 内运行hybrid先 direct失败回退 gateway预留未来使用WhatsApp 使用 gateway 模式是因为 Baileys无头 WhatsApp Web运行在 Gateway 守护进程内出站消息必须通过它路由而不是独立发起 API 调用。 五、平台能力矩阵不是所有通道都生而平等这是 Channel 系统中最容易被忽视、却最影响用户体验的设计——能力声明Capabilities。每个平台支持的功能集差异巨大OpenClaw 通过capabilities字段显式声明这些差异Agent 据此调整行为。5.1 关键能力差异能力影响范围差异示例线程回复是否以线程形式组织Telegram/Discord/Slack/飞书支持WhatsApp/Signal/iMessage 不支持反应用户能否对消息加表情大部分支持iMessage 仅 Tapback有限流式输出Agent 能否逐 token 推送Telegram 支持编辑消息WhatsApp/Signal 不支持投票能否创建投票仅 Discord 和 WhatsApp 原生支持媒体上限文件大小限制飞书 20MB WhatsApp/iMessage 16MB Telegram 5MB5.2 Agent 如何适配能力差异Agent 在生成回复时会检查当前通道的 capabilities不支持线程→ 所有回复以平铺消息发送不使用 reply_to不支持流式→ 等完整回复生成后一次性发送不做逐 token 推送媒体超限→ 自动压缩或转为链接分享不支持投票→ 用文本列表替代原生投票组件这种能力协商的设计确保了 AI 助手在每个平台上的体验都是该平台上的最佳体验而不是最低公分母体验。⚡ 六、Skills 系统AI 的技能树是怎么长的如果说 Channel 是 OpenClaw 的手连接外部世界那 Skills 就是 OpenClaw 的技能决定能做什么。Skills 系统的设计哲学和 Channel 一脉相承——插件化、声明式、按需加载。6.1 什么是 SkillSkill 是一个自包含的能力单元由一个SKILL.md文件和可选的支撑脚本组成。它定义了 AI 助手的一项新能力——可以是搜索网页、“生成图片”、“操作 GitHub”、“发送邮件”、转换文件格式等任何你能想到的事情。关键设计决策Skill 不是代码插件而是提示词插件。SKILL.md 告诉 AI “你能做什么、怎么做”AI 通过已有的工具bash、read_file、write_file 等来执行。这意味着你不需要写复杂的 TypeScript 插件代码只需要写一份清晰的 Markdown 说明文件。6.2 Skill 的三层优先级OpenClaw 的 Skill 加载遵循严格的三层优先级优先级位置说明最高~/.openclaw/skills/用户自定义技能覆盖一切中ClawHub 安装的技能社区技能openclaw skill install安装最低src/skills/OpenClaw 内置 49 个技能如果用户自定义了一个与内置技能同名的 Skill自定义版本会覆盖内置版本。这让用户可以轻松定制 AI 的行为而不需要修改框架代码。6.3 Skill 的生命周期一个 Skill 从创建到被 Agent 使用经历四个阶段1. 发现Discover— Gateway 启动时扫描技能目录读取所有 SKILL.md构建技能索引。技能快照在会话创建时固化——如果你在会话中途添加了新技能需要重启会话才能生效。2. 加载Load— 会话创建时buildSkillsSection()将所有活跃技能的摘要信息拼装到 System Prompt 中。注意这里只加载摘要不加载完整内容以节省 token。3. 触发Trigger— Agent 在推理时根据 System Prompt 中的技能描述决定是否使用某个技能。触发方式有两种斜杠命令用户输入/weather 北京直接触发 weather 技能自然语言用户说北京今天天气怎么样Agent 自主判断应该调用 weather 技能4. 执行Execute— Agent 读取 SKILL.md 的完整内容通过read_file工具按照其中的指令调用支撑脚本或工具。执行在沙箱中进行受 Tool Policy 约束。 七、SKILL.md 详解一个技能的完整解剖一个完整的 SKILL.md 包含以下 Section--- name: notebook-to-docx description: 将 Jupyter Notebook 转换为 Word 文档 trigger: /notebook-to-docx notebook_path --- # Notebook to DOCX 将 .ipynb 文件转换为格式化的 .docx 文档。 ## Features - 保留 Markdown 单元格的格式标题、列表、链接、图片 - 代码单元格带语法高亮 - 输出单元格文本、图片、表格完整保留 - 自动生成目录 ## Usage 当用户要求转换 notebook 时运行以下命令 \\\bash python3 ~/.openclaw/skills/notebook-to-docx/notebook_to_docx.py notebook_path \\\ ## Requirements - Python 3.10 - pip install nbformat python-docx pygments ## Notes - 输出文件默认与输入文件同目录 - 大型 notebook50MB可能需要较长时间7.1 Front Matter元信息---包裹的 YAML 头部定义技能的元信息名称、描述、触发命令。这些信息会被buildSkillsSection()提取并注入 System Prompt让 Agent 知道有这个技能可用。7.2 正文指令Markdown 正文是给 AI 看的操作手册。它告诉 AI什么时候用触发条件用户要求转换 notebook怎么用具体命令运行 Python 脚本依赖什么前置条件Python 3.10、pip 包注意事项边界情况大型文件可能耗时7.3 支撑脚本SKILL.md 可以引用同目录下的脚本文件Python、Shell 等。这些脚本在沙箱中执行受 Tool Policy 约束。脚本负责实际的业务逻辑——调用 API、处理文件、执行计算等。 八、ClawHub从开发到发布的完整闭环ClawHub 是 OpenClaw 的官方技能市场托管了 5700 个社区技能。它提供了从开发到发布的完整闭环8.1 开发流程1. 创建技能目录mkdir -p ~/.openclaw/skills/my-skill 2. 编写 SKILL.md描述技能的功能、用法、依赖 3. 编写支撑脚本实现具体业务逻辑 4. 本地测试重启会话用斜杠命令或自然语言触发8.2 发布流程1. 认证clawhub auth login 2. 发布clawhub publish ~/.openclaw/skills/my-skill 3. 审核社区审核自动 人工 4. 上线其他用户可以搜索和安装8.3 安装流程1. 搜索openclaw skill search weather 2. 安装openclaw skill install weather-forecast 3. 更新openclaw skill update --all 4. 列表openclaw skill list8.4 安全考量ClawHub 的技能是社区贡献的OpenClaw 采取了多层安全措施沙箱隔离所有技能脚本在 Docker 沙箱中执行无法访问宿主机的文件系统Tool Policy技能只能使用 Tool Policy 允许的工具元信息门控SKILL.md 中可以声明需要的权限用户在安装时可以看到社区审核ClawHub 有自动化的安全扫描和人工审核流程用户控制用户可以随时卸载技能也可以覆盖社区技能 九、源码导航Channel 核心文件文件职责src/channels/dock.ts轻量级 Dock 注册定义通道元信息src/channels/plugins/index.tsPluginRegistry管理所有通道插件src/channels/plugins/telegram/Telegram 适配器grammYsrc/channels/plugins/discord/Discord 适配器discord.jssrc/channels/plugins/whatsapp/WhatsApp 适配器Baileyssrc/channels/plugins/slack/Slack 适配器Bolt SDKsrc/channels/plugins/signal/Signal 适配器signal-clisrc/channels/plugins/bluebubbles/iMessage 适配器BlueBubblessrc/channels/plugins/feishu/飞书适配器WebSocket APIsrc/gateway/server-channels.tsChannel 生命周期管理启停/状态Skills 核心文件文件职责src/agents/system-prompt.tsbuildSkillsSection()构建技能提示词src/agents/skills/技能快照、提示词构建src/skills/内置 49 个技能src/plugins/registry.ts插件注册中心含技能注册~/.openclaw/skills/用户自定义技能目录 十、系列预告第五篇也是最后一篇我们将拆解 OpenClaw 的记忆与安全系统核心问题Memory 的分层架构短期/长期/工作记忆是如何设计的MemoryIndexManager 如何用 SQLite sqlite-vec 实现混合 BM25向量检索PRISM 安全层如何实现零 Fork 的运行时安全防护生产部署的最佳实践有哪些关注我不要错过最终篇 总结速查卡Channel 核心概念概念一句话解释三层架构Agent 层消费→ 抽象层翻译→ 平台层实现Dock轻量注册元信息Gateway 启动时加载不占内存Plugin重量加载完整实现通道启动时懒加载缓存复用MsgContext统一消息上下文封装平台差异Capabilities能力声明Agent 据此调整行为三种投递模式direct进程内/ gateway守护进程/ hybrid预留Skills 核心概念概念一句话解释SKILL.md技能的身份证操作手册Markdown 格式提示词插件Skill 不是代码插件而是告诉 AI 怎么用现有工具三层优先级用户自定义 ClawHub 安装 内置四阶段生命周期发现 → 加载 → 触发 → 执行ClawHub官方技能市场5700 社区技能沙箱隔离技能脚本在 Docker 中执行受 Tool Policy 约束一句话总结Channel 用适配器模式抹平了 25 平台的差异Skills 用提示词插件实现了能力的无限扩展。两者共享同一个设计哲学——框架只定义契约具体实现交给插件。这就是 OpenClaw 一套框架多个通道无限技能的魔法所在。参考链接OpenClaw GitHub 仓库OpenClaw Channel 插件开发文档OpenClaw ClawHub 文档Avasdream: Channel Messaging Deep DiveDatacamp: Building Custom OpenClaw Skills