OpenClaw 静默房间事件(Ambient Room Events)完全指南:让 Agent 在群聊中"只听不说"
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
导读
本文档讲解 OpenClaw 的 ambient room events(静默房间事件)机制:它允许 Agent 将群聊或频道中未被 @ 提及的消息作为"安静上下文"进行处理——Agent 可以更新记忆与会话状态,但房间保持静默,除非 Agent 显式调用message工具才会发言。该机制面向需要 7×24 小时"常驻监听"型群聊的场景,是替代旧式NO_REPLY提示词模式的现代方案。读完本文,你将掌握如何配置全局群聊行为、如何针对 Discord / Slack / Telegram 等频道落地、如何做 Agent 级策略覆盖,以及如何排查"只打字不说话"类问题。
一、什么是 Ambient Room Events
在默认行为下,OpenClaw 收到群聊中未被 @ 提及的消息时,通常不会唤醒 Agent 进行处理。而开启 ambient room events 后,未提及的群组/频道消息会被归类为room_event(房间事件),而不是user_request(用户请求)。
从源码分类器可以清晰看到这一设计意图(src/channels/inbound-event/kind.ts):
/** * High-level inbound event class used to separate actionable user requests from room activity. */ export type InboundEventKind = "user_request" | "room_event";对应的分类逻辑位于 src/channels/inbound-event/classification.ts:
export function classifyChannelInboundEvent( params: ClassifyChannelInboundEventParams, ): InboundEventKind { if (params.unmentionedGroupPolicy !== "room_event") { return "user_request"; } if (params.conversation.kind !== "group" && params.conversation.kind !== "channel") { return "user_request"; } // Native commands, mentions, control commands, and aborts are explicit user intent even when // unmentioned group traffic would otherwise be treated as passive room activity. if ( params.wasMentioned === true || params.hasControlCommand === true || params.hasAbortRequest === true || params.commandSource === "native" ) { return "user_request"; } return "room_event"; }也就是说:只有当"未提及群聊策略"被显式配置为room_event、且会话属于群组/频道、且消息既未被提及、也不含控制命令/中止请求/原生命令时,该消息才会被归类为静默房间事件。提及、控制命令、原生命令、中止请求始终是显式的用户意图,无论群聊流量如何配置都会保持为user_request。
支持范围
目前支持 ambient room events 的频道有:
- Discord 公会频道(guild channels)
- Slack 频道与私密频道(channels & private channels)
- Slack 多人私信(multi-person DMs,mpim)
- Telegram 群组与超级群组(groups / supergroups)
其他群组频道在未明确声明支持前,维持原有的群组行为不变。
与旧式 NO_REPLY 提示词模式的对比
传统做法是在系统提示词中要求模型对无需回复的消息输出NO_REPLY,由 Agent 端判断后抑制回复。ambient room events 将这一决策从"模型提示词"下沉到"路由层分类器":分类器在消息进入 Agent 前就决定其归属,Agent 只处理被归类为user_request的请求,而房间事件则作为静默上下文注入。这意味着:
- 不再依赖模型"记得"输出 NO_REPLY;
- 模型不会因为被迫输出标记文本而浪费 token;
- 是否发言完全由 Agent 通过显式调用
message(action=send)决定。
二、推荐配置:让房间"常驻监听、按需发言"
核心推荐组合是两条messages.groupChat配置:
{ messages: { groupChat: { unmentionedInbound: "room_event", visibleReplies: "message_tool", historyLimit: 50, }, }, }三个字段的作用:
| 字段 | 取值 | 说明 |
|---|---|---|
unmentionedInbound | "room_event" | 未提及的群组/频道消息被归类为静默房间事件(另一可选值为"user_request",即默认行为,未提及消息仍唤醒 Agent) |
visibleReplies | "message_tool" | 可见回复必须通过message工具发送;模型产出的最终文本默认保持私密 |
historyLimit | 正整数,默认 50 | 全局群组历史窗口条数上限 |
从配置 Schema 可以看到这三个字段的合法取值范围(src/config/zod-schema.messages.ts):
export const GroupChatSchema = z .object({ mentionPatterns: z.array(z.string()).optional(), historyLimit: z.number().int().min(0).optional(), unmentionedInbound: z.enum(["user_request", "room_event"]).optional(), visibleReplies: VisibleRepliesSchema.optional(), }) .strict() .optional();其中visibleReplies还兼容布尔写法(src/config/zod-schema.messages.ts):true归一化为"automatic",false归一化为"message_tool"。
关于历史窗口的补充:
historyLimit为 0 时表示该频道禁用群组历史上下文;频道可用channels.<channel>.historyLimit覆盖全局值,部分频道还支持按账号设置历史上限。Telegram 的旧配置键includeGroupHistoryContext已被移除,可通过openclaw doctor --fix自动清理。
完成全局配置后,还需要让该房间"常驻开启":即关闭该房间的提及门槛(mention gating)。注意房间仍需通过其正常的groupPolicy、房间白名单与发送者白名单校验。
配置生效方式
保存配置后,Gateway 会对messages相关设置进行热应用(hot-apply)。但如果设置了gateway.reload.mode: "off",则需要手动重启 Gateway 才能使改动生效。
三、前置条件:两个容易忽略的"静默开关"
即使设置了unmentionedInbound: "room_event",仍有两个设置会静默地禁用 ambient room events。
1. 房间必须关闭提及门槛(requireMention: false)
requireMention: true会在消息路由之前丢弃所有未提及消息,因此它们永远不可能变成房间事件。此时 Agent 完全没有房间回放(room backlog),它只能看到提及自己的消息。如果 Agent 反馈"看不到最近的房间历史",请先检查提及门槛,而不是其他配置。
2. Agent 必须拥有 message 工具
房间事件采用严格的可见投递(strict visible delivery)机制,发言必须调用message(action=send)。message工具随messaging工具档案(tool profile)一起提供,而minimal与coding档案不包含它。如果 Agent 运行在tools.profile: "coding"下,它会"听得到"房间事件,却永远无法发言。
当档案缺少该工具时,需要显式授权:
{ agents: { entries: { "<agent-id>": { tools: { alsoAllow: ["message"] }, }, }, }, }不要凭经验假设档案一定包含message工具,请用openclaw agents list查看有效工具面(effective surface),并通过一轮探针对话(probe turn)实测确认。
四、开启后行为变化一览
配置messages.groupChat.unmentionedInbound: "room_event"后:
| 入站消息类型 | 归类结果 |
|---|---|
| 被允许的未提及群组/频道消息 | 静默房间事件(room event) |
| 被提及的消息 | 用户请求(user request) |
| 文本控制命令 / 原生命令 | 用户请求 |
| 中止(abort)/ 停止请求 | 用户请求 |
| 私聊消息(direct message) | 用户请求 |
房间事件使用严格的可见投递:
- 最终助手文本(final assistant text)保持私密;
- Agent 必须调用
message(action=send)才能在房间内发言; - 打字状态(typing)与生命周期状态反应(lifecycle status reactions)对房间事件保持抑制。
唯一显式的回执(receipt)例外是messages.ackReactionScope: "all":该配置会发送已配置的确认反应(ack reaction)。如果希望房间完全静默,请使用任何更窄的 scope 或"off"。
从 ack 反应门控源码可以看到这一约束(src/channels/ack-reactions.ts):
export function shouldAckReaction(params: AckReactionGateParams): boolean { const scope = params.scope ?? "group-mentions"; if (scope === "off" || scope === "none") { return false; } // Ambient room events stay silent unless the operator explicitly chose the // unconditional scope. This keeps every channel on the same `all` contract. if (params.inboundEventKind === "room_event" && scope !== "all") { return false; } if (scope === "all") { return true; } ... }ackReactionScope的合法取值在 src/config/zod-schema.messages.ts 中定义为:["group-mentions", "group-all", "direct", "all", "off", "none"],默认值是group-mentions。
五、Discord 实例配置
场景一:整个公会全部静默监听
{ messages: { groupChat: { unmentionedInbound: "room_event", visibleReplies: "message_tool", historyLimit: 50, }, }, channels: { discord: { groupPolicy: "allowlist", guilds: { "<DISCORD_SERVER_ID>": { requireMention: false, users: ["<YOUR_DISCORD_USER_ID>"], }, }, }, }, }场景二:仅单个频道静默监听
当只需要一个频道保持 ambient 时,使用按频道(per-channel)的 Discord 配置。在groupPolicy: "allowlist"下,列出该频道即是允许它(enabled: false可禁用某个条目):
{ channels: { discord: { groupPolicy: "allowlist", guilds: { "<DISCORD_SERVER_ID>": { channels: { "<DISCORD_CHANNEL_ID_OR_NAME>": { requireMention: false, }, }, }, }, }, }, }注意:这里的<DISCORD_SERVER_ID>与<DISCORD_CHANNEL_ID_OR_NAME>需要替换为你实际的值。Discord 频道既支持 ID 也支持频道名称作为键。
六、Slack 实例配置
Slack 频道白名单是ID-first的:必须使用频道 ID(形如C12345678),而不是#channel-name。在channels.slack.channels下列出该频道即是允许它(enabled: false可禁用条目):
{ messages: { groupChat: { unmentionedInbound: "room_event", visibleReplies: "message_tool", historyLimit: 50, }, }, channels: { slack: { groupPolicy: "allowlist", channels: { "<SLACK_CHANNEL_ID>": { requireMention: false, }, }, }, }, }Slack 历史权限提示:如果 Slack ambient 房间完全不触发,请确认:① 频道键确实是 Slack 频道 ID;② 应用具备对应房间类型的历史读取 scope——公开频道需要
channels:history,私密频道需要groups:history,多人私信(mpim)需要mpim:history。
七、Telegram 实例配置
对 Telegram 群组而言,bot 必须能够看到普通群消息。设置requireMention: false后,需要关闭 BotFather 的隐私模式(privacy mode),或采用其他能向 bot 投递完整群流量的 Telegram 设置。
{ messages: { groupChat: { unmentionedInbound: "room_event", visibleReplies: "message_tool", historyLimit: 50, }, }, channels: { telegram: { groups: { "<TELEGRAM_GROUP_CHAT_ID>": { groupPolicy: "open", requireMention: false, }, }, }, }, }获取 Telegram 群组 ID 的三种途径:
- Telegram 群组 ID 通常是负数,形如
-1001234567890; - 从
openclaw logs --follow中读取chat.id; - 将一条群消息转发给 ID helper bot,或直接检查 Bot API 的
getUpdates返回。
Telegram 历史窗口的特殊行为:Telegram 支持房间事件频道时,会维护一个由
historyLimit限定的常驻滚动窗口(always-on rolling per-group window)。用户请求回合(user-request turns)会选取 bot 最后一次回复之后的条目作为上下文;而房间事件回合(room-event turns)会获得完整的最近窗口,以便模型看到自己最近的发言。旧版includeGroupHistoryContext模式键已被移除,openclaw doctor --fix会负责清理。
八、Agent 级策略覆盖(多 Agent 共享房间)
当多个 Agent 共享同一个房间、但只有其中一个需要把未提及闲聊当作 ambient 上下文时,可以使用 Agent 覆盖(agent override):
{ messages: { groupChat: { visibleReplies: "message_tool", }, }, agents: { entries: { main: { default: true, groupChat: { unmentionedInbound: "room_event", mentionPatterns: ["@openclaw", "openclaw"], }, }, }, }, }Agent 特定的agents.entries.*.groupChat.unmentionedInbound值会覆盖全局messages.groupChat.unmentionedInbound。这一点与源码中的策略解析逻辑一致(src/channels/inbound-event/classification.ts):解析时优先读取 Agent 的groupChat配置,仅当 Agent 配置显式包含unmentionedInbound键时才采用它,否则回退到全局messages.groupChat.unmentionedInbound,最终默认值为user_request。
九、可见回复模式(Visible Reply Modes)详解
messages.groupChat.visibleReplies的默认值是"automatic",适用于普通群组/频道的用户请求:最终助手文本无需显式调用 message 工具即可自动可见发布。
- 保持
"automatic":适用于常规群聊,希望 Agent 的最终回复自动上屏; - 改用
"message_tool":适用于 ambient 常驻房间,让 Agent 通过调用 message 工具自行决定何时发言。
官方建议在 ambient 常驻房间中始终使用"message_tool",尤其适合最新一代、工具调用可靠性高的模型(例如文档中提到的 GPT-5.6 Sol 类模型)。如果模型返回了最终文本但没有调用工具,OpenClaw 会保持该文本私密,并记录"抑制投递"(suppressed-delivery)元数据。
重要区别:即使其他群组请求使用自动回复,房间事件依然保持严格投递——未提及的 ambient 房间事件始终需要message(action=send)才能产生可见输出。
十、历史上下文(History)机制
messages.groupChat.historyLimit是全局群组历史默认值,未设置时为 50,必须为正整数;- 频道可用
channels.<channel>.historyLimit覆盖全局值,部分频道还支持按账号设置历史上限; - 设置频道级
historyLimit: 0可禁用该频道的群组历史上下文。
从源码的会话转录逻辑可见(src/channels/inbound-event/context.ts),历史窗口只有在historyLimit > 0时才会作为SessionTranscriptContext提供给入站事件:
SessionTranscriptContext: params.sessionTranscript && params.sessionTranscript.historyLimit > 0 ? params.sessionTranscript : undefined,支持房间事件的频道会保留最近的 ambient 房间消息作为上下文。Telegram 的滚动窗口行为已在第七节详述。
十一、故障排查(Troubleshooting)
现象:房间显示打字状态或 token 消耗,但看不到可见消息
按以下顺序排查:
- 确认房间已通过频道白名单与发送者白名单(channel allowlist & sender allowlist);
- 确认
requireMention: false已设置在预期的房间层级(检查是公会级还是频道级); - 检查
messages.groupChat.unmentionedInbound或 Agent 覆盖值是否为"room_event"; - 检查日志中的抑制投递元数据,关注
didSendViaMessagingTool: false之类的标记; - 对普通群组请求:如果需要最终回复自动上屏,请保持/恢复
messages.groupChat.visibleReplies: "automatic";对使用message_tool的 ambient 房间,请使用能可靠调用工具的模型/运行时。
现象:Telegram ambient 房间完全不触发
检查 BotFather 隐私模式是否关闭,并验证 Gateway 是否确实收到了普通群消息。
现象:Slack ambient 房间不触发
验证两点:① 频道键是否为 Slack 频道 ID(而非#channel-name);② 应用是否具备对应房间类型的历史 scope(公开channels:history/ 私密groups:history/ 多人私信mpim:history)。
现象:Agent 报告看不到房间历史
优先检查提及门槛——requireMention: true会在路由前丢弃未提及消息,Agent 将完全没有房间回放。
十二、延伸阅读
- 群组(Groups)
- Discord 频道
- Slack 频道
- Telegram 频道
- 频道故障排查
- 频道配置参考
小结
Ambient room events 是 OpenClaw 中"监听型常驻 Agent"的基础设施:它在路由层完成消息分类,让 Agent 在群聊中安静地更新记忆与状态,只在值得回应时通过message工具主动开口。核心配置只有三件事——unmentionedInbound: "room_event"、visibleReplies: "message_tool"、房间级requireMention: false,再加上message工具授权;配合 Agent 级覆盖与频道级历史窗口,即可构建出从 Discord、Slack 到 Telegram 的统一静默监听体验。
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考