Skip to content

流式传输 + 分块

OpenClaw 有两个独立的"流式传输"层:

  • 块流式传输(频道): 在助手写入时发出完整的。这些是正常的频道消息(不是 token 增量)。
  • 类 Token 流式传输(仅 Telegram): 在生成时用部分文本更新草稿气泡;最终消息在结束时发送。

目前没有真正的 token 流式传输到外部频道消息。Telegram 草稿流式传输是唯一的部分流式传输界面。

块流式传输(频道消息)

块流式传输在输出可用时以粗粒度块发送助手输出。

Model output
  └─ text_delta/events
       ├─ (blockStreamingBreak=text_end)
       │    └─ chunker emits blocks as buffer grows
       └─ (blockStreamingBreak=message_end)
            └─ chunker flushes at message_end
                   └─ channel send (block replies)

图例:

  • 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 处拆分。
  • 断点偏好: paragraphnewlinesentencewhitespace → 硬断点。
  • 代码围栏: 永远不在围栏内拆分;当在 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"(边生成边发出)。非 Telegram 频道还需要 *.blockStreaming: true
  • 最后流式传输全部: blockStreamingBreak: "message_end"(刷新一次,如果很长可能有多个块)。
  • 无块流式传输: blockStreamingDefault: "off"(仅最终回复)。

频道注意: 对于非 Telegram 频道,块流式传输默认关闭,除非*.blockStreaming 明确设置为 true。Telegram 可以在没有块回复的情况下流式传输草稿 (channels.telegram.streamMode)。

配置位置提醒: blockStreaming* 默认值位于 agents.defaults 下,而不是根配置。

Telegram 草稿流式传输(类 token)

Telegram 是唯一具有草稿流式传输的频道:

  • 带主题的私聊中使用 Bot API sendMessageDraft
  • channels.telegram.streamMode: "partial" | "block" | "off"
    • partial: 用最新的流文本更新草稿。
    • block: 以分块块更新草稿(相同的分块器规则)。
    • off: 无草稿流式传输。
  • 草稿块配置(仅用于 streamMode: "block"): channels.telegram.draftChunk(默认值: minChars: 200,maxChars: 800)。
  • 草稿流式传输与块流式传输分离;块回复默认关闭,仅在非 Telegram 频道上由 *.blockStreaming: true 启用。
  • 最终回复仍然是正常消息。
  • /reasoning stream 将推理写入草稿气泡(仅 Telegram)。

当草稿流式传输活动时,OpenClaw 禁用该回复的块流式传输以避免双重流式传输。

Telegram (private + topics)
  └─ sendMessageDraft (draft bubble)
       ├─ streamMode=partial → update latest text
       └─ streamMode=block   → chunker updates draft
  └─ final reply → normal message

图例:

  • sendMessageDraft: Telegram 草稿气泡(不是真实消息)。
  • final reply: 正常 Telegram 消息发送。