Skip to content

流式输出与分块(Streaming + Chunking)

OpenClaw 有两套独立的流式层:

  • 区块流式(Block Streaming):助手写作过程中以完整的区块为单位向频道发送消息,是正常的频道消息(不是 token 增量)。
  • 预览流式(Preview Streaming,适用于 Telegram / Discord / Slack):生成过程中更新一条临时预览消息

目前没有真正的 token 级 delta 流式推送到频道消息。预览流式基于消息(发送 + 编辑/追加)实现。

区块流式(频道消息)

区块流式在输出可用时以粗粒度分块发送助手内容。

Model output
  └─ text_delta/events
       ├─ (blockStreamingBreak=text_end)
       │    └─ chunker 随缓冲区增长输出区块
       └─ (blockStreamingBreak=message_end)
            └─ chunker 在 message_end 时刷新
                   └─ channel send(区块回复)

说明:

  • text_delta/events:模型流事件(非流式模型可能较稀疏)。
  • chunkerEmbeddedBlockChunker,应用最小/最大边界和换行偏好。
  • channel send:实际出站消息(区块回复)。

控制参数:

  • 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? }(发送前合并区块)。
  • 频道硬上限:*.textChunkLimit(如 channels.whatsapp.textChunkLimit)。
  • 频道分块模式:*.chunkMode(默认 lengthnewline 在段落边界先按空行分块再按长度分块)。
  • Discord 软上限:channels.discord.maxLinesPerMessage(默认 17),超高回复拆分以避免 UI 裁剪。

边界语义:

  • text_end:chunker 一发出就立即推送区块,每次 text_end 刷新一次。
  • message_end:等待助手消息结束后一次性刷新缓冲输出。

message_end 当缓冲文本超过 maxChars 时仍会使用 chunker,因此末尾可能产生多个分块。

分块算法(低/高水位线)

区块分块由 EmbeddedBlockChunker 实现:

  • 低水位线:缓冲 < minChars 时不输出(除非强制)。
  • 高水位线:优先在 maxChars 之前找合适的断点;强制时在 maxChars 截断。
  • 换行偏好paragraphnewlinesentencewhitespace → 硬截断。
  • 代码块保护:绝不在代码围栏内截断;强制在 maxChars 截断时,关闭并重新打开围栏以保持 Markdown 合法。

maxChars 会被钳制到频道的 textChunkLimit,不能超过每频道上限。

合并(合并流式区块)

开启区块流式后,OpenClaw 可以在发送前合并连续的区块,既减少"单行刷屏",又保留渐进式输出效果。

  • 合并等待空闲间隔idleMs)后再刷新。
  • 缓冲上限为 maxChars,超出即刷新。
  • minChars 防止过小的片段发送,直到积累足够文本(最终刷新时发送剩余内容)。
  • 连接符由 blockStreamingChunk.breakPreference 决定(paragraph\n\nnewline\nsentence → 空格)。
  • 可通过 *.blockStreamingCoalesce 进行频道级覆盖(含每账号配置)。
  • Signal / Slack / Discord 的默认合并 minChars 提升至 1500,除非覆盖。

仿人类节奏(区块间延迟)

开启区块流式后,可在区块回复之间添加随机停顿(首块之后),让多气泡回复更自然——就像一只真实的小龙虾在思考后才夹出下一段话。

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

"流式分块 vs 全量发送"映射

  • 流式分块blockStreamingDefault: "on" + blockStreamingBreak: "text_end"(边生成边发)。非 Telegram 频道还需要 *.blockStreaming: true
  • 结束后一次发完blockStreamingBreak: "message_end"(一次刷新,长文本可能产生多个分块)。
  • 无区块流式blockStreamingDefault: "off"(只发最终回复)。

频道说明:除非显式设置 *.blockStreaming: true,否则区块流式默认关闭。频道可以在不开启区块回复的情况下使用实时预览(channels.<channel>.streaming)。

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

预览流式模式

配置键:channels.<channel>.streaming

模式:

  • off:关闭预览流式。
  • partial:单条预览,持续替换为最新文本。
  • block:以分块/追加方式更新预览。
  • progress:生成期间显示进度/状态预览,完成后发出最终答案。

各频道支持情况

频道offpartialblockprogress
Telegram映射为 partial
Discord映射为 partial
Slack

仅 Slack:

  • channels.slack.nativeStreamingstreaming=partial 时切换 Slack 原生流式 API(默认 true)。

旧版配置迁移:

  • Telegram:streamMode + 布尔值 streaming 自动迁移为 streaming 枚举。
  • Discord:streamMode + 布尔值 streaming 自动迁移为 streaming 枚举。
  • Slack:streamMode 自动迁移为 streaming 枚举;布尔值 streaming 自动迁移为 nativeStreaming

运行时行为

Telegram:

  • 在私聊和群组/话题中使用 sendMessage + editMessageText 更新预览。
  • 当 Telegram 区块流式显式开启时跳过预览流式(避免双重流式)。
  • /reasoning stream 可将推理过程写入预览。

Discord:

  • 使用发送 + 编辑方式更新预览消息。
  • block 模式使用草稿分块(draftChunk)。
  • 当 Discord 区块流式显式开启时跳过预览流式。

Slack:

  • partial 可使用 Slack 原生流式(chat.startStream/append/stop)。
  • block 使用追加式草稿预览。
  • progress 使用状态预览文本,完成后发出最终答案。