流式传输 + 分块
OpenClaw 有两个独立的流式传输层:- 区块流式传输(频道): 当助手生成时,发送完成的区块。这些是普通频道消息(非令牌增量)。
- 预览流式传输(Telegram/Discord/Slack): 生成过程中实时更新一个临时的预览消息。
区块流式传输(频道消息)
区块流式传输以粗粒度块的形式发送助手输出,一旦输出可用即发送。text_delta/events:模型流事件(对于非流模式模型可能是稀疏的)。chunker:EmbeddedBlockChunker,应用最小/最大边界 + 中断偏好。channel send:实际出站消息(区块回复)。
agents.defaults.blockStreamingDefault:"on"/"off"(默认关闭)。- 频道覆盖设置:
*.blockStreaming(及按账户划分变体),可强制对频道开启/关闭。 agents.defaults.blockStreamingBreak:"text_end"或"message_end"。agents.defaults.blockStreamingChunk:{ minChars, maxChars, breakPreference? }。agents.defaults.blockStreamingCoalesce:{ minChars?, maxChars?, idleMs? }(在发送前合并流式块)。- 频道硬限制:
*.textChunkLimit(例如channels.whatsapp.textChunkLimit)。 - 频道分块模式:
*.chunkMode(默认length,newline会在空行(段落边界)处拆分,再按长度分块)。 - Discord 软限制:
channels.discord.maxLinesPerMessage(默认 17),分割过长回复以避免 UI 裁剪。
text_end:分块器一发出区块即流出;每遇text_end刷新。message_end:等助手消息完成后,再刷新缓冲输出。
message_end 模式下,如果缓冲文本超过了 maxChars,仍然会调用分块器,可能在结尾处输出多个区块。
分块算法(低/高边界)
区块分块由EmbeddedBlockChunker 实现:
- 低边界: 缓冲区未达到
minChars不输出(除非被强制)。 - 高边界: 优先在
maxChars之前分段;若被强制,则在maxChars处拆分。 - 中断偏好顺序:
paragraph→newline→sentence→whitespace→ 硬中断。 - 代码块: 永远不在代码区块内拆分;若在
maxChars处被迫拆分,则关闭后重新打开代码块,保持 Markdown 合法。
maxChars 会被限制为频道的 textChunkLimit,因此无法超出频道最大限制。
合并(合并流式块)
启用区块流式传输时,OpenClaw 可以合并连续的区块片段再发送。这减少了“单行刷屏”,同时仍支持渐进输出。- 合并会等待空闲间隙(
idleMs)后刷新。 - 缓冲区大小限制为
maxChars,超过则强制刷新。 minChars防止过小片段被发送,直到累计足够文本为止(最后刷新时会发送剩余文本)。- 拼接符由
blockStreamingChunk.breakPreference决定(paragraph→\n\n,newline→\n,sentence→ 空格)。 - 频道覆盖配置支持
*.blockStreamingCoalesce(包括按账户分配置)。 - Signal/Slack/Discord 默认将合并最小字符数提至 1500,除非覆盖。
区块间仿人类节奏
启用区块流式传输时,可以在区块回复之间(首个区块之后)添加随机停顿,让多气泡回复更自然。- 配置项:
agents.defaults.humanDelay(可通过agents.list[].humanDelay针对单个代理覆盖)。 - 模式:
off(默认)、natural(800–2500ms)、custom(minMs/maxMs)。 - 仅对区块回复生效,不影响最终回复或工具汇总。
“流式分块或一次输出”
映射为:- 流式分块:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(边生成边发送)。非 Telegram 频道也需*.blockStreaming: true。 - 全部流式输出于完成时:
blockStreamingBreak: "message_end"(一次刷新,极长文本时可能分多个区块)。 - 不使用区块流式:
blockStreamingDefault: "off"(仅最终回复)。
*.blockStreaming 设置为 true,区块流式默认关闭。频道可以流式发送实时预览(channels.<频道>.streaming),无区块回复。
配置位置提示:blockStreaming* 默认值位于 agents.defaults 下,而非根配置。
预览流式模式
标准配置键:channels.<channel>.streaming
模式:
off:禁用预览流式。partial:单一预览消息,持续替换为最新文本。block:预览消息以分块追加更新。progress:生成中显示进度/状态预览,完成显示最终答案。
频道映射
| 频道 | off | partial | block | progress |
|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | 映射为 partial |
| Discord | ✅ | ✅ | ✅ | 映射为 partial |
| Slack | ✅ | ✅ | ✅ | ✅ |
channels.slack.nativeStreaming用于当streaming=partial时,切换 Slack 原生流式 API 调用(默认:true)。
- Telegram:
streamMode+ 布尔型streaming自动迁移至streaming枚举。 - Discord:
streamMode+ 布尔型streaming自动迁移至streaming枚举。 - Slack:
streamMode自动迁移至streaming枚举;布尔型streaming自动迁移至nativeStreaming。
运行时行为
Telegram:- 在私聊时使用 Bot API 的
sendMessageDraft(如果可用),群组/主题使用sendMessage+editMessageText实现预览更新。 - 明确启用 Telegram 区块流式时,跳过预览流式(避免双重流式)。
/reasoning stream可将推理写入预览。
- 使用发送 + 编辑预览消息。
block模式使用草稿分块(draftChunk)。- 明确启用 Discord 区块流式时,跳过预览流式。
partial模式时,如果可用,使用 Slack 原生流式接口(chat.startStream/append/stop)。block使用追加式草稿预览。progress先显示状态预览文本,随后显示最终答案。