> ## Documentation Index
> Fetch the complete documentation index at: https://openclaw.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 流式传输与分块

OpenClaw 有两个独立的流式层，并且当前**没有真正的
令牌增量流式传输**到频道消息：

* **区块流式传输（频道）：** 在助手
  写入时发出已完成的**区块**。这些是普通的频道消息，不是令牌增量。
* **预览流式传输（Telegram/Discord/Slack/Matrix/Mattermost/MS Teams）：**
  在生成过程中更新一个临时的**预览消息**（发送 + 编辑/追加）。

## 控制 UI 启动状态

在 `chat.send` 确认一个活动运行后，在助理文本或工具活动可见之前，网关可以发送一个带类型的、粗粒度的启动状态。控制 UI 会在工作指示器旁显示此状态，包含工作区准备、环境配置、上下文准备和模型启动等阶段。

第一次助理增量或工具启动会永久替换该运行的启动状态。在工具等待操作者操作时，审批状态优先。工作树创建和初始云端派发发生在聊天运行存在之前，因此它们在运行前的 RPC 进度不会作为运行启动状态呈现；环境配置仅在活动运行重新配置已回收的工作节点时才会出现在这里。

## 区块流式传输（频道消息）

区块流式传输会在助手输出可用时，以较粗粒度的块发送。

```text theme={"theme":{"light":"min-light","dark":"min-dark"}}
模型输出
  └─ text_delta/events
       ├─ (blockStreamingBreak=text_end)
       │    └─ chunker 随着缓冲区增长发出区块
       └─ (blockStreamingBreak=message_end)
            └─ chunker 在 message_end 时刷新
                   └─ 频道发送（区块回复）
```

* `text_delta/events`：模型流事件（对于非流式模型，可能是稀疏的）。
* `chunker`：`EmbeddedBlockChunker`，应用最小／最大边界＋中断偏好。
* `channel send`：实际的出站消息（区块回复）。

**控制项**（除非另有说明，均位于 `agents.defaults` 下）：

| Key                                                       | Values / shape                                 | Default    |
| --------------------------------------------------------- | ---------------------------------------------- | ---------- |
| `blockStreamingDefault`                                   | `"on"`／`"off"`                                 | `"off"`    |
| `blockStreamingBreak`                                     | `"text_end"`／`"message_end"`                   | -          |
| `blockStreamingChunk`                                     | `{ minChars, maxChars, breakPreference? }`     | -          |
| `blockStreamingCoalesce`                                  | `{ minChars?, maxChars?, idleMs? }`（发送前合并流式区块） | -          |
| `*.streaming.block.enabled`（频道覆盖）                         | `true`／`false`，按频道（以及按账户）强制启用区块流式传输            | -          |
| `*.textChunkLimit`（例如 `channels.whatsapp.textChunkLimit`） | number，硬上限                                     | 4000       |
| `*.streaming.chunkMode`                                   | `"length"`／`"newline"`                         | `"length"` |
| `channels.discord.maxLinesPerMessage`                     | number，软行数上限，用于拆分过高的回复以避免 UI 裁剪                | 17         |

`streaming.chunkMode: "newline"` 会按空白行（段落边界）拆分，
而不是每一行；当文本超过限制后，再回退到按长度分块。

捆绑频道将这些覆盖项写作
`channels.<id>.streaming.{chunkMode,block.enabled,block.coalesce}`。扁平形式的
`*.chunkMode`／`*.blockStreaming`／`*.blockStreamingCoalesce` 在任何地方都会被拒绝。
`openclaw doctor --fix` 会将旧版配置迁移为嵌套形式。

**`blockStreamingBreak` 的边界语义**：

* `text_end`：一旦 chunker 发出区块就立即流式发送；每次 `text_end` 都刷新。
* `message_end`：等助手消息结束后，再刷新缓冲输出。若缓冲文本超过 `maxChars`，仍会使用 chunker，因此在结束时可以发出多个区块。

### 使用区块流式传输的媒体投递

流式媒体必须使用结构化载荷字段，例如 `mediaUrl` 或 `mediaUrls`；流式文本不会被解析为附件命令。当区块流式传输较早发送媒体时，OpenClaw 会记住该轮投递。如果最终的助手载荷重复了相同的媒体 URL，最终投递会去除重复媒体，而不是再次发送附件。

完全重复的最终载荷会被抑制。如果最终载荷在已经流式发送过的媒体周围加入了不同的文本，OpenClaw 仍会发送新文本，同时保持媒体只投递一次。这可以防止 Telegram 等频道中重复出现语音笔记或文件。

## 分块算法（低/高边界）

区块分块由 `EmbeddedBlockChunker` 实现：

* **低边界：** 缓冲区未达到 `minChars` 前不输出（除非被强制）。
* **高边界：** 优先在 `maxChars` 之前进行切分；如果被强制，则在 `maxChars` 处切分。
* **断点偏好链：** `paragraph` -> `newline` -> `sentence` ->
  空白符 -> 强制断开。
* **代码围栏：** 永远不要在围栏内部切分；当在 `maxChars` 处被强制切分时，关闭
  并重新打开围栏，以保持 Markdown 有效。

`maxChars` 会被限制为频道的 `textChunkLimit`，因此你不能超过
每个频道的上限。

## 合并（合并已流式区块）

当启用区块流式传输时，OpenClaw 可以在发送前**合并连续的区块
片段**，在保持渐进式输出的同时减少单行刷屏。

* 合并会在刷新前等待**空闲间隔**（`idleMs`）。
* 缓冲区会受 `maxChars` 限制，并在超过时立即刷新。
* `minChars` 可防止过小的片段过早发送，直到累积到足够文本
  （最终刷新始终会发送剩余文本）。
* 连接符由 `blockStreamingChunk.breakPreference` 决定：`paragraph` ->
  `\n\n`，`newline` -> `\n`，`sentence` -> 空格。
* 可通过 `*.streaming.block.coalesce` 进行频道覆盖（包括
  按账户配置）。
* Discord、Signal 和 Slack 的默认合并配置为 `{ minChars: 1500, idleMs: 1000 }`
  ，除非被覆盖。

## 区块之间的人性化节奏

当启用区块流式传输时，在第一个区块之后，在区块回复之间添加一个**随机暂停**，让多气泡回复感觉更自然。

| `agents.defaults.humanDelay.mode` | 行为              |
| --------------------------------- | --------------- |
| `off`（默认）                         | 无暂停             |
| `natural`                         | 800-2500 毫秒随机暂停 |
| `custom`                          | `minMs`/`maxMs` |

可通过 `agents.entries.*.humanDelay` 为每个代理单独覆盖。仅适用于**区块回复**，不适用于最终回复或工具摘要。

## “流式分块还是一次全部输出”

* **流式分块：** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`
  （边生成边输出）。非 Telegram 渠道还需要
  `*.streaming.block.enabled: true`。
* **在末尾一次性输出全部内容：** `blockStreamingBreak: "message_end"`（一次
  刷出，内容很长时可能会分成多个块）。
* **不进行分块流式输出：** `blockStreamingDefault: "off"`（仅最终回复）。

分块流式输出遵循 `agents.defaults.blockStreamingDefault`，除非某个渠道或账户显式设置了 `*.streaming.block.enabled`。QQ Bot 没有 `streaming.block` 相关键，并且会进行分块回复流式输出，除非 `channels.qqbot.streaming.mode` 为 `"off"`。渠道可以流式传输实时预览（`channels.<channel>.streaming.mode`），而不发送分块回复。`blockStreaming*` 默认值位于 `agents.defaults` 下，而不是配置根目录。

对于 Discord 和 Telegram，显式配置的非 `off` 预览模式优先于继承的 `agents.defaults.blockStreamingDefault: "on"`。当分块回复应覆盖其预览时，将该渠道的 `streaming.block.enabled` 设置为 `true`。如果某一轮对话无法使用预览，继承的分块传递仍会生效。

## 预览流式模式

规范键：`channels.<channel>.streaming`（嵌套 `{ mode, ... }`；旧版顶层布尔值/字符串写法会由 `openclaw doctor --fix` 重写）。

| 模式         | 行为                      |
| ---------- | ----------------------- |
| `off`      | 禁用预览流式传输                |
| `partial`  | 单个预览被最新文本替换             |
| `block`    | 预览以分块/追加步骤更新            |
| `progress` | 生成期间显示进度/状态预览，完成时输出最终答案 |

`streaming.mode: "block"` 是适用于可编辑频道（如 Discord 和 Telegram）的预览流式模式；它本身不会在这些频道中启用频道块投递。正常的块回复请使用 `streaming.block.enabled`。
Microsoft Teams 是个例外：它没有草稿预览块传输，因此 `streaming.mode:
"block"` 会完全禁用原生流式传输，回复会作为普通块投递，而不是原生的 partial/progress 流式传输。Mattermost 也有所不同：在 `block` 模式下，它会在已完成文本和工具活动块之间轮换预览，因此较早的块会作为单独帖子保持可见，而不会在一个可编辑草稿中被覆盖。

### 频道映射

当未设置 `streaming` 时，Discord 默认为 `off`，Telegram 和 Slack 默认为 `progress`，Mattermost 和 MS Teams 默认为 `partial`。

| 频道         | `off` | `partial` | `block` | `progress`         |
| ---------- | ----- | --------- | ------- | ------------------ |
| Telegram   | 是     | 是         | 是       | 可编辑的进度草稿（默认）       |
| Discord    | 是（默认） | 是         | 是       | 可编辑的进度草稿（选择启用）     |
| Slack      | 是     | 是         | 是       | Block Kit 会话卡片（默认） |
| Mattermost | 是     | 是         | 是       | 是                  |
| MS Teams   | 是     | 是         | 是       | 原生进度流              |

预览分块配置（`streaming.preview.chunk.*`，例如在 `channels.discord.streaming` 或 `channels.telegram.streaming` 下）默认值为 `minChars: 200`、`maxChars: 800`（会限制在频道的 `textChunkLimit` 之内），以及 `breakPreference: "paragraph"`。

仅限 Slack：

* `channels.slack.streaming.nativeTransport` 控制当 `channels.slack.streaming.mode="partial"` 时是否调用 Slack 原生流式 API（`chat.startStream`/`chat.appendStream`/`chat.stopStream`）（`nativeTransport` 默认为 `true`）。
* Slack 原生流式传输和 Slack 助手线程状态需要回复线程目标。顶层私信不会显示这种线程式预览，但仍可以使用 Slack 草稿预览帖和编辑。

### 旧键迁移

| 频道       | 旧版键                                               | 状态                                                                                                             |
| -------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Telegram | `streamMode`、标量/布尔值 `streaming`                   | 由 `openclaw doctor --fix` 重写为 `streaming.mode`；运行时不会读取                                                         |
| Discord  | `streamMode`、布尔值 `streaming`                      | 由 `openclaw doctor --fix` 重写为 `streaming.mode`；运行时不会读取                                                         |
| Slack    | `streamMode`；布尔值 `streaming`；旧版 `nativeStreaming` | 由 `openclaw doctor --fix` 重写为 `streaming.mode`（以及布尔值/旧形式对应的 `streaming.nativeTransport`）；运行时不会读取               |
| Matrix   | 标量/布尔值 `streaming`                                | 由 `openclaw doctor --fix` 重写为 `streaming.mode`（包括 Matrix 的 `"quiet"` 模式）；运行时不会读取                               |
| Feishu   | 布尔值 `streaming`                                   | 由 `openclaw doctor --fix` 重写为 `streaming.mode`；运行时不会读取                                                         |
| QQ Bot   | 布尔值 `streaming`；`streaming.c2cStreamApi`          | 由 `openclaw doctor --fix` 重写为 `streaming.mode`（以及布尔值/`c2cStreamApi` 形式对应的 `streaming.nativeTransport`）；运行时不会读取 |

## 运行时行为

### Telegram

* 在私信和群组/话题中，使用 `sendMessage` + `editMessageText` 进行预览更新；最终文本会就地编辑当前预览。Telegram 的临时 30 秒“输入中”草稿（`sendMessageDraft`）不用于答案流式传输。
* 短的初始预览仍会为推送通知体验而进行防抖，但会在有界延迟后呈现，因此活跃运行不会在视觉上保持沉默。
* 长文本最终结果会复用预览消息的第一块，只发送其余分块。
* `block` 模式会在 `streaming.preview.chunk.maxChars` 处将预览轮换为新消息（默认 800，且受 Telegram 4096 字符编辑限制上限约束）；其他模式会将一个预览增长到 4096 字符。
* `progress` 模式会将工具进度保留在可编辑的状态草稿中；当答案流式传输已激活但尚无工具行可用时，会呈现状态标签；完成时清除草稿，并通过常规投递发送最终答案。
* 如果在完成文本被确认之前最终编辑失败，OpenClaw 会使用常规最终投递并清理过期预览。
* 当 Telegram block streaming 被显式启用时，会跳过预览流式传输，以避免双重流式传输。
* `/reasoning stream` 可以将推理写入一个临时预览，该预览会在最终投递后被删除。
* Telegram 选中的引用回复是一个例外：当 `replyToMode` 不是 `"off"` 且存在选中的引用文本时，OpenClaw 会跳过该轮的答案预览流（最终答案必须通过原生引用回复路径），因此工具进度预览行无法渲染。没有选中引用文本的当前消息回复仍会保留预览流。详情请参见 [Telegram 频道文档](/channels/telegram)。

### Discord

* 使用发送 + 编辑预览消息。
* `block` 模式使用草稿分块（`draftChunk`）。
* 当 Discord block streaming 被显式启用时，会跳过预览流式传输。
* `progress` 模式会在最终答案后附加一个小的 `-#` 活动回执（思考/工具调用计数以及耗时），并在该答案送达后删除状态草稿，因此繁忙频道不会在回复上方留下孤立的工具日志。错误类最终结果会保留草稿，作为失败轮次的记录。
* 最终媒体、错误以及显式回复载荷会取消待处理的预览，而不会刷新新的草稿，然后使用常规投递。

### Slack

* 在可用时，`partial` 可以使用 Slack 原生流式传输（`chat.startStream`/`append`/`stop`）。
* `block` 使用追加式草稿预览。
* `progress` 会维护一张实时 Block Kit 会话卡片，将其最终状态设为成功或错误，并始终将助手的最终文本作为单独消息发布。
* 当设置了 `gateway.publicOrigin` 时，终端卡片会包含**在 OpenClaw 中打开**。
  Slack 原生计划/任务流仍需通过 `streaming.progress.nativeTaskCards: true` 选择启用。
* 没有回复线程的顶层私信会使用草稿预览帖和编辑，而不是 Slack 原生流式传输。
* 原生预览流式传输和草稿预览流式传输会抑制该轮的区块回复，因此 Slack 回复只通过一种投递路径进行流式传输。
* 成功且没有可见回复的轮次仍会删除其草稿卡片。失败且没有回复的轮次会保留处于错误状态的卡片。

### Mattermost

* 在 `partial` 模式下，会将思考和部分回复文本流式传输到同一个草稿预览帖子中，并在最终答案可以安全发送时就地完成。
* 在 `progress` 模式下，会将思考和工具活动流式传输到同一个状态预览中，并在最终答案可以安全发送时就地完成。
* 在 `block` 模式下，会在已完成文本和工具活动帖子之间轮换；并行和连续的工具更新会共享当前的工具活动帖子。
* 如果预览帖子已被删除，或在完成时不可用，则会回退为发送一条新的最终帖子。
* 最终媒体/错误载荷会在常规投递之前取消待处理的预览更新，而不是刷新一个临时预览帖子。

### Matrix

* 当最终文本可以复用预览事件时，草稿预览会就地完成。
* 仅媒体、错误以及回复目标不匹配的最终结果会在常规投递之前取消待处理的预览更新；已经可见的过期预览会被重写。

## 工具进度预览更新

预览流还可以包含 **工具进度** 更新：像“正在搜索网页”“正在读取文件”或“正在调用工具”这样的简短状态行，会在工具运行期间以同一条预览消息中的形式出现，并早于最终回复。在 Codex app-server 模式下，Codex 的前言/说明消息也使用同一预览路径，因此简短的“我正在检查……”进度提示可以流入可编辑草稿，而不会成为最终答案的一部分。这样可以让多步骤工具调用在视觉上保持“活跃”，而不是在第一次思考预览和最终答案之间静默无声。

长时间运行的工具在返回之前可能会发出带类型的进度信息。例如，`web_fetch` 在启动时会启动一个五秒计时器：如果抓取仍在进行中，预览会显示 `正在获取页面内容...`；如果抓取在此之前完成或被取消，则不会发出进度行。随后较晚到达的最终工具结果仍会正常传递给模型。

支持的场景：

* **Discord**、**Slack**、**Telegram** 和 **Matrix** 会在预览流式传输处于活动状态时，默认将工具进度和 Codex 前言更新流式传输到实时预览编辑中。Microsoft Teams 在个人聊天中使用其原生进度流。
* Telegram 自 `v2026.4.22` 起已启用工具进度预览更新；保持启用状态即可保留该已发布行为。
* **Mattermost** 会在 `partial` 和 `progress` 模式下将工具活动合并到一个预览帖子中，或在 `block` 模式下将其放在文本块之间的一个工具活动帖子中（见上文）。
* 工具进度编辑遵循当前的预览流式模式；当预览流式传输为 `off`，或区块流式传输已接管消息时，会跳过这些编辑。在 Telegram 中，`streaming.mode: "off"` 表示仅最终投递：通用进度提示也会被抑制，而不会作为独立状态消息投递；但审批提示、媒体载荷和错误仍会正常路由。
* 若要保留预览流式传输但隐藏工具进度行，请为该频道将 `streaming.preview.toolProgress` 或 `streaming.progress.toolProgress` 设置为 `false`（两者默认均为 `true`，并且在所有模式下都会生效）。若要保留工具进度行，同时隐藏命令/执行文本，请将 `streaming.preview.commandText` 或 `streaming.progress.commandText` 设置为 `"status"`（默认值）。将任一选项设置为 `"raw"` 可选择启用命令文本。此策略由使用 OpenClaw 紧凑进度渲染器的草稿/进度频道共享，包括 Discord、Matrix、Microsoft Teams、Mattermost、Slack 会话卡片和 Telegram。若要完全禁用预览编辑，请将 `streaming.mode` 设置为 `off`。

## 进度草稿渲染

进度模式草稿（`streaming.progress.*`）是有上限且可按
通道配置的：

| 键                                 | 默认值      | 行为                            |
| --------------------------------- | -------- | ----------------------------- |
| `streaming.progress.maxLines`     | `8`      | 保留在草稿标签下方的最多紧凑进度行数            |
| `streaming.progress.maxLineChars` | `120`    | 每行紧凑内容在截断前允许的最多字符数（按单词感知）     |
| `streaming.progress.label`        | `"auto"` | 草稿标题；可自定义字符串，或设为 `false` 以隐藏它 |
| `streaming.progress.labels`       | 内置池      | 当 `label: "auto"` 时使用的候选标签    |

Slack 始终将进度模式渲染为固定的会话卡片布局；这些限制仍会约束该卡片中的活动行和计划文本。

### 评论进度通道

除了工具进度之外，紧凑进度渲染器还可以在草稿中显示另一条通道：

* **`streaming.progress.commentary`** - 渲染模型在工具调用前的
  **评论**（一段简短的“我会检查……然后……”式叙述），并与
  工具行交错显示在进度草稿中。在 Discord 和 Telegram 的进度模式下，
  即使关闭了这个可选通道，同样的前导文本也会提供状态标题；其他通道则保留其现有的进度行为。参见
  [进度草稿](/concepts/progress-drafts#status-headline)。

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "channels": {
    "discord": {
      "streaming": { "mode": "progress", "progress": { "commentary": true } }
    }
  }
}
```

保持进度行可见，但隐藏原始命令/执行文本：

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "channels": {
    "telegram": {
      "streaming": {
        "mode": "partial",
        "preview": {
          "toolProgress": true,
          "commandText": "状态"
        }
      }
    }
  }
}
```

在另一个紧凑进度通道键下使用相同的结构，例如
`channels.discord`、`channels.matrix`、`channels.msteams`、
`channels.mattermost`，或 Slack 草稿预览。对于进度草稿模式，请在
`streaming.progress` 下放置相同的策略：

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "channels": {
    "telegram": {
      "streaming": {
        "mode": "progress",
        "progress": {
          "toolProgress": true,
          "commandText": "状态"
        }
      }
    }
  }
}
```

## 相关内容

* [消息生命周期重构](/concepts/message-lifecycle-refactor) - 目标是共享用于预览、编辑、流式传输和完成的设计
* [进度草稿](/concepts/progress-drafts) - 在长时间轮次中更新的可见进行中消息
* [消息](/concepts/messages) - 消息生命周期和传递
* [重试](/concepts/retry) - 传递失败时的重试行为
* [通道](/channels) - 各通道的流式支持。
