Skip to content

Streaming + chunking

Moltbot 有两层彼此独立的“streaming”:

  • Block streaming(channels):当 assistant 生成内容时,按完成的 blocks 逐段发出。这些是普通的渠道消息(不是 token deltas)。
  • Token-ish streaming(仅 Telegram):在生成过程中,用部分文本更新一个 draft bubble;结束时再发送最终消息。

目前对外部渠道消息来说,并不存在真正的 token streaming。Telegram 的 draft streaming 是唯一的“部分流式”对外表面。

Block streaming(渠道消息)

Block streaming 会把 assistant 输出以较粗的分块方式在可用时发送出去。

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:模型的流事件(对非 streaming 模型可能很稀疏)。
  • chunkerEmbeddedBlockChunker,应用 min/max 边界 + break 偏好。
  • channel send:实际向外发送的消息(block replies)。

控制项:

  • agents.defaults.blockStreamingDefault"on"/"off"(默认 off)。
  • 渠道覆盖:*.blockStreaming(以及每账号的变体)用于按渠道强制 "on"/"off"
  • agents.defaults.blockStreamingBreak"text_end""message_end"
  • agents.defaults.blockStreamingChunk{ minChars, maxChars, breakPreference? }
  • agents.defaults.blockStreamingCoalesce{ minChars?, maxChars?, idleMs? }(发送前合并流式 blocks)。
  • 渠道硬上限:*.textChunkLimit(例如 channels.whatsapp.textChunkLimit)。
  • 渠道分块模式:*.chunkMode(默认 lengthnewline 会先按空行(段落边界)拆分,再做长度分块)。
  • Discord 软上限:channels.discord.maxLinesPerMessage(默认 17)会拆分“过高”的回复以避免 UI 裁切。

边界语义:

  • text_end:chunker 一产出 block 就立刻发送;每个 text_end 都会触发 flush。
  • message_end:等 assistant 消息完成后,再一次性 flush 缓冲内容。

即使使用 message_end,当缓冲文本超过 maxChars 时仍会使用 chunker,因此可能在结尾一次性发出多个 chunks。

分块算法(低/高边界)

Block chunking 由 EmbeddedBlockChunker 实现:

  • 低边界(Low bound):buffer < minChars 时不输出(除非强制)。
  • 高边界(High bound):尽量在 maxChars 之前找分割点;若被迫则在 maxChars 硬切。
  • 断点偏好(Break preference)paragraphnewlinesentencewhitespace → 硬断。
  • 代码围栏(Code fences):绝不在围栏内部拆分;当被迫在 maxChars 处硬切时,会先关闭再重开围栏,以保持 Markdown 合法。

maxChars 会被 clamp 到渠道的 textChunkLimit,因此不能超过每渠道上限。

Coalescing(合并连续 blocks)

当启用 block streaming 时,Moltbot 可以在发送前合并连续的 block chunks。 这能减少“一行一条消息”的刷屏,同时仍提供渐进式输出。

  • Coalescing 会等待空闲间隔idleMs)后再 flush。
  • buffer 有 maxChars 上限,超过就会立即 flush。
  • minChars 会阻止太小的碎片被发送,直到累积到足够长度(最终 flush 总会发送剩余文本)。
  • 连接符(joiner)来自 blockStreamingChunk.breakPreferenceparagraph\n\nnewline\nsentence → 空格)。
  • 渠道也可通过 *.blockStreamingCoalesce(含按账号配置)覆盖。
  • 对 Signal/Slack/Discord,默认 coalesce 的 minChars 会提升到 1500(除非覆盖)。

blocks 之间更像人类的节奏

启用 block streaming 后,你可以在 block replies 之间加入随机暂停(从第二个 block 开始)。这会让多气泡回复更自然。

  • 配置:agents.defaults.humanDelay(可在 agents.list[].humanDelay 里按 agent 覆盖)。
  • 模式:off(默认)、natural(800–2500ms)、customminMs/maxMs)。
  • 只作用于 block replies,不作用于最终回复或 tool summaries。

“流式分块还是一次性发完”

其对应关系为:

  • 流式分块(Stream chunks)blockStreamingDefault: "on" + blockStreamingBreak: "text_end"(边生成边发)。非 Telegram 渠道还需要显式设置 *.blockStreaming: true
  • 末尾一次性发完(Stream everything at end)blockStreamingBreak: "message_end"(结尾 flush 一次;很长时可能分多个 chunks)。
  • 不做 block streamingblockStreamingDefault: "off"(只发最终回复)。

**渠道注意:**对非 Telegram 渠道,除非显式设置 *.blockStreamingtrue,否则 block streaming 默认关闭。Telegram 可以在不发送 block replies 的情况下进行 draft streaming(channels.telegram.streamMode)。

配置位置提示:blockStreaming* 的 defaults 位于 agents.defaults,而不是根配置。

Telegram draft streaming(token-ish)

Telegram 是唯一支持 draft streaming 的渠道:

  • 带 topics 的私聊中使用 Bot API sendMessageDraft
  • channels.telegram.streamMode: "partial" | "block" | "off"
    • partial:用最新的流文本更新 draft。
    • block:以分块 blocks 的方式更新 draft(同一套 chunker 规则)。
    • off:不启用 draft streaming。
  • Draft 分块配置(仅 streamMode: "block" 时生效):channels.telegram.draftChunk(默认:minChars: 200maxChars: 800)。
  • Draft streaming 与 block streaming 相互独立;block replies 默认关闭,且对非 Telegram 渠道仅在 *.blockStreaming: true 时启用。
  • 最终回复仍然是普通消息。
  • /reasoning stream 会把 reasoning 写入 draft bubble(仅 Telegram)。

当 draft streaming 处于激活状态时,Moltbot 会为该条回复禁用 block streaming,以避免双重 streaming。

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

图例:

  • sendMessageDraft:Telegram 的 draft bubble(不是真实消息)。
  • final reply:普通 Telegram 消息发送。