流式传输 + 分块
OpenClaw 有两个独立的"流式传输"层:
- 块流式传输(通道): 在助手写入时发出完成的块。这些是正常通道消息(不是令牌增量)。
- 类令牌流式传输(仅 Telegram): 在生成时用部分文本更新草稿气泡;最终消息在结束时发送。
今天没有真正的令牌流式传输到外部通道消息。Telegram 草稿流式传输是唯一的部分流表面。
块流式传输(通道消息)
块流式传输在输出可用时以粗粒度块发送助手输出。
模型输出
└─ text_delta/events
├─ (blockStreamingBreak=text_end)
│ └─ 分块器在缓冲区增长时发出块
└─ (blockStreamingBreak=message_end)
└─ 分块器在 message_end 时刷新
└─ 通道发送(块回复)图例:
text_delta/events:模型流事件(非流式模型可能稀疏)。chunker:EmbeddedBlockChunker应用最小/最大边界 + 断点偏好。channel send:实际出站消息(块回复)。
控制:
agents.defaults.blockStreamingDefault:"on"/"off"(默认关闭)。- 通道覆盖:
*.blockStreaming(和每账户变体)强制每个通道"on"/"off"。 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:等待助手消息完成,然后刷新缓冲输出。
当缓冲区文本超过 maxChars 时 message_end 仍使用分块器,因此它可以在结束时发出多个块。
分块算法(低/高边界)
块分块由 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(包括每账户配置)获得。 - 默认合并
minChars对于 Signal/Slack/Discord 增加到 1500,除非覆盖。
块之间类似人的节奏
当块流式传输启用时,你可以在块回复之间添加随机暂停(第一个块之后)。这使多气泡响应感觉更自然。
- 配置:
agents.defaults.humanDelay(通过agents.list[].humanDelay每智能体覆盖)。 - 模式:
off(默认)、natural(800–2500ms)、custom(minMs/maxMs)。 - 仅适用于块回复,不适用于最终回复或工具摘要。
"流式传输块还是全部"
这映射到:
- 流式传输块:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(边走边 emit)。非 Telegram 通道也需要*.blockStreaming: true。 - 最后流式传输全部:
blockStreamingBreak: "message_end"(一次刷新,可能多个块如果非常长)。 - 无块流式传输:
blockStreamingDefault: "off"(仅最终回复)。
通道注意: 对于非 Telegram 通道,块流式传输关闭除非 *.blockStreaming 显式设置为 true。Telegram 可以在没有块回复的情况下流式传输草稿(channels.telegram.streamMode)。
配置位置提醒:blockStreaming* 默认位于 agents.defaults 下,不是根配置。
Telegram 草稿流式传输(类令牌)
Telegram 是唯一具有草稿流式传输的通道:
- 在带有主题的私信中使用 Bot API
sendMessageDraft。 channels.telegram.streamMode: "partial" | "block" | "off"。partial:用最新流式文本更新草稿。block:用分块块更新草稿(相同分块器规则)。off:无草稿流式传输。
- 草稿分块配置(仅用于
streamMode: "block"):channels.telegram.draftChunk(默认:minChars: 200,maxChars: 800)。 - 草稿流式传输与块流式传输分离;默认关闭块回复,仅通过
*.blockStreaming: true在非 Telegram 通道上启用。 - 最终回复仍是正常消息。
/reasoning stream将推理写入草稿气泡(仅限 Telegram)。
当草稿流式传输活动时,OpenClaw 为该回复禁用块流式传输以避免双重流式传输。
Telegram(私信 + 主题)
└─ sendMessageDraft(草稿气泡)
├─ streamMode=partial → 更新最新文本
└─ streamMode=block → 分块器更新草稿
└─ 最终回复 → 正常消息图例:
sendMessageDraft:Telegram 草稿气泡(不是真实消息)。最终回复:正常 Telegram 消息发送。