Streaming + 分块
OpenClaw 有两个独立的 “Streaming” 层:
- 块 Streaming (Channel): 在助手写入时发出完整的块。这些是普通的 Channel 消息(不是 Token 增量)。
- 类 Token Streaming (仅 Telegram): 在生成时用部分文本更新草稿气泡;最终消息在结束时发送。
目前没有真正的 Token Streaming 到外部 Channel 消息。Telegram 草稿 Streaming 是唯一的部分流式传输界面。
块 Streaming (Channel 消息)
块 Streaming 在助手输出可用时以粗粒度块的形式发送。
模型输出
└─ text_delta/events
├─ (blockStreamingBreak=text_end)
│ └─ chunker 在缓冲区增长时发出块
└─ (blockStreamingBreak=message_end)
└─ chunker 在 message_end 时刷新
└─ channel send (块回复)
图例:
text_delta/events: 模型流事件(对于非流式模型可能稀疏)。chunker:EmbeddedBlockChunker应用最小/最大边界 + 断点偏好。channel send: 实际的出站消息(块回复)。
控制选项:
agents.defaults.blockStreamingDefault:"on"/"off"(默认关闭)。- Channel 覆盖:
*.blockStreaming(以及每账户变体)来强制每个 Channel 的"on"/"off"。 agents.defaults.blockStreamingBreak:"text_end"或"message_end"。agents.defaults.blockStreamingChunk:{ minChars, maxChars, breakPreference? }。agents.defaults.blockStreamingCoalesce:{ minChars?, maxChars?, idleMs? }(在发送前合并流式块)。- Channel 硬上限:
*.textChunkLimit(例如channels.whatsapp.textChunkLimit)。 - Channel 分块模式:
*.chunkMode(length默认,newline在长度分块前按空行(段落边界)拆分)。 - Discord 软上限:
channels.discord.maxLinesPerMessage(默认 17) 拆分高回复以避免 UI 裁剪。
边界语义:
text_end: 一旦 chunker 发出就流式传输块;在每个text_end时刷新。message_end: 等到助手消息完成,然后刷新缓冲输出。
message_end 如果缓冲文本超过 maxChars,仍会使用 chunker,所以它可以在最后发出多个块。
分块算法(下限/上限)
块分块由 EmbeddedBlockChunker 实现:
- 下限: 在缓冲区 >=
minChars之前不发出(除非强制)。 - 上限: 优先在
maxChars之前拆分;如果强制,在maxChars处拆分。 - 断点偏好:
paragraph→newline→sentence→whitespace→ 硬断点。 - 代码围栏: 永远不在围栏内拆分;当在
maxChars处强制时,关闭 + 重新打开围栏以保持 Markdown 有效。
maxChars 被限制在 Channel 的 textChunkLimit,所以你不能超过每个 Channel 的上限。
合并(合并流式块)
当启用块 Streaming 时,OpenClaw 可以在发送前合并连续的块。这减少了”单行垃圾信息”,同时仍提供渐进式输出。
- 合并在刷新前等待空闲间隙 (
idleMs)。 - 缓冲区被
maxChars限制,如果超过会刷新。 minChars防止微小片段发送,直到积累足够的文本(最终刷新总是发送剩余文本)。- 连接符从
blockStreamingChunk.breakPreference派生(paragraph→\n\n,newline→\n,sentence→ 空格)。 - Channel 覆盖可通过
*.blockStreamingCoalesce获得(包括每账户配置)。 - 对于 Signal/Slack/Discord,默认合并
minChars提升到 1500,除非被覆盖。
块之间的类人节奏
当启用块 Streaming 时,你可以在块回复之间(第一个块之后)添加随机暂停。这使多气泡响应感觉更自然。
- 配置:
agents.defaults.humanDelay(通过agents.list[].humanDelay覆盖每个 Agent)。 - 模式:
off(默认),natural(800–2500ms),custom(minMs/maxMs)。 - 仅适用于块回复,不适用于最终回复或工具摘要。
“流式传输块或全部”
这对应于:
- 流式传输块:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(边生成边发出)。非 Telegram Channel 还需要*.blockStreaming: true。 - 在结束时流式传输全部:
blockStreamingBreak: "message_end"(一次刷新,如果很长可能有多个块)。 - 无块 Streaming:
blockStreamingDefault: "off"(仅最终回复)。
Channel 注意: 对于非 Telegram Channel,块 Streaming 默认关闭,除非 *.blockStreaming 显式设置为 true。Telegram 可以在没有块回复的情况下流式传输草稿(channels.telegram.streamMode)。
配置位置提醒: blockStreaming* 默认值位于 agents.defaults 下,而不是根配置。
Telegram 草稿 Streaming (类 Token)
Telegram 是唯一具有草稿 Streaming 的 Channel:
- 在带主题的私聊中使用 Bot API
sendMessageDraft。 channels.telegram.streamMode: "partial" | "block" | "off"。partial: 用最新的流文本更新草稿。block: 以分块块更新草稿(相同的 chunker 规则)。off: 无草稿 Streaming。
- 草稿块配置(仅用于
streamMode: "block"):channels.telegram.draftChunk(默认:minChars: 200,maxChars: 800)。 - 草稿 Streaming 与块 Streaming 分离;块回复默认关闭,仅通过非 Telegram Channel 上的
*.blockStreaming: true启用。 - 最终回复仍然是普通消息。
/reasoning stream将推理写入草稿气泡(仅 Telegram)。
当草稿 Streaming 激活时,OpenClaw 禁用该回复的块 Streaming 以避免双重流式传输。
Telegram (私聊 + 主题)
└─ sendMessageDraft (草稿气泡)
├─ streamMode=partial → 更新最新文本
└─ streamMode=block → chunker 更新草稿
└─ final reply → 普通消息
图例:
sendMessageDraft: Telegram 草稿气泡(不是真实消息)。final reply: 普通 Telegram 消息发送。