消息
入站消息会经过路由、去重/防抖、一次 agent 运行以及出站投递:
Inbound message
-> routing/bindings -> session key
-> dedupe + debounce
-> queue (if a run is already active)
-> agent run (streaming + tools)
-> outbound replies (channel limits + chunking)
关键配置项:
messages.*用于前缀、排队、入站防抖和群组行为。agents.defaults.*用于块流式传输、分块和静默回复默认值。- 通道覆盖项(
channels.telegram.*、channels.whatsapp.*等)用于每个通道的上限和流式传输开关。
完整模式参见 配置。
入站去重¶
通道可能在重连后重新投递同一条消息。OpenClaw 会维护一个内存缓存,其键由 agent 作用域、通道路由(channel + peer + account + thread)和消息 id 组成,因此重新投递的消息不会触发第二次 agent 运行。缓存条目在 20 分钟后过期,或者在跟踪到 5000 个条目后过期,以先发生者为准。
入站防抖¶
来自同一发送者的快速文本消息可以通过 messages.inbound 合并为一个 agent 回合。防抖按通道 + 会话范围生效,并使用最近一条消息进行回复线程/ID 关联。它是一种静默窗口启发式策略,并不保证长消息的每一部分都会在一个回合内到达。
{
messages: {
inbound: {
debounceMs: 2000,
byChannel: {
discord: 1500,
slack: 1500,
whatsapp: 5000,
},
},
},
}
- 防抖仅适用于纯文本消息;媒体/附件会立即发送。
- 控制命令(stop/abort/status 等)会绕过防抖,因此会立即派发。
- Telegram 默认在 300ms 静默窗口后对普通文本进行批处理。其他通道除非配置,否则没有通用防抖延迟。
messages.inbound.byChannel.<channel>优先于messages.inbound.debounceMs;两者都会覆盖通道默认值。设置为0可禁用普通突发批处理。- 对于非转发的 Telegram 文本,长度至少为 4000 个字符的消息允许最多 1500ms 用于后续内容。短消息和长消息共享同一批次,且不要求消息 ID 连续。即使禁用了普通批处理,这种自动长粘贴组装仍然有效。
- iMessage 遵循相同的通用防抖策略。
imsg0.13.1 及更高版本会在 OpenClaw 接收之前合并 Apple URL 预览拆分发送,因此无需 iMessage 专用防抖设置。
对 messages.inbound.debounceMs 和 messages.inbound.byChannel 的更改无需重新连接 Discord、Feishu、iMessage、Mattermost、Microsoft Teams、Signal、Slack、Telegram 或 WhatsApp 即可生效。新准入的入站工作使用已提交的延迟。仅配置更改本身不会重新调度待处理批次;后续消息可以在原始最大截止时间范围内更新其空闲延迟。显式传输计时覆盖项保持不变。Telegram 的转发消息收集窗口仍然独立。
会话与设备¶
会话由网关拥有,而不是由客户端拥有。
- 直接聊天会合并到 agent 的主会话键中。
- 群组/频道拥有各自的会话键。
- 会话存储和转录记录位于网关主机上。
多个设备/通道可以映射到同一会话,但历史不会完全同步回每个客户端。对于长对话,请使用一个主设备以避免上下文分歧。Control UI 和 TUI 始终显示由网关支持的会话转录记录,因此它们是事实来源。
详情:会话管理。
提示词主体与历史上下文¶
通道插件会在入站上下文中填充多个文本字段,按优先级从高到低排列:
| 字段 | 用途 |
|---|---|
BodyForAgent |
面向当前回合模型的文本。未设置时回退到 CommandBody / RawBody / Body。 |
BodyForCommands |
用于指令/命令解析的干净文本。未设置时回退到 CommandBody / RawBody / Body。 |
CommandBody |
遗留中间主体;优先使用 BodyForCommands。 |
RawBody |
CommandBody 的已弃用别名。 |
Body |
遗留提示词主体;可能包含通道信封和历史包装。 |
当通道提供历史时,它会用以下内容包装:
[Chat messages since your last reply - for context][Current message - respond to this]
对于非直接聊天(群组/频道/房间),当前消息主体会加上发送者标签前缀,以匹配历史条目所使用的样式。指令剥离仅适用于当前消息部分,因此历史保持完整。包装历史的通道应将 BodyForCommands(或遗留的 CommandBody / RawBody)设置为原始消息文本,并将 Body 保留为组合提示词。
历史缓冲区仅包含待处理内容:它们包括未触发运行的群组消息(例如,提及门控消息),并排除已存在于会话转录记录中的消息。结构化历史、回复、转发和通道元数据在提示词组装期间会渲染为不可信的用户角色上下文块。
使用 messages.groupChat.historyLimit(全局默认值)或按通道覆盖项(例如 channels.slack.historyLimit 和 channels.telegram.accounts.<id>.historyLimit)配置历史大小(设置为 0 可禁用)。
工具结果元数据¶
工具结果的 content 是模型可见的结果;details 是用于 UI 渲染、诊断、媒体投递和插件的运行时元数据。
toolResult.details会在提供商重放之前和压缩输入之前被移除。- 持久化的会话转录记录仅保留有界的
details;超大的元数据会被替换为标记为persistedDetailsTruncated: true的简洁摘要。 - 插件和工具应将模型必须读取的文本放在
content中,而不仅仅放在details中。
当工具错误警告是代理的唯一回复时,WebChat 会显示并保留该警告。该警告本身不会将已完成的代理运行变为运行时失败;失败的工具结果仍会单独记录。
排队与后续消息¶
当已有运行处于活动状态时,传入消息默认会转向该运行。messages.queue 控制模式:
| 模式 | 行为 |
|---|---|
steer(默认) |
将新提示注入活动运行。 |
followup |
在活动运行结束后运行该消息。 |
collect |
将兼容的消息批量合并为一个后续回合。 |
interrupt |
中止活动运行,然后启动最新的提示。 |
队列对 steer、followup 和 collect 批处理使用内置的 500ms 防抖。messages.queue.cap 默认为 20 条排队消息,messages.queue.drop 默认为 summarize(也可用 old 和 new)。通过 messages.queue.byChannel 和 messages.queue.debounceMsByChannel 配置按通道覆盖。
通道运行所有权¶
通道插件可以在消息进入会话队列之前保持顺序、对输入进行防抖并应用传输背压。它们不应在代理回合本身周围设置单独的超时。一旦消息被路由到会话,会话、工具和运行时生命周期将管理长时间运行的工作,以便所有通道一致地报告并恢复缓慢的回合。
一旦回合被持久接受,在其答案之前发生的意外失败会在直接聊天以及启用了自动回复的明确指定对话中生成一条紧凑的错误回复。进度确认不会替代该最终结果。该回合仍保持失败状态,并且不会作为新的传入消息重放;投递策略以及已通过 message 工具发送的回复仍然适用。
在 OpenClaw 运行时中,如果助手回合在生成部分文本后出错或被中止,且没有工具调用,则会在下一个模型请求中显示为一个简短的失败标记。其未完成文本不会被重放,已存储的失败回合保持不变。空失败和仅占位符失败仍被排除;失败的工具调用保留其现有配对规则。该标记不会确定先前操作是否已完成。
流式传输、分块与批处理¶
块流式传输会在模型生成文本块时发送部分回复;分块会遵守通道文本限制,并避免拆分围栏代码。
agents.defaults.blockStreamingDefault(on|off,默认off)agents.defaults.blockStreamingBreak(text_end|message_end)agents.defaults.blockStreamingChunk(minChars|maxChars|breakPreference)agents.defaults.blockStreamingCoalesce(基于空闲的批处理)agents.defaults.humanDelay(块回复之间类似人类的暂停)- 通道覆盖:捆绑通道上的
*.streaming.block.enabled和*.streaming.block.coalesce;过时的扁平键由openclaw doctor --fix迁移。除非明确启用,否则块流式传输在所有通道上均关闭,包括 Telegram。QQ Bot 是例外:它没有streaming.block键,并且会流式传输块回复,除非channels.qqbot.streaming.mode为"off"。
详情:流式传输 + 分块。
推理可见性与令牌¶
/reasoning on|off|stream控制可见性。- 当模型生成推理内容时,该内容仍会计入令牌使用量。
- Telegram 支持将推理流式传输到临时草稿气泡中,该气泡在最终投递后删除;使用
/reasoning on可获取持久推理输出。
前缀、线程与回复¶
- 支持回复前缀的通道使用
channels.<channel>.responsePrefix;当支持多账户配置时,使用channels.<channel>.accounts.<id>.responsePrefix。账户值优先,包括使用""禁用继承的前缀。使用"auto"表示代理身份名称,或使用诸如"[{model}]"之类的模板表示所选模型。自动回复支持因通道而异。Doctor 在那些规范字段未设置时,将全局回退值复制到受支持的已配置通道块中;messages.responsePrefix仍作为隐式和自定义通道的回退值。 - 显式
message工具和 CLI 文本发送也会应用已解析的前缀,而不会重复已存在的前缀。它们会解析身份占位符,但不会选择模型;包含未解析的模型、提供商或思考级别占位符的前缀将被完全省略。 - 通过
replyToMode和按通道默认值进行回复线程。
详情:配置 和通道文档。
静默回复¶
静默令牌 NO_REPLY(不区分大小写,因此 no_reply 也会匹配)永远不会作为用户可见文本投递。当回合还有待处理工具媒体(例如生成的 TTS 音频)时,OpenClaw 会移除静默文本,但仍会投递媒体附件。
静默策略按对话类型解析:
- 直接对话永远不会收到
NO_REPLY提示指导。未投递的必需答案仍需恢复;该令牌不能免除该义务。 - 已接受的群组/通道请求默认需要回复,包括以
requireMention: false放行的未提及消息。提及和访问门控仍决定哪些消息到达代理。若要允许未指定对象的请求静默结束,请在以下配置范围之一中显式设置silentReply.group: "allow";提及和授权命令仍需要响应。 - 环境房间事件 和内部辅助回合可以保持静默。在
message_tool可见回复模式下,可选回合通过不调用message(action=send)保持静默。
默认值位于 agents.defaults.silentReply 下;surfaces.<id>.silentReply 可按 surface 覆盖群组/内部策略。
通用内部 runner 故障对于尚未显示可见输出的可选轮次保持静默,包括明确配置为允许静默的群组。必需轮次仍会收到错误。已分类的恢复指引(例如 missing-auth、rate-limit 或 overload 通知)仍可投递,并且可见进度会收到失败结果,而不是被遗留为未完成状态。直接聊天默认显示简洁的失败文案;只有启用 /verbose full 时才会显示原始 runner 详情。
回复要求来自准入,而不是模型控制 token。已确认的投递或仍由当前方持有的投递可防止重复恢复;参见 回复整形。
相关¶
- Channel inbound API - 接收编排和确认策略
- Channel outbound API - 持久化发送和投递回执
- 流式传输 - 实时消息投递
- 重试 - 消息投递重试行为
- 队列 - 消息处理队列
- 频道 - 消息平台集成
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw