OpenClaw 消息系统:多平台消息收发深度解析

目录

    • 摘要
    • [一、消息系统架构:消息通道与协议 🏗️](#一、消息系统架构:消息通道与协议 🏗️)
      • [1.1 Gateway 核心架构](#1.1 Gateway 核心架构)
      • [1.2 内置通道与插件通道](#1.2 内置通道与插件通道)
      • [1.3 通道协议适配层](#1.3 通道协议适配层)
    • [二、消息发送机制 📤](#二、消息发送机制 📤)
      • [2.1 message 工具详解](#2.1 message 工具详解)
      • [2.2 发送文本消息](#2.2 发送文本消息)
      • [2.3 发送富媒体消息](#2.3 发送富媒体消息)
      • [2.4 发送带结构的消息](#2.4 发送带结构的消息)
    • [三、消息接收处理 📥](#三、消息接收处理 📥)
      • [3.1 事件监听机制](#3.1 事件监听机制)
      • [3.2 DM 安全策略](#3.2 DM 安全策略)
      • [3.3 群聊消息处理](#3.3 群聊消息处理)
      • [3.4 可见回复模式](#3.4 可见回复模式)
    • [四、富媒体消息处理 🖼️](#四、富媒体消息处理 🖼️)
      • [4.1 入站媒体处理管道](#4.1 入站媒体处理管道)
      • [4.2 媒体模板变量](#4.2 媒体模板变量)
      • [4.3 媒体理解配置](#4.3 媒体理解配置)
    • [五、消息格式转换:跨平台兼容 🔄](#五、消息格式转换:跨平台兼容 🔄)
      • [5.1 格式转换的挑战](#5.1 格式转换的挑战)
      • [5.2 降级策略](#5.2 降级策略)
      • [5.3 平台特性保留](#5.3 平台特性保留)
    • [六、会话管理:私聊与群聊 💬](#六、会话管理:私聊与群聊 💬)
      • [6.1 会话键(Session Key)设计](#6.1 会话键(Session Key)设计)
      • [6.2 多智能体会话隔离](#6.2 多智能体会话隔离)
      • [6.3 绑定路由优先级](#6.3 绑定路由优先级)
      • [6.4 群聊沙箱隔离](#6.4 群聊沙箱隔离)
    • [七、实战案例 1:跨平台消息聚合中心 🌐](#七、实战案例 1:跨平台消息聚合中心 🌐)
      • [7.1 场景描述](#7.1 场景描述)
      • [7.2 架构设计](#7.2 架构设计)
      • [7.3 配置实现](#7.3 配置实现)
    • [八、实战案例 2:消息自动回复系统 🤖](#八、实战案例 2:消息自动回复系统 🤖)
      • [8.1 场景描述](#8.1 场景描述)
      • [8.2 工作流设计](#8.2 工作流设计)
      • [8.3 实现代码](#8.3 实现代码)
    • [九、实战案例 3:富媒体消息推送管道 📊](#九、实战案例 3:富媒体消息推送管道 📊)
      • [9.1 场景描述](#9.1 场景描述)
      • [9.2 架构设计](#9.2 架构设计)
      • [9.3 实现代码](#9.3 实现代码)
      • [9.4 媒体处理细节](#9.4 媒体处理细节)
    • [十、高级话题与最佳实践 🎯](#十、高级话题与最佳实践 🎯)
      • [10.1 Bot 循环防护](#10.1 Bot 循环防护)
      • [10.2 环境房间事件](#10.2 环境房间事件)
      • [10.3 多账号支持](#10.3 多账号支持)
      • [10.4 CLI 消息发送](#10.4 CLI 消息发送)
      • [10.5 安全最佳实践](#10.5 安全最佳实践)
    • [十一、总结与展望 🔭](#十一、总结与展望 🔭)

🔗 官方文档:docs.openclaw.ai | 📂 源码仓库:MIT 开源

摘要

OpenClaw 是一款自托管的多通道 AI 网关,能够将 Discord、Telegram、WhatsApp、飞书、Slack、Signal、iMessage、Microsoft Teams、QQ Bot 等数十个即时通讯平台统一接入,实现跨平台消息的收发与智能处理。本文深入剖析 OpenClaw 消息系统的核心架构,从消息通道与协议、消息发送机制、事件监听与回调、富媒体消息处理、跨平台格式转换、会话管理等维度展开全面解析,并结合三个实战案例------跨平台消息聚合中心、智能自动回复系统、富媒体消息推送管道------展示 OpenClaw 消息系统在生产场景中的工程实践。无论你是刚接触 OpenClaw 的新手,还是正在构建多平台消息集成方案的架构师,本文都将为你提供系统性的参考与可落地的代码示例。读完本文,你将掌握 OpenClaw 消息系统的全貌,能够独立设计并部署一个多平台消息集成方案。


一、消息系统架构:消息通道与协议 🏗️

1.1 Gateway 核心架构

OpenClaw 的核心是一个名为 Gateway 的自托管网关进程。Gateway 运行在你自己的硬件上,作为所有消息平台与 AI 智能体之间的桥梁。它采用事件驱动的架构设计,所有消息的流入与流出都经过 Gateway 的统一路由与处理。
#mermaid-svg-LRN1YSpmjkfUj4IM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LRN1YSpmjkfUj4IM .error-icon{fill:#552222;}#mermaid-svg-LRN1YSpmjkfUj4IM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LRN1YSpmjkfUj4IM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LRN1YSpmjkfUj4IM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LRN1YSpmjkfUj4IM .marker.cross{stroke:#333333;}#mermaid-svg-LRN1YSpmjkfUj4IM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LRN1YSpmjkfUj4IM p{margin:0;}#mermaid-svg-LRN1YSpmjkfUj4IM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM .cluster-label text{fill:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM .cluster-label span{color:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM .cluster-label span p{background-color:transparent;}#mermaid-svg-LRN1YSpmjkfUj4IM .label text,#mermaid-svg-LRN1YSpmjkfUj4IM span{fill:#333;color:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM .node rect,#mermaid-svg-LRN1YSpmjkfUj4IM .node circle,#mermaid-svg-LRN1YSpmjkfUj4IM .node ellipse,#mermaid-svg-LRN1YSpmjkfUj4IM .node polygon,#mermaid-svg-LRN1YSpmjkfUj4IM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LRN1YSpmjkfUj4IM .rough-node .label text,#mermaid-svg-LRN1YSpmjkfUj4IM .node .label text,#mermaid-svg-LRN1YSpmjkfUj4IM .image-shape .label,#mermaid-svg-LRN1YSpmjkfUj4IM .icon-shape .label{text-anchor:middle;}#mermaid-svg-LRN1YSpmjkfUj4IM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LRN1YSpmjkfUj4IM .rough-node .label,#mermaid-svg-LRN1YSpmjkfUj4IM .node .label,#mermaid-svg-LRN1YSpmjkfUj4IM .image-shape .label,#mermaid-svg-LRN1YSpmjkfUj4IM .icon-shape .label{text-align:center;}#mermaid-svg-LRN1YSpmjkfUj4IM .node.clickable{cursor:pointer;}#mermaid-svg-LRN1YSpmjkfUj4IM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LRN1YSpmjkfUj4IM .arrowheadPath{fill:#333333;}#mermaid-svg-LRN1YSpmjkfUj4IM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LRN1YSpmjkfUj4IM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LRN1YSpmjkfUj4IM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LRN1YSpmjkfUj4IM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LRN1YSpmjkfUj4IM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LRN1YSpmjkfUj4IM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LRN1YSpmjkfUj4IM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LRN1YSpmjkfUj4IM .cluster text{fill:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM .cluster span{color:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LRN1YSpmjkfUj4IM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LRN1YSpmjkfUj4IM rect.text{fill:none;stroke-width:0;}#mermaid-svg-LRN1YSpmjkfUj4IM .icon-shape,#mermaid-svg-LRN1YSpmjkfUj4IM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LRN1YSpmjkfUj4IM .icon-shape p,#mermaid-svg-LRN1YSpmjkfUj4IM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LRN1YSpmjkfUj4IM .icon-shape .label rect,#mermaid-svg-LRN1YSpmjkfUj4IM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LRN1YSpmjkfUj4IM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LRN1YSpmjkfUj4IM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LRN1YSpmjkfUj4IM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 智能体
Gateway
消息源
Discord
Telegram
WhatsApp
飞书/Feishu
Slack
Signal
iMessage
WebChat
路由与协议层
会话引擎
消息格式转换器
认证与安全层
Agent: main
Agent: coding
Agent: alerts

从上图可以看出,Gateway 是消息路由的唯一入口。各平台的消息通过各自的通道协议进入 Gateway,经过路由判断、会话管理、格式转换和安全校验后,分发给对应的智能体处理。

1.2 内置通道与插件通道

OpenClaw 将通道分为内置通道插件通道两大类:

分类 通道列表 接入方式
内置通道 Discord、Telegram、WhatsApp、Slack、Signal、iMessage、IRC、WebChat 开箱即用,配置即生效
捆绑插件 飞书、Microsoft Teams、Matrix、QQ Bot、Nostr、Zalo、Twitch、Nextcloud Talk、Synology Chat 无需额外安装,Gateway 加载时自动识别
外部插件 WeChat(微信)、LINE、Voice Call、Yuanbao 需要通过 ClawHub 安装或 npm 集成

这种分层设计的好处是显而易见的:核心通道零配置启动,扩展通道按需加载,既保持了 Gateway 进程本身的轻量性,又不牺牲消息覆盖的灵活性。每个通道都有独立的适配器模块,遵循统一的接口契约,确保新增通道不会影响已有通道的稳定性。如果你需要接入一个 OpenClaw 尚未内置的平台,也可以通过 ClawHub 社区查找第三方插件,或者按照插件开发规范自行编写适配器。

1.3 通道协议适配层

每个通道都有独立的协议适配器,负责将平台特有的消息格式转换为 OpenClaw 内部的统一消息模型。这种适配是双向的------入站消息被标准化为内部格式,出站消息则被还原为目标平台的原始协议。

以 WhatsApp 为例,它通过 Baileys Web 协议与 WhatsApp 服务器通信,而 Telegram 则使用 grammY 库对接 Bot API。不同协议的连接方式、认证机制、消息编码各有差异,但 Gateway 将这些复杂性封装在适配层内部,对上层的智能体完全透明。
AI Agent Gateway Telegram WhatsApp 用户 AI Agent Gateway Telegram WhatsApp 用户 #mermaid-svg-CjIps9ZIYEecveTw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CjIps9ZIYEecveTw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CjIps9ZIYEecveTw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CjIps9ZIYEecveTw .error-icon{fill:#552222;}#mermaid-svg-CjIps9ZIYEecveTw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CjIps9ZIYEecveTw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CjIps9ZIYEecveTw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CjIps9ZIYEecveTw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CjIps9ZIYEecveTw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CjIps9ZIYEecveTw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CjIps9ZIYEecveTw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CjIps9ZIYEecveTw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CjIps9ZIYEecveTw .marker.cross{stroke:#333333;}#mermaid-svg-CjIps9ZIYEecveTw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CjIps9ZIYEecveTw p{margin:0;}#mermaid-svg-CjIps9ZIYEecveTw .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CjIps9ZIYEecveTw text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-CjIps9ZIYEecveTw .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-CjIps9ZIYEecveTw .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-CjIps9ZIYEecveTw .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-CjIps9ZIYEecveTw .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-CjIps9ZIYEecveTw #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-CjIps9ZIYEecveTw .sequenceNumber{fill:white;}#mermaid-svg-CjIps9ZIYEecveTw #sequencenumber{fill:#333;}#mermaid-svg-CjIps9ZIYEecveTw #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-CjIps9ZIYEecveTw .messageText{fill:#333;stroke:none;}#mermaid-svg-CjIps9ZIYEecveTw .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CjIps9ZIYEecveTw .labelText,#mermaid-svg-CjIps9ZIYEecveTw .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-CjIps9ZIYEecveTw .loopText,#mermaid-svg-CjIps9ZIYEecveTw .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-CjIps9ZIYEecveTw .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-CjIps9ZIYEecveTw .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-CjIps9ZIYEecveTw .noteText,#mermaid-svg-CjIps9ZIYEecveTw .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-CjIps9ZIYEecveTw .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CjIps9ZIYEecveTw .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CjIps9ZIYEecveTw .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CjIps9ZIYEecveTw .actorPopupMenu{position:absolute;}#mermaid-svg-CjIps9ZIYEecveTw .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-CjIps9ZIYEecveTw .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CjIps9ZIYEecveTw .actor-man circle,#mermaid-svg-CjIps9ZIYEecveTw line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-CjIps9ZIYEecveTw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 发送消息 "帮我查天气" Baileys协议适配 路由判定 + 会话匹配 标准化消息体 回复 "北京今天晴,25°C" Baileys协议编码 收到回复 发送消息 "帮我查天气" grammY Bot API适配 路由判定 + 会话匹配 标准化消息体 回复 "北京今天晴,25°C" Bot API编码 收到回复

这种协议适配层的设计,使得同一个智能体可以无缝地为多个平台提供服务,而不需要关心底层协议的细节。


二、消息发送机制 📤

2.1 message 工具详解

OpenClaw 的消息发送核心是 message 工具。智能体通过调用该工具向用户发送消息、管理消息状态、执行频道操作。message 工具支持多种操作类型(action),以下是最常用的几个:

Action 功能 典型用途
send 发送消息 向用户或频道发送文本、图片、文件
read 读取消息 拉取聊天记录、获取对话上下文
edit 编辑消息 修正已发送的消息内容
react 添加表情反应 对消息快速回应(👍、✅等)
pin / unpin 置顶/取消置顶 重要消息标记
thread-reply 线程回复 在 Slack/Discord 线程中回复

2.2 发送文本消息

最基本的用法是向指定目标发送文本消息。target 参数决定了消息的接收方,格式因平台而异:

python 复制代码
# 示例:通过 message 工具发送文本消息
# target 格式说明:
#   WhatsApp/Signal: E.164 号码,如 "+8613800138000"
#   Telegram: chat_id 或 @username
#   Discord/Slack: channelId 或 user:ID
#   iMessage: Apple ID 或手机号

message_action = {
    "action": "send",
    "target": "+8613800138000",  # WhatsApp 目标号码
    "message": "你好!这是一条来自 OpenClaw 的测试消息。"
}

上述代码展示了消息发送的核心参数。target 采用 E.164 格式适配 WhatsApp,而对于 Telegram 则需要使用 chat_id。Gateway 会根据当前激活的通道自动选择正确的协议进行投递。

2.3 发送富媒体消息

OpenClaw 支持发送图片、音频、视频、文档等多种媒体类型。媒体可以通过 URL 引用或本地文件路径提供:

python 复制代码
# 示例:发送图片消息
message_image = {
    "action": "send",
    "target": "tg:123456789",  # Telegram 用户
    "message": "这是今天的天气图表 🌤️",
    "media": "https://example.com/weather-chart.png"  # 图片URL
}

# 示例:发送文件消息
message_file = {
    "action": "send",
    "target": "+8613800138000",  # WhatsApp 用户
    "message": "这是你请求的报告",
    "filePath": "/workspace/reports/quarterly-2025.pdf",
    "filename": "2025年Q1季度报告.pdf"
}

# 示例:发送语音消息
message_voice = {
    "action": "send",
    "target": "discord:channel:987654321",  # Discord 频道
    "media": "/workspace/audio/notification.mp3",
    "asVoice": True  # 标记为语音消息
}

每种媒体类型在发送时会经过不同的处理管道。图片会被自动压缩至最大 2048px 边长(WhatsApp 通道),音频会以语音笔记(voice note)模式发送,文档则保留原始文件名并直接投递。媒体处理的最大限制如下:

媒体类型 大小限制 处理方式
图片 50 MB(压缩后) 自动缩放 + JPEG 重压缩
音频/语音 16 MB 语音笔记模式投递
视频 16 MB 原样传递
文档 100 MB 保留文件名,原样投递

2.4 发送带结构的消息

对于支持富文本的平台(如 Discord、Slack、Telegram),OpenClaw 支持通过 presentation 参数发送带按钮、选择器等交互元素的结构化消息:

python 复制代码
# 示例:发送带按钮的交互式消息
message_buttons = {
    "action": "send",
    "target": "discord:channel:987654321",
    "presentation": {
        "title": "任务确认",
        "tone": "info",
        "blocks": [
            {
                "type": "text",
                "text": "你确定要执行此操作吗?"
            },
            {
                "type": "buttons",
                "buttons": [
                    {"label": "✅ 确认", "style": "success", "value": "confirm"},
                    {"label": "❌ 取消", "style": "danger", "value": "cancel"}
                ]
            }
        ]
    }
}

presentationblocks 数组支持 textcontextdividerbuttonsselect 等类型,可以灵活组合出丰富的消息布局。对于不支持富文本的平台,OpenClaw 会自动降级为纯文本格式,确保跨平台兼容性。


三、消息接收处理 📥

3.1 事件监听机制

OpenClaw 采用事件驱动的消息接收模型。当用户在某个平台发送消息时,对应通道的适配器会将消息推送到 Gateway,Gateway 经过一系列处理后将其包装为标准事件分发给智能体。

整个消息接收流程可以用以下状态图描述:
#mermaid-svg-hV2ixWtZnCGAreYt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hV2ixWtZnCGAreYt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hV2ixWtZnCGAreYt .error-icon{fill:#552222;}#mermaid-svg-hV2ixWtZnCGAreYt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hV2ixWtZnCGAreYt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hV2ixWtZnCGAreYt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hV2ixWtZnCGAreYt .marker.cross{stroke:#333333;}#mermaid-svg-hV2ixWtZnCGAreYt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hV2ixWtZnCGAreYt p{margin:0;}#mermaid-svg-hV2ixWtZnCGAreYt defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-hV2ixWtZnCGAreYt g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-hV2ixWtZnCGAreYt g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-hV2ixWtZnCGAreYt g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-hV2ixWtZnCGAreYt g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-hV2ixWtZnCGAreYt g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-hV2ixWtZnCGAreYt .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-hV2ixWtZnCGAreYt .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-hV2ixWtZnCGAreYt .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-hV2ixWtZnCGAreYt .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-hV2ixWtZnCGAreYt .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-hV2ixWtZnCGAreYt .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-hV2ixWtZnCGAreYt .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-hV2ixWtZnCGAreYt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hV2ixWtZnCGAreYt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hV2ixWtZnCGAreYt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hV2ixWtZnCGAreYt .edgeLabel .label text{fill:#333;}#mermaid-svg-hV2ixWtZnCGAreYt .label div .edgeLabel{color:#333;}#mermaid-svg-hV2ixWtZnCGAreYt .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-hV2ixWtZnCGAreYt .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-hV2ixWtZnCGAreYt .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-hV2ixWtZnCGAreYt .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-hV2ixWtZnCGAreYt .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-hV2ixWtZnCGAreYt .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hV2ixWtZnCGAreYt .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hV2ixWtZnCGAreYt #statediagram-barbEnd{fill:#333333;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hV2ixWtZnCGAreYt .cluster-label,#mermaid-svg-hV2ixWtZnCGAreYt .nodeLabel{color:#131300;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-hV2ixWtZnCGAreYt .note-edge{stroke-dasharray:5;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-note text{fill:black;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram-note .nodeLabel{color:black;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagram .edgeLabel{color:red;}#mermaid-svg-hV2ixWtZnCGAreYt #dependencyStart,#mermaid-svg-hV2ixWtZnCGAreYt #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-hV2ixWtZnCGAreYt .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hV2ixWtZnCGAreYt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 平台消息到达
通道适配器解析
DM/群聊策略校验
未授权用户
确定目标Agent
无匹配Binding
查找/创建Session
标准化消息体
图片/音频/视频理解
纯文本直接传递
生成回复
接收
认证
路由
丢弃
会话匹配
格式转换
媒体处理
智能体处理

3.2 DM 安全策略

消息接收的第一道防线是 DM 策略(dmPolicy)。OpenClaw 提供四种 DM 访问控制模式:

  • pairing(默认):未知发送者会收到一次性配对码,需要用户在 Gateway 端确认授权
  • allowlist :仅允许 allowFrom 列表中的发送者
  • open :允许所有入站 DM(需设置 allowFrom: ["*"]
  • disabled:忽略所有 DM

配置示例:

json5 复制代码
{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123456:ABC-DEF",
      dmPolicy: "pairing",    // 默认配对模式
      allowFrom: ["tg:123456789"],  // allowlist 模式下的白名单
    },
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+8613800138000", "+8613900139000"],
    },
  },
}

这段配置展示了如何为不同通道设置不同的 DM 策略。Telegram 使用配对模式(更安全),WhatsApp 使用白名单模式(更便捷)。

3.3 群聊消息处理

群聊消息的处理比 DM 更复杂,需要考虑触发授权上下文可见性两个维度。

触发授权决定了谁可以激活智能体:

json5 复制代码
{
  channels: {
    whatsapp: {
      groupPolicy: "allowlist",  // 群聊策略:allowlist | open | disabled
      groups: {
        "*": { requireMention: true },  // 所有群默认需要 @提及
        "120363xxx@g.us": { requireMention: false },  // 特定群免提及
      },
      groupAllowFrom: ["+8613800138000"],  // 群内允许触发的人
    },
  },
}

上下文可见性则控制智能体能够看到多少群聊上下文信息。默认情况下,OpenClaw 保持"即收即用"的语义,不过滤引用和转发内容。

3.4 可见回复模式

OpenClaw 引入了**可见回复(visibleReplies)**的概念,控制智能体在群聊中的回复行为:

  • automatic(默认):智能体的最终文本回复自动发送到群聊,适合较弱的模型或不需要精确控制回复的场景
  • message_tool :智能体必须显式调用 message(action=send) 才能在群聊中发送可见消息,适合需要精确控制何时发言的场景
json5 复制代码
{
  messages: {
    groupChat: {
      visibleReplies: "message_tool",  // 群聊必须用 message 工具发送
      unmentionedInbound: "room_event",  // 未提及的群消息作为静默上下文
    },
  },
}

message_tool 模式特别适合"常驻群"场景------智能体持续监听群消息但不主动发言,仅在需要时才通过 message 工具输出。这种模式下,未调用 message 工具的回复会被静默丢弃,不会打扰群聊。


四、富媒体消息处理 🖼️

4.1 入站媒体处理管道

当用户发送包含媒体的消息时,OpenClaw 会启动一个完整的媒体处理管道:
#mermaid-svg-8vXKlO0sh01xK0PF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8vXKlO0sh01xK0PF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8vXKlO0sh01xK0PF .error-icon{fill:#552222;}#mermaid-svg-8vXKlO0sh01xK0PF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8vXKlO0sh01xK0PF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8vXKlO0sh01xK0PF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8vXKlO0sh01xK0PF .marker.cross{stroke:#333333;}#mermaid-svg-8vXKlO0sh01xK0PF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8vXKlO0sh01xK0PF p{margin:0;}#mermaid-svg-8vXKlO0sh01xK0PF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8vXKlO0sh01xK0PF .cluster-label text{fill:#333;}#mermaid-svg-8vXKlO0sh01xK0PF .cluster-label span{color:#333;}#mermaid-svg-8vXKlO0sh01xK0PF .cluster-label span p{background-color:transparent;}#mermaid-svg-8vXKlO0sh01xK0PF .label text,#mermaid-svg-8vXKlO0sh01xK0PF span{fill:#333;color:#333;}#mermaid-svg-8vXKlO0sh01xK0PF .node rect,#mermaid-svg-8vXKlO0sh01xK0PF .node circle,#mermaid-svg-8vXKlO0sh01xK0PF .node ellipse,#mermaid-svg-8vXKlO0sh01xK0PF .node polygon,#mermaid-svg-8vXKlO0sh01xK0PF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8vXKlO0sh01xK0PF .rough-node .label text,#mermaid-svg-8vXKlO0sh01xK0PF .node .label text,#mermaid-svg-8vXKlO0sh01xK0PF .image-shape .label,#mermaid-svg-8vXKlO0sh01xK0PF .icon-shape .label{text-anchor:middle;}#mermaid-svg-8vXKlO0sh01xK0PF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8vXKlO0sh01xK0PF .rough-node .label,#mermaid-svg-8vXKlO0sh01xK0PF .node .label,#mermaid-svg-8vXKlO0sh01xK0PF .image-shape .label,#mermaid-svg-8vXKlO0sh01xK0PF .icon-shape .label{text-align:center;}#mermaid-svg-8vXKlO0sh01xK0PF .node.clickable{cursor:pointer;}#mermaid-svg-8vXKlO0sh01xK0PF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8vXKlO0sh01xK0PF .arrowheadPath{fill:#333333;}#mermaid-svg-8vXKlO0sh01xK0PF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8vXKlO0sh01xK0PF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8vXKlO0sh01xK0PF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8vXKlO0sh01xK0PF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8vXKlO0sh01xK0PF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8vXKlO0sh01xK0PF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8vXKlO0sh01xK0PF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8vXKlO0sh01xK0PF .cluster text{fill:#333;}#mermaid-svg-8vXKlO0sh01xK0PF .cluster span{color:#333;}#mermaid-svg-8vXKlO0sh01xK0PF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8vXKlO0sh01xK0PF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8vXKlO0sh01xK0PF rect.text{fill:none;stroke-width:0;}#mermaid-svg-8vXKlO0sh01xK0PF .icon-shape,#mermaid-svg-8vXKlO0sh01xK0PF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8vXKlO0sh01xK0PF .icon-shape p,#mermaid-svg-8vXKlO0sh01xK0PF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8vXKlO0sh01xK0PF .icon-shape .label rect,#mermaid-svg-8vXKlO0sh01xK0PF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8vXKlO0sh01xK0PF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8vXKlO0sh01xK0PF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8vXKlO0sh01xK0PF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 图片
音频
视频
文档
入站媒体消息
下载到临时文件
媒体类型判断
图片理解模型
语音转文字
视频描述
直接传递
注入 Body 描述
模板变量替换
传递给智能体

入站媒体被下载到临时文件后,根据类型进入不同的理解管道。图片会被视觉模型描述,音频会被转写为文字,视频则生成摘要描述。这些理解结果会注入到消息的 Body 字段中,使智能体能够"看到"和"听到"媒体内容。

4.2 媒体模板变量

OpenClaw 为入站媒体提供了便捷的模板变量,方便在命令和工作流中引用:

变量 含义 示例值
{``{MediaUrl}} 入站媒体的伪 URL media://inbound/photo.jpg
{``{MediaPath}} 本地临时文件路径 /tmp/openclaw-media/abc123.jpg
{``{Transcript}} 音频转写文本 "今天天气不错..."

当启用 Docker 沙箱时,MediaPath 会被重写为沙箱内的相对路径(如 media/inbound/photo.jpg),媒体文件会被自动复制到沙箱工作空间中。

4.3 媒体理解配置

默认情况下,OpenClaw 只处理第一个匹配的媒体附件。如果需要处理多个附件,可以配置 tools.media.<capability>.attachments

json5 复制代码
{
  tools: {
    media: {
      image: {
        maxBytes: 10485760,  // 10 MB,图片理解上限
        attachments: 3,       // 最多处理3张图片
      },
      audio: {
        maxBytes: 20971520,  // 20 MB,音频转写上限
        attachments: 1,       // 只处理1条音频
      },
      video: {
        maxBytes: 52428800,  // 50 MB,视频描述上限
        attachments: 1,
      },
    },
  },
}

如果智能体的主要模型已经原生支持视觉能力(如 GPT-4o、Claude Sonnet),OpenClaw 会跳过独立的图片理解步骤,直接将原始图片传递给模型,避免重复处理和潜在的信息损失。


五、消息格式转换:跨平台兼容 🔄

5.1 格式转换的挑战

不同消息平台对富文本的支持差异巨大,这是跨平台消息系统面临的核心挑战之一:

特性 Discord Telegram WhatsApp Slack 飞书
Markdown ✅ 完整 ⚠️ 子集 ❌ 极有限 ✅ 完整 ✅ 完整
按钮
卡片/Embed
表格
线程
反应/表情
文件附件

5.2 降级策略

OpenClaw 采用优雅降级策略处理跨平台格式差异:

  1. Markdown 转换:完整 Markdown 在 WhatsApp 等平台降级为纯文本;表格在 Discord 中转为代码块或列表
  2. 交互元素降级:按钮和选择器在不支持的平台降级为带编号的文本选项
  3. 图片语法转换 :Telegram 通道中,回复里的 Markdown 图片语法 ![alt](url) 会被自动转换为媒体回复
  4. 链接格式适配 :Discord 中多个链接用 <> 包裹以抑制嵌入预览
python 复制代码
# 示例:跨平台消息格式适配器
def adapt_message_for_platform(message_content, target_platform):
    """根据目标平台适配消息格式"""
    
    if target_platform == "whatsapp":
        # WhatsApp 不支持 Markdown,转为纯文本
        adapted = strip_markdown(message_content)
        # 表格转为列表格式
        adapted = table_to_list(adapted)
        # 移除嵌入预览
        adapted = remove_embeds(adapted)
        
    elif target_platform == "telegram":
        # Telegram 支持 Markdown 子集
        adapted = convert_to_telegram_md(message_content)
        # 图片语法转为媒体回复
        adapted = md_image_to_media(adapted)
        
    elif target_platform == "discord":
        # Discord 支持完整 Markdown
        # 多链接抑制嵌入
        adapted = wrap_links_no_embed(message_content)
        
    elif target_platform == "feishu":
        # 飞书支持完整富文本
        adapted = message_content  # 无需转换
        
    return adapted

这段代码展示了一个简化的跨平台消息适配器。实际中 OpenClaw 的格式转换器更复杂,覆盖了 HTML、Markdown、纯文本等多种输入输出格式的双向转换。

5.3 平台特性保留

在降级的同时,OpenClaw 也尽量保留各平台的独有特性。例如:

  • Discord Embed:发送到 Discord 的消息可以利用 Embed 结构展示更丰富的卡片式布局
  • Telegram 内联键盘:在 Telegram 中可以发送带内联键盘的交互式消息
  • WhatsApp 语音笔记:音频文件在 WhatsApp 中自动标记为语音笔记(ptt: true),收件人可以像播放语音消息一样播放
  • 飞书卡片消息:在飞书通道中支持完整的交互式卡片消息

六、会话管理:私聊与群聊 💬

6.1 会话键(Session Key)设计

OpenClaw 的会话管理基于**会话键(Session Key)**机制,不同类型的会话有不同的键格式:

会话类型 会话键格式 说明
私聊(DM) agent:<agentId>:<mainKey> 所有私聊合并到主会话
群聊 agent:<agentId>:<channel>:group:<id> 每个群独立会话
频道 agent:<agentId>:<channel>:channel:<id> 每个频道独立会话
论坛话题 agent:<agentId>:<channel>:group:<id>:topic:<threadId> Telegram 论坛的每个话题独立

私聊会话合并到主会话(main session)是一个关键设计决策------这意味着用户在不同平台上与同一个智能体的私聊共享同一个上下文,实现了真正的跨平台会话连续性。

6.2 多智能体会话隔离

在多智能体模式下,每个智能体拥有完全隔离的会话空间:

json5 复制代码
{
  agents: {
    list: [
      { id: "main", workspace: "~/.openclaw/workspace-main" },
      { id: "coding", workspace: "~/.openclaw/workspace-coding" },
      { id: "alerts", workspace: "~/.openclaw/workspace-alerts" },
    ],
  },
  bindings: [
    { agentId: "main", match: { channel: "whatsapp", accountId: "default" } },
    { agentId: "coding", match: { channel: "discord", accountId: "coding" } },
    { agentId: "alerts", match: { channel: "telegram", accountId: "alerts" } },
  ],
}

每个智能体有独立的工作空间(workspace)、认证配置(auth profiles)和会话存储(sessions),互不干扰。消息通过**绑定(bindings)**规则路由到正确的智能体。

6.3 绑定路由优先级

当消息到达 Gateway 时,绑定匹配按以下优先级进行:
#mermaid-svg-dEusAsx3bZPhb4vO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dEusAsx3bZPhb4vO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dEusAsx3bZPhb4vO .error-icon{fill:#552222;}#mermaid-svg-dEusAsx3bZPhb4vO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dEusAsx3bZPhb4vO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dEusAsx3bZPhb4vO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dEusAsx3bZPhb4vO .marker.cross{stroke:#333333;}#mermaid-svg-dEusAsx3bZPhb4vO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dEusAsx3bZPhb4vO p{margin:0;}#mermaid-svg-dEusAsx3bZPhb4vO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dEusAsx3bZPhb4vO .cluster-label text{fill:#333;}#mermaid-svg-dEusAsx3bZPhb4vO .cluster-label span{color:#333;}#mermaid-svg-dEusAsx3bZPhb4vO .cluster-label span p{background-color:transparent;}#mermaid-svg-dEusAsx3bZPhb4vO .label text,#mermaid-svg-dEusAsx3bZPhb4vO span{fill:#333;color:#333;}#mermaid-svg-dEusAsx3bZPhb4vO .node rect,#mermaid-svg-dEusAsx3bZPhb4vO .node circle,#mermaid-svg-dEusAsx3bZPhb4vO .node ellipse,#mermaid-svg-dEusAsx3bZPhb4vO .node polygon,#mermaid-svg-dEusAsx3bZPhb4vO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dEusAsx3bZPhb4vO .rough-node .label text,#mermaid-svg-dEusAsx3bZPhb4vO .node .label text,#mermaid-svg-dEusAsx3bZPhb4vO .image-shape .label,#mermaid-svg-dEusAsx3bZPhb4vO .icon-shape .label{text-anchor:middle;}#mermaid-svg-dEusAsx3bZPhb4vO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dEusAsx3bZPhb4vO .rough-node .label,#mermaid-svg-dEusAsx3bZPhb4vO .node .label,#mermaid-svg-dEusAsx3bZPhb4vO .image-shape .label,#mermaid-svg-dEusAsx3bZPhb4vO .icon-shape .label{text-align:center;}#mermaid-svg-dEusAsx3bZPhb4vO .node.clickable{cursor:pointer;}#mermaid-svg-dEusAsx3bZPhb4vO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dEusAsx3bZPhb4vO .arrowheadPath{fill:#333333;}#mermaid-svg-dEusAsx3bZPhb4vO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dEusAsx3bZPhb4vO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dEusAsx3bZPhb4vO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dEusAsx3bZPhb4vO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dEusAsx3bZPhb4vO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dEusAsx3bZPhb4vO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dEusAsx3bZPhb4vO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dEusAsx3bZPhb4vO .cluster text{fill:#333;}#mermaid-svg-dEusAsx3bZPhb4vO .cluster span{color:#333;}#mermaid-svg-dEusAsx3bZPhb4vO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dEusAsx3bZPhb4vO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dEusAsx3bZPhb4vO rect.text{fill:none;stroke-width:0;}#mermaid-svg-dEusAsx3bZPhb4vO .icon-shape,#mermaid-svg-dEusAsx3bZPhb4vO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dEusAsx3bZPhb4vO .icon-shape p,#mermaid-svg-dEusAsx3bZPhb4vO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dEusAsx3bZPhb4vO .icon-shape .label rect,#mermaid-svg-dEusAsx3bZPhb4vO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dEusAsx3bZPhb4vO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dEusAsx3bZPhb4vO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dEusAsx3bZPhb4vO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是













入站消息
peer 精确匹配?
路由到对应Agent
parentPeer 线程继承?
guildId + roles 匹配?
guildId 匹配?
teamId 匹配?
accountId 匹配?
accountId: '*' 通配?
默认Agent

这种**最具体优先(most-specific-wins)**的路由策略确保了消息分发的精确性。在同一优先级内出现多个匹配时,配置文件中排在前面的绑定胜出。

6.4 群聊沙箱隔离

一个特别实用的模式是私聊走主机、群聊走沙箱 。通过配置沙箱模式为 non-main,所有群聊会话自动在 Docker 沙箱中执行,而私聊会话保持在主机上运行:

json5 复制代码
{
  agents: {
    defaults: {
      sandbox: {
        mode: "non-main",      // 非主会话使用沙箱
        scope: "session",       // 每个群/频道独立容器
        workspaceAccess: "none", // 沙箱无法访问工作空间
      },
    },
  },
  tools: {
    sandbox: {
      tools: {
        allow: ["group:messaging", "group:sessions"],
        deny: ["group:runtime", "group:fs", "group:ui", "nodes", "cron", "gateway"],
      },
    },
  },
}

这种模式下,群聊用户无法通过消息访问主机的文件系统或运行危险命令,而私聊用户则享有完整的工具访问权限。一个智能体、两种执行姿态,兼顾了便利性与安全性。


七、实战案例 1:跨平台消息聚合中心 🌐

7.1 场景描述

假设你是一个团队的负责人,团队使用 Discord 讨论技术、Telegram 接收告警、WhatsApp 进行日常沟通。你需要一个统一的消息聚合中心,将三个平台的重要消息汇总到一个智能体中处理。

7.2 架构设计

#mermaid-svg-6ddRtAERuBOWhLm0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6ddRtAERuBOWhLm0 .error-icon{fill:#552222;}#mermaid-svg-6ddRtAERuBOWhLm0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6ddRtAERuBOWhLm0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6ddRtAERuBOWhLm0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6ddRtAERuBOWhLm0 .marker.cross{stroke:#333333;}#mermaid-svg-6ddRtAERuBOWhLm0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6ddRtAERuBOWhLm0 p{margin:0;}#mermaid-svg-6ddRtAERuBOWhLm0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 .cluster-label text{fill:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 .cluster-label span{color:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 .cluster-label span p{background-color:transparent;}#mermaid-svg-6ddRtAERuBOWhLm0 .label text,#mermaid-svg-6ddRtAERuBOWhLm0 span{fill:#333;color:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 .node rect,#mermaid-svg-6ddRtAERuBOWhLm0 .node circle,#mermaid-svg-6ddRtAERuBOWhLm0 .node ellipse,#mermaid-svg-6ddRtAERuBOWhLm0 .node polygon,#mermaid-svg-6ddRtAERuBOWhLm0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6ddRtAERuBOWhLm0 .rough-node .label text,#mermaid-svg-6ddRtAERuBOWhLm0 .node .label text,#mermaid-svg-6ddRtAERuBOWhLm0 .image-shape .label,#mermaid-svg-6ddRtAERuBOWhLm0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-6ddRtAERuBOWhLm0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6ddRtAERuBOWhLm0 .rough-node .label,#mermaid-svg-6ddRtAERuBOWhLm0 .node .label,#mermaid-svg-6ddRtAERuBOWhLm0 .image-shape .label,#mermaid-svg-6ddRtAERuBOWhLm0 .icon-shape .label{text-align:center;}#mermaid-svg-6ddRtAERuBOWhLm0 .node.clickable{cursor:pointer;}#mermaid-svg-6ddRtAERuBOWhLm0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6ddRtAERuBOWhLm0 .arrowheadPath{fill:#333333;}#mermaid-svg-6ddRtAERuBOWhLm0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6ddRtAERuBOWhLm0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6ddRtAERuBOWhLm0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ddRtAERuBOWhLm0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6ddRtAERuBOWhLm0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ddRtAERuBOWhLm0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6ddRtAERuBOWhLm0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6ddRtAERuBOWhLm0 .cluster text{fill:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 .cluster span{color:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6ddRtAERuBOWhLm0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6ddRtAERuBOWhLm0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-6ddRtAERuBOWhLm0 .icon-shape,#mermaid-svg-6ddRtAERuBOWhLm0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ddRtAERuBOWhLm0 .icon-shape p,#mermaid-svg-6ddRtAERuBOWhLm0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6ddRtAERuBOWhLm0 .icon-shape .label rect,#mermaid-svg-6ddRtAERuBOWhLm0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ddRtAERuBOWhLm0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6ddRtAERuBOWhLm0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6ddRtAERuBOWhLm0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Gateway
消息源
技术问题
告警信息
日常事项
分类摘要
Discord: 技术讨论
Telegram: 告警通知
WhatsApp: 日常沟通
路由层
聚合Agent
WhatsApp: 每日汇总

7.3 配置实现

json5 复制代码
{
  agents: {
    list: [
      {
        id: "aggregator",
        workspace: "~/.openclaw/workspace-aggregator",
      },
    ],
  },
  bindings: [
    // 所有通道消息路由到聚合 Agent
    { agentId: "aggregator", match: { channel: "discord", accountId: "default" } },
    { agentId: "aggregator", match: { channel: "telegram", accountId: "default" } },
    { agentId: "aggregator", match: { channel: "whatsapp", accountId: "default" } },
  ],
  channels: {
    discord: {
      accounts: {
        default: { token: "${DISCORD_TOKEN}" },
      },
      groups: {
        "123456789": { requireMention: true },
      },
    },
    telegram: {
      accounts: {
        default: { botToken: "${TELEGRAM_TOKEN}" },
      },
      dmPolicy: "allowlist",
      allowFrom: ["tg:123456789"],
    },
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+8613800138000"],
    },
  },
  messages: {
    groupChat: {
      visibleReplies: "message_tool",  // 仅在主动调用时发言
      unmentionedInbound: "room_event", // 静默监听群消息
    },
  },
}

这个配置将三个通道统一路由到一个聚合智能体。群聊模式下,智能体静默监听所有消息(room_event),只在需要时通过 message 工具发送汇总。这样既不会在群中造成消息骚扰,又能确保不遗漏重要信息。


八、实战案例 2:消息自动回复系统 🤖

8.1 场景描述

构建一个智能自动回复系统,根据消息内容自动分类处理:常见问题直接回复,技术问题转发到技术频道,紧急告警立即通知负责人。

8.2 工作流设计

#mermaid-svg-Y3VUmdQXPUgaRjYY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Y3VUmdQXPUgaRjYY .error-icon{fill:#552222;}#mermaid-svg-Y3VUmdQXPUgaRjYY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Y3VUmdQXPUgaRjYY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .marker.cross{stroke:#333333;}#mermaid-svg-Y3VUmdQXPUgaRjYY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Y3VUmdQXPUgaRjYY p{margin:0;}#mermaid-svg-Y3VUmdQXPUgaRjYY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .cluster-label text{fill:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .cluster-label span{color:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .cluster-label span p{background-color:transparent;}#mermaid-svg-Y3VUmdQXPUgaRjYY .label text,#mermaid-svg-Y3VUmdQXPUgaRjYY span{fill:#333;color:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .node rect,#mermaid-svg-Y3VUmdQXPUgaRjYY .node circle,#mermaid-svg-Y3VUmdQXPUgaRjYY .node ellipse,#mermaid-svg-Y3VUmdQXPUgaRjYY .node polygon,#mermaid-svg-Y3VUmdQXPUgaRjYY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .rough-node .label text,#mermaid-svg-Y3VUmdQXPUgaRjYY .node .label text,#mermaid-svg-Y3VUmdQXPUgaRjYY .image-shape .label,#mermaid-svg-Y3VUmdQXPUgaRjYY .icon-shape .label{text-anchor:middle;}#mermaid-svg-Y3VUmdQXPUgaRjYY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .rough-node .label,#mermaid-svg-Y3VUmdQXPUgaRjYY .node .label,#mermaid-svg-Y3VUmdQXPUgaRjYY .image-shape .label,#mermaid-svg-Y3VUmdQXPUgaRjYY .icon-shape .label{text-align:center;}#mermaid-svg-Y3VUmdQXPUgaRjYY .node.clickable{cursor:pointer;}#mermaid-svg-Y3VUmdQXPUgaRjYY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .arrowheadPath{fill:#333333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Y3VUmdQXPUgaRjYY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Y3VUmdQXPUgaRjYY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Y3VUmdQXPUgaRjYY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Y3VUmdQXPUgaRjYY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .cluster text{fill:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY .cluster span{color:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Y3VUmdQXPUgaRjYY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Y3VUmdQXPUgaRjYY rect.text{fill:none;stroke-width:0;}#mermaid-svg-Y3VUmdQXPUgaRjYY .icon-shape,#mermaid-svg-Y3VUmdQXPUgaRjYY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Y3VUmdQXPUgaRjYY .icon-shape p,#mermaid-svg-Y3VUmdQXPUgaRjYY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Y3VUmdQXPUgaRjYY .icon-shape .label rect,#mermaid-svg-Y3VUmdQXPUgaRjYY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Y3VUmdQXPUgaRjYY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Y3VUmdQXPUgaRjYY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Y3VUmdQXPUgaRjYY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 常见问题
技术问题
紧急告警
收到消息
消息类型判断
查询FAQ库
直接回复答案
转发到技术频道
message: send to discord:tech
立即通知负责人
message: send to whatsapp:admin
创建待办事项
记录处理日志

8.3 实现代码

以下是一个基于 OpenClaw 智能体的自动回复逻辑伪代码,展示了消息分类和路由的核心思路:

python 复制代码
# 自动回复系统核心逻辑
# 该逻辑运行在 OpenClaw Agent 的上下文中

class AutoReplySystem:
    """智能自动回复系统"""
    
    # FAQ 数据库(示例)
    FAQ_DATABASE = {
        "营业时间": "我们的营业时间是周一至周五 9:00-18:00",
        "联系方式": "客服电话:400-123-4567,邮箱:support@example.com",
        "退款政策": "购买后7天内可申请全额退款,请提供订单号",
    }
    
    # 紧急关键词
    URGENT_KEYWORDS = ["宕机", "故障", "紧急", "down", "urgent", "critical"]
    
    # 技术关键词
    TECH_KEYWORDS = ["API", "部署", "代码", "bug", "错误", "异常"]
    
    def process_message(self, message_text, sender, channel):
        """处理收到的消息并自动回复"""
        
        # Step 1: 检查是否为紧急消息
        if self._is_urgent(message_text):
            # 立即通知管理员
            self._notify_admin(message_text, sender)
            # 在原频道确认收到
            self._send_reply(
                channel, sender,
                f"⚠️ 已收到紧急消息,管理员已通知,将尽快处理。"
            )
            return
        
        # Step 2: 检查是否为常见问题
        faq_answer = self._match_faq(message_text)
        if faq_answer:
            self._send_reply(channel, sender, faq_answer)
            return
        
        # Step 3: 检查是否为技术问题
        if self._is_tech_question(message_text):
            # 转发到技术频道
            self._forward_to_tech_channel(message_text, sender)
            self._send_reply(
                channel, sender,
                "🔧 技术问题已转发到技术团队,预计30分钟内回复。"
            )
            return
        
        # Step 4: 默认回复
        self._send_reply(
            channel, sender,
            "收到您的消息,我们会尽快处理。如有紧急事项请标注【紧急】。"
        )
    
    def _is_urgent(self, text):
        return any(kw in text.lower() for kw in self.URGENT_KEYWORDS)
    
    def _match_faq(self, text):
        for question, answer in self.FAQ_DATABASE.items():
            if question in text:
                return answer
        return None
    
    def _is_tech_question(self, text):
        return any(kw in text.lower() for kw in self.TECH_KEYWORDS)
    
    def _notify_admin(self, message_text, sender):
        # 调用 message 工具发送紧急通知
        pass  # message(action=send, target=admin_whatsapp, message=...)
    
    def _send_reply(self, channel, sender, reply_text):
        # 调用 message 工具发送回复
        pass  # message(action=send, target=sender, message=reply_text)
    
    def _forward_to_tech_channel(self, message_text, sender):
        # 调用 message 工具转发到技术频道
        pass  # message(action=send, target=tech_channel, message=...)

这个自动回复系统通过分层判断逻辑,将消息分为紧急、FAQ、技术、普通四个级别,每个级别采取不同的处理策略。紧急消息双通道通知(原频道确认 + 管理员私聊推送),FAQ 直接命中回复,技术问题转发专业频道,普通消息兜底回复。


九、实战案例 3:富媒体消息推送管道 📊

9.1 场景描述

构建一个定时数据报告推送管道,每天自动生成数据图表和 PDF 报告,推送到飞书群和 Telegram 频道。支持图片、PDF 文档和交互式卡片消息。

9.2 架构设计

#mermaid-svg-o1eMVqvhO58I4xTI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o1eMVqvhO58I4xTI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o1eMVqvhO58I4xTI .error-icon{fill:#552222;}#mermaid-svg-o1eMVqvhO58I4xTI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o1eMVqvhO58I4xTI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o1eMVqvhO58I4xTI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o1eMVqvhO58I4xTI .marker.cross{stroke:#333333;}#mermaid-svg-o1eMVqvhO58I4xTI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o1eMVqvhO58I4xTI p{margin:0;}#mermaid-svg-o1eMVqvhO58I4xTI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-o1eMVqvhO58I4xTI .cluster-label text{fill:#333;}#mermaid-svg-o1eMVqvhO58I4xTI .cluster-label span{color:#333;}#mermaid-svg-o1eMVqvhO58I4xTI .cluster-label span p{background-color:transparent;}#mermaid-svg-o1eMVqvhO58I4xTI .label text,#mermaid-svg-o1eMVqvhO58I4xTI span{fill:#333;color:#333;}#mermaid-svg-o1eMVqvhO58I4xTI .node rect,#mermaid-svg-o1eMVqvhO58I4xTI .node circle,#mermaid-svg-o1eMVqvhO58I4xTI .node ellipse,#mermaid-svg-o1eMVqvhO58I4xTI .node polygon,#mermaid-svg-o1eMVqvhO58I4xTI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o1eMVqvhO58I4xTI .rough-node .label text,#mermaid-svg-o1eMVqvhO58I4xTI .node .label text,#mermaid-svg-o1eMVqvhO58I4xTI .image-shape .label,#mermaid-svg-o1eMVqvhO58I4xTI .icon-shape .label{text-anchor:middle;}#mermaid-svg-o1eMVqvhO58I4xTI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o1eMVqvhO58I4xTI .rough-node .label,#mermaid-svg-o1eMVqvhO58I4xTI .node .label,#mermaid-svg-o1eMVqvhO58I4xTI .image-shape .label,#mermaid-svg-o1eMVqvhO58I4xTI .icon-shape .label{text-align:center;}#mermaid-svg-o1eMVqvhO58I4xTI .node.clickable{cursor:pointer;}#mermaid-svg-o1eMVqvhO58I4xTI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o1eMVqvhO58I4xTI .arrowheadPath{fill:#333333;}#mermaid-svg-o1eMVqvhO58I4xTI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o1eMVqvhO58I4xTI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o1eMVqvhO58I4xTI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o1eMVqvhO58I4xTI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o1eMVqvhO58I4xTI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o1eMVqvhO58I4xTI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o1eMVqvhO58I4xTI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o1eMVqvhO58I4xTI .cluster text{fill:#333;}#mermaid-svg-o1eMVqvhO58I4xTI .cluster span{color:#333;}#mermaid-svg-o1eMVqvhO58I4xTI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o1eMVqvhO58I4xTI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o1eMVqvhO58I4xTI rect.text{fill:none;stroke-width:0;}#mermaid-svg-o1eMVqvhO58I4xTI .icon-shape,#mermaid-svg-o1eMVqvhO58I4xTI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o1eMVqvhO58I4xTI .icon-shape p,#mermaid-svg-o1eMVqvhO58I4xTI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o1eMVqvhO58I4xTI .icon-shape .label rect,#mermaid-svg-o1eMVqvhO58I4xTI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o1eMVqvhO58I4xTI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o1eMVqvhO58I4xTI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o1eMVqvhO58I4xTI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 飞书
Telegram
WhatsApp
定时触发器: Cron/Heartbeat
数据采集
生成图表 PNG
生成 PDF 报告
生成摘要文本
消息组装层
目标平台判断
卡片消息 + 图片 + PDF
图片 + 文档 + 文字说明
图片 + 文档 + 纯文本

9.3 实现代码

python 复制代码
# 富媒体消息推送管道
# 基于 OpenClaw message 工具实现跨平台富媒体推送

class MediaPushPipeline:
    """富媒体消息推送管道"""
    
    def push_daily_report(self, chart_path, pdf_path, summary_text):
        """推送每日报告到各平台"""
        
        # ---- 推送到飞书群 ----
        # 飞书支持完整的卡片消息 + 图片 + 文件
        self._push_to_feishu(chart_path, pdf_path, summary_text)
        
        # ---- 推送到 Telegram 频道 ----
        # Telegram 支持图片 + 文档 + Markdown 文字
        self._push_to_telegram(chart_path, pdf_path, summary_text)
        
        # ---- 推送到 WhatsApp ----
        # WhatsApp 支持图片 + 文档 + 纯文本
        self._push_to_whatsapp(chart_path, pdf_path, summary_text)
    
    def _push_to_feishu(self, chart_path, pdf_path, summary_text):
        """推送到飞书:使用卡片消息"""
        
        # 步骤1: 发送交互式卡片消息
        feishu_card = {
            "action": "send",
            "target": "feishu:chat:oc_xxxxxxx",
            "presentation": {
                "title": "📊 每日数据报告",
                "tone": "info",
                "blocks": [
                    {"type": "text", "text": summary_text},
                    {"type": "divider"},
                    {"type": "text", "text": "📅 报告日期:2025-06-16"},
                    {"type": "divider"},
                    {
                        "type": "buttons",
                        "buttons": [
                            {"label": "📄 查看完整报告", "style": "primary", "value": "view_report"},
                            {"label": "📈 查看趋势", "style": "secondary", "value": "view_trend"},
                        ]
                    }
                ]
            }
        }
        # 调用 message 工具发送卡片消息
        # message(**feishu_card)
        
        # 步骤2: 发送图表图片
        feishu_image = {
            "action": "send",
            "target": "feishu:chat:oc_xxxxxxx",
            "message": "今日数据趋势图",
            "media": chart_path,  # 本地图片路径
        }
        # message(**feishu_image)
        
        # 步骤3: 发送 PDF 报告
        feishu_pdf = {
            "action": "send",
            "target": "feishu:chat:oc_xxxxxxx",
            "message": "完整 PDF 报告",
            "filePath": pdf_path,
            "filename": "2025-06-16-每日报告.pdf",
        }
        # message(**feishu_pdf)
    
    def _push_to_telegram(self, chart_path, pdf_path, summary_text):
        """推送到 Telegram:图片 + 文档"""
        
        # Telegram 先发图片(带 caption)
        tg_image = {
            "action": "send",
            "target": "tg:-1001234567890",  # Telegram 频道 ID
            "message": f"📊 每日数据报告\n\n{summary_text}",
            "media": chart_path,
        }
        # message(**tg_image)
        
        # 再发 PDF 文档
        tg_pdf = {
            "action": "send",
            "target": "tg:-1001234567890",
            "message": "📄 完整 PDF 报告",
            "filePath": pdf_path,
            "filename": "daily-report-2025-06-16.pdf",
        }
        # message(**tg_pdf)
    
    def _push_to_whatsapp(self, chart_path, pdf_path, summary_text):
        """推送到 WhatsApp:图片 + 文档"""
        
        # WhatsApp 图片会自动压缩优化
        wa_image = {
            "action": "send",
            "target": "+8613800138000",
            "message": f"每日数据报告\n\n{summary_text}",
            "media": chart_path,
        }
        # message(**wa_image)
        
        # WhatsApp 文档保留原始文件名
        wa_pdf = {
            "action": "send",
            "target": "+8613800138000",
            "filePath": pdf_path,
            "filename": "2025-06-16-daily-report.pdf",
        }
        # message(**wa_pdf)

这个推送管道的核心思路是:同一份数据,根据目标平台的能力选择最佳的呈现方式。飞书用卡片消息呈现交互式报告,Telegram 用 Markdown + 图片 + 文档组合,WhatsApp 用纯文本 + 图片 + 文档。所有平台都能收到完整的信息,但每个平台都能以最自然的方式呈现。

9.4 媒体处理细节

在推送过程中,OpenClaw 会自动处理以下媒体转换:

  • 图片压缩:WhatsApp 通道会自动将图片缩放至最大 2048px 边长并重新压缩为 JPEG,确保在移动端快速加载
  • 文件名保留 :文档发送时保留原始文件名(通过 filename 参数指定),方便接收方识别
  • 语音笔记模式:如果推送的是音频文件,WhatsApp 通道会自动以语音笔记模式发送
  • GIF 播放 :视频文件可以通过 gifPlayback: true 标记为 GIF 模式,在移动端循环内联播放

十、高级话题与最佳实践 🎯

10.1 Bot 循环防护

当两个机器人互相监听同一个频道时,可能出现无限回复循环。OpenClaw 提供了内置的 Bot 循环防护 机制,自动检测并中断这种循环。在多机器人共存的频道中,建议始终启用此功能。

10.2 环境房间事件

对于需要智能体"常驻但不主动说话"的场景,可以使用 环境房间事件(Ambient Room Events) 模式。此模式下,未被提及的群聊消息作为静默上下文传递给智能体,智能体不会自动回复,但可以基于上下文在必要时主动发言。

10.3 多账号支持

OpenClaw 支持在同一 Gateway 中配置同一通道的多个账号。例如,你可以同时连接两个 WhatsApp 号码、两个 Telegram Bot,分别路由到不同的智能体:

json5 复制代码
{
  channels: {
    telegram: {
      accounts: {
        default: {
          botToken: "123456:ABC...",   // 主 Bot
          dmPolicy: "pairing",
        },
        alerts: {
          botToken: "987654:XYZ...",   // 告警 Bot
          dmPolicy: "allowlist",
          allowFrom: ["tg:123456789"],
        },
      },
    },
  },
}

10.4 CLI 消息发送

除了通过智能体调用 message 工具外,OpenClaw 还提供了命令行接口直接发送消息:

bash 复制代码
# 发送文本消息
openclaw message send --target "+8613800138000" --message "测试消息"

# 发送带媒体的消息
openclaw message send --media /workspace/chart.png --message "今日图表"

# 干跑模式(只显示将要发送的内容,不实际发送)
openclaw message send --target "tg:123456789" --message "测试" --dry-run

# JSON 输出模式
openclaw message send --target "+8613800138000" --message "测试" --json

CLI 方式特别适合在脚本和自动化工作流中使用,例如 CI/CD 管道中的通知推送。

10.5 安全最佳实践

  • 最小权限原则 :使用 allowlist 而非 open 模式,仅允许已知的发送者
  • 群聊沙箱化:为群聊会话启用 Docker 沙箱,隔离主机资源访问
  • 定期审计 :使用 openclaw doctor 定期检查配置安全性和通道健康状态
  • 密钥管理:API Token 等敏感信息使用环境变量注入,不要硬编码在配置文件中
  • 可见回复控制 :在公共群中使用 message_tool 模式,避免智能体意外泄露信息

十一、总结与展望 🔭

OpenClaw 的消息系统设计体现了几个核心工程理念:

  1. 协议无关性:智能体不需要关心底层消息平台的协议细节,Gateway 统一处理适配
  2. 优雅降级:跨平台消息格式差异通过自动降级策略解决,确保信息不丢失
  3. 会话连续性:跨平台私聊共享同一会话上下文,用户可以无缝切换平台继续对话
  4. 安全优先:从 DM 策略到群聊沙箱,多层安全机制保护主机和用户数据
  5. 灵活路由:基于绑定的路由系统支持多智能体、多账号的复杂部署场景

随着 AI 智能体的应用场景不断扩展,消息系统作为人机交互的核心界面,其重要性将持续增长。OpenClaw 通过统一的 Gateway 架构和灵活的消息处理管道,为开发者提供了一个强大而可靠的基础设施。

如果你正在构建多平台消息集成方案,或者希望让自己的 AI 助手同时服务于多个即时通讯平台,OpenClaw 无疑是一个值得深入探索的选择。更多信息请访问 官方文档


📌 参考链接

相关推荐
智海观潮17 小时前
OpenClaw生态全景解析 - 9大核心工具赋能 AI 自动化落地
ai·agent·skills·ai 自动化·openclaw
虾壳云官方1 天前
openclaw 一键安装教程(2026年6月15最新)
运维·人工智能·windows·自动化·openclaw
AC赳赳老秦1 天前
OpenClaw + 飞书多维表格:自动同步数据、生成统计图表、触发自动化任务
java·大数据·python·缓存·自动化·deepseek·openclaw
AC赳赳老秦2 天前
OpenClaw+Power Apps 实战:自动生成 Power Apps 应用、连接 Excel 数据源
大数据·开发语言·python·serverless·excel·deepseek·openclaw
七夜zippoe2 天前
OpenClaw 节点方法调用:跨设备能力调用实战
ai·调用·跨设备·openclaw·nodes
虾壳云官方3 天前
OpenClaw 2.7.9 Windows 一键部署教程:零基础也能搭建 AI 自动化助手
运维·人工智能·windows·自动化·openclaw·openclaw一键部署
七夜zippoe3 天前
OpenClaw 节点命令执行:远程Shell与系统操作实战
github·shell·openclaw·nodes·系统操作
旺财矿工3 天前
OpenClaw 飞书机器人配置教程|一键对接飞书,实现聊天下达 AI 指令
人工智能·机器人·飞书·openclaw·龙虾
程序猿小白菜3 天前
OpenClaw 飞书机器人搭建流程
ai·机器人·飞书·openclaw