串流 + 分塊

OpenClaw 有兩個獨立的串流層:

  • 區塊串流(頻道): 在助理撰寫過程中發送已完成的區塊。這些是一般的頻道訊息(不是 Token 差異)。
  • 預覽串流(Telegram/Discord/Slack): 在生成過程中更新一則暫時的預覽訊息

目前沒有真正的 Token 差異串流到頻道訊息。預覽串流是基於訊息的(傳送 + 編輯/附加)。

區塊串流(頻道訊息)

區塊串流在助理輸出可用時,以粗粒度的區塊傳送。

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:模型串流事件(非串流模型的事件可能較稀疏)。
  • 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 → 硬切分。
  • 程式碼區塊(Code fence): 絕不在 fence 內部切分;被強制在 maxChars 處切分時,會關閉再重新開啟 fence 以保持 Markdown 格式正確。

maxChars 受頻道 textChunkLimit 限制,因此不會超過各頻道的上限。

合併(合併已串流的區塊)

啟用區塊串流時,OpenClaw 可以在傳送前合併連續的區塊片段。這能減少「單行刷屏」的現象,同時仍提供漸進式輸出。

  • 合併會等待閒置間隔idleMs)後才清空。
  • 緩衝區受 maxChars 限制,超過時會清空。
  • minChars 防止過小的片段被傳送,直到累積足夠文字(最終清空時一定會傳送剩餘文字)。
  • 連接符號依 blockStreamingChunk.breakPreference 決定(paragraph\n\nnewline\nsentence → 空格)。
  • 頻道覆蓋可透過 *.blockStreamingCoalesce(含各帳號設定)進行。
  • Signal/Slack/Discord 的預設合併 minChars 會提高到 1500,除非另有覆蓋。

區塊間的擬人化節奏

啟用區塊串流時,你可以在區塊回覆之間(第一個區塊之後)加入隨機停頓。這讓多氣泡回覆的節奏更自然。

  • 設定:agents.defaults.humanDelay(依 Agent 覆蓋:agents.list[].humanDelay)。
  • 模式: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 下,不在根設定中。

預覽串流模式

標準 Key:channels.<channel>.streaming

模式:

  • off:停用預覽串流。
  • partial:單一預覽,以最新文字取代。
  • block:預覽以分塊/附加方式更新。
  • progress:生成期間顯示進度/狀態預覽,完成時顯示最終答案。

頻道對應表

頻道offpartialblockprogress
Telegram對應為 partial
Discord對應為 partial
Slack

Slack 專屬:

  • channels.slack.nativeStreamingstreaming=partial 時切換是否使用 Slack 原生串流 API 呼叫(預設:true)。

舊版 Key 遷移:

  • 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 使用狀態預覽文字,然後是最終答案。