跳到主要内容

流式传输 + 分段

Clawdbot 有两个独立的“流式传输”层:

  • 块流式传输 (Block streaming,频道): 在助手写作时,以已完成的块 (blocks) 为单位发出回复。这些是正常的频道消息(不是 Token 增量)。
  • Token 风格流式传输 (仅限 Telegram): 在生成过程中,用部分文本更新草稿泡泡 (draft bubble);最终消息在结束时发送。

目前没有真正意义上的 Token 流式传输到外部频道消息。Telegram 草稿流是唯一的部分文本流式显示界面。

块流式传输 (频道消息)

块流式传输在助手的输出块可用时,分批发送这些粗颗粒度的内容。

模型输出
└─ text_delta/events
├─ (blockStreamingBreak=text_end)
│ └─ 分段器 (chunker) 随着缓冲区增长发出块
└─ (blockStreamingBreak=message_end)
└─ 分段器在消息结束 (message_end) 时刷新
└─ 频道发送 (块回复)

图例:

  • text_delta/events: 模型流事件(对于非流式模型可能比较稀疏)。
  • chunker: EmbeddedBlockChunker 应用最小/最大边界 + 分割偏好。
  • channel send: 实际的出站消息(块回复)。

控制项:

  • agents.defaults.blockStreamingDefault: "on"/"off" (默认 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 实现:

  • 低边界 (Low bound): 除非强制刷新,否则在缓冲区长度达到 minChars 之前不发出内容。
  • 高边界 (High bound): 优先在 maxChars 之前进行分割;如果强制分割,则在 maxChars 处分割。
  • 分割偏好 (Break preference): paragraph (段落) → newline (换行) → sentence (句子) → whitespace (空格) → 硬分割。
  • 代码围栏 (Code fences): 绝不在围栏内部进行分割;如果在 maxChars 处强制分割,会先关闭围栏再在下一段重新开启,以保持 Markdown 语法正确。

maxChars 会被限制在频道的 textChunkLimit 之内,因此不会超过频道的字符上限。

合并 (Coalescing,合并流式块)

启用块流式传输时,Clawdbot 可以在发出前合并连续的块分段。这减少了“单行刷屏”,同时仍能提供渐进式的输出。

  • 合并会等待空闲间隙 (idleMs) 后再刷新。
  • 缓冲区受 maxChars 限制,超过则刷新。
  • minChars 防止发送过小的片段,直到累积了足够的文本(最终刷新始终会发送剩余文本)。
  • 连接符源自 blockStreamingChunk.breakPreference (paragraph\n\n, newline\n, sentence → 空格)。
  • 可通过 *.blockStreamingCoalesce 进行频道覆盖(包括各账号配置)。
  • 默认的合并 minChars 在 Signal/Slack/Discord 上被调高至 1500(除非被覆盖)。

块回复之间的人性化节奏

启用块流式传输时,你可以在块回复之间(从第二个块开始)添加随机停顿。这使多气泡回复感觉更自然。

  • 配置: agents.defaults.humanDelay (可通过 agents.list[].humanDelay 按 Agent 覆盖)。
  • 模式: off (默认), natural (800–2500ms), custom (minMs/maxMs)。
  • 仅适用于块回复,不适用于最终回复或工具调用摘要。

“流式发送分段还是发送全部”

这对应于:

  • 流式发送分段 (Stream chunks): blockStreamingDefault: "on" + blockStreamingBreak: "text_end" (边写边发)。非 Telegram 频道还需要设置 *.blockStreaming: true
  • 结束时流式发送全部 (Stream everything at end): 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)。

当草稿流处于活动状态时,Clawdbot 会禁用该次回复的块流式传输,以避免重复发送。

Telegram (私聊 + 话题)
└─ sendMessageDraft (草稿泡泡)
├─ streamMode=partial → 更新最新文本
└─ streamMode=block → 分段器更新草稿
└─ 最终回复 → 普通消息

图例:

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