Appearance
OpenClaw 的流式输出分为两层:区块流式(Block Streaming) 向频道发送完整区块消息,预览流式(Preview Streaming) 在生成过程中更新临时预览消息。要开启区块流式,需设置 agents.defaults.blockStreamingDefault 为 "on" 并为对应频道显式设置 *.blockStreaming: true;预览流式通过 channels.<channel>.streaming.mode 选择 partial、block 或 progress 模式。当前版本不支持真实 token-delta 推送,预览流式基于消息编辑实现。
OpenClaw 流式输出配置:区块流式 vs 预览流式
OpenClaw 有两套独立的流式层:
- 区块流式(Block Streaming,频道消息):助手在写作过程中以完整的区块为单位向频道发送常规消息(非 token 增量)。
- 预览流式(Preview Streaming,Telegram / Discord / Slack / Mattermost / MS Teams / Matrix):生成过程中更新一条临时预览消息。
目前没有真实的 token-delta 流式推送到频道消息。预览流式基于消息发送与编辑/追加实现。
区块流式(频道消息)配置与排查
区块流式在输出可用时以粗粒度分块发送助手内容。以下是区块流式的数据流:
Model output
└─ text_delta/events
├─ (blockStreamingBreak=text_end)
│ └─ chunker 随缓冲区增长输出区块
└─ (blockStreamingBreak=message_end)
└─ chunker 在 message_end 时刷新
└─ channel send(区块回复)说明:
text_delta/events:模型流事件(非流式模型可能较稀疏)。chunker:EmbeddedBlockChunker,应用最小/最大字符限制及换行偏好。channel send:实际出站消息(区块回复)。
核心控制参数
| 参数 | 说明 |
|---|---|
agents.defaults.blockStreamingDefault | 全局开关,"on" / "off"(默认 off)。 |
*.blockStreaming | 频道级强制覆盖。例如 channels.telegram.blockStreaming: true。也支持每账号变体。 |
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(先按空行分段,再按长度分块)。 |
channels.discord.maxLinesPerMessage | Discord 软上限,默认 17,超高回复会自动拆分。 |
边界语义
text_end:chunker 一发出区块就立即推送,每次text_end都会刷新。message_end:等待助手消息结束后,一次性刷新缓冲输出。若缓冲文本超过maxChars,仍会使用 chunker 产生多个分块。
开启区块流式的完整步骤
- 设置
agents.defaults.blockStreamingDefault: "on"。 - 为目标频道设置
channels.<name>.blockStreaming: true(非 Telegram 频道必须显式设置)。 - 选择边界策略:
agents.defaults.blockStreamingBreak: "text_end"(实时推送)或"message_end"(结束后一次发送)。 - 可选:调整
blockStreamingChunk和blockStreamingCoalesce。
配置位置提示:所有 blockStreaming* 默认值位于 agents.defaults 下,不是根配置。
分块算法(低水位线 / 高水位线)
EmbeddedBlockChunker 的分块逻辑:
- 低水位线:缓冲 <
minChars时不输出(除非强制)。 - 高水位线:优先在
maxChars之前找合适断点;强制时在maxChars截断。 - 断点优先级:
paragraph→newline→sentence→whitespace→ 硬截断。 - 代码围栏保护:绝不在代码围栏内截断;强制截断时会关闭围栏再重新打开,保证 Markdown 合法。
maxChars 会被钳制到频道的 textChunkLimit,确保不超过每频道上限。
合并策略(Coalescing)
区块流式开启后,OpenClaw 可以合并连续区块后再发送,减少“单行刷屏”问题。
- 等待空闲间隔(
idleMs)后刷新缓冲。 - 缓冲上限为
maxChars,超出即强制刷新。 minChars防止过小片段发送,最终刷新时发送剩余文本。- 连接符由
blockStreamingChunk.breakPreference决定:paragraph→ 双换行、newline→ 单换行、sentence→ 空格。 - 频道级覆盖:通过
*.blockStreamingCoalesce配置(含每账号)。 - 默认
minChars:Signal / Slack / Discord 为 1500,除非显式覆盖。
仿人类节奏(Human-like Pacing)
开启区块流式后,可在首块之后的回复之间添加随机停顿,让多气泡回复更自然。
- 配置:
agents.defaults.humanDelay(也可通过agents.list[].humanDelay按智能体覆盖)。 - 模式:
off(默认)、natural(800–2500ms 随机)、custom(minMs/maxMs)。 - 仅作用于区块回复,不影响最终回复或工具摘要。
频道预览流式映射
channels.<channel>.streaming.mode 定义预览推送方式:
| Channel | off | partial | block | progress |
|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | editable progress draft |
| Discord | ✅ | ✅ | ✅ | editable progress draft |
| Slack | ✅ | ✅ | ✅ | ✅ |
| Mattermost | ✅ | ✅ | ✅ | ✅ |
| MS Teams | ✅ | ✅ | ✅ | native progress stream |
Slack 专用:
channels.slack.streaming.nativeTransport:当streaming.mode="partial"时,默认true,启用 Slack 原生流式 API(chat.startStream/append/stop)。- 顶级私聊无回复线程时,使用草稿预览帖和编辑,无法使用原生流式。
旧版配置迁移
运行 openclaw doctor --fix 可自动迁移旧版配置:
- Telegram:
streamMode/ 布尔值streaming→ 写入streaming.mode。 - Discord:
streamMode/ 布尔值streaming→ 运行时别名,--fix后持久化。 - Slack:
streamMode→streaming.mode;布尔值streaming→streaming.mode+streaming.nativeTransport;nativeStreaming→streaming.nativeTransport。
频道运行时行为
Telegram
- 使用
sendMessage+editMessageText更新预览。 progress模式:工具进度显示为可编辑状态草稿,完成后清除草稿,最终答案正常发送。- 当 Telegram 区块流式显式开启时,预览流式被跳过(避免双重推送)。
/reasoning stream可将推理过程写入临时预览,最终交付后删除。- 若最终编辑失败,OpenClaw 使用正常交付并清理失效预览。
Discord
- 使用发送 + 编辑预览消息。
block模式使用草稿分块(draftChunk)。- 当 Discord 区块流式显式开启时,预览流式被跳过。
- 最终媒体/错误/显式回复负载会取消待处理的预览,不刷新新草稿。
Slack
partial使用 Slack 原生流式(当nativeTransport=true且存在回复线程)。block使用追加式草稿预览。progress使用状态预览文本,完成后发最终答案。- 原生和草稿预览流式会抑制该轮的区块回复,一条 Slack 回复只走一种交付路径。
- 最终媒体/错误负载不会创建临时草稿消息。
Mattermost
- 将思考、工具活动和回复文本流式到单个预览帖,最终就位。
- 若预览帖被删除,回退为发送新帖。
- 最终媒体/错误负载取消待处理预览后正常交付。
Matrix
- 预览草稿就位后直接替换该事件。
- 纯媒体/错误/回复目标不匹配时,取消预览后正常交付,若预览已可见则撤回。
工具进度预览
预览流式可包含工具进度更新(如“正在搜索网页”、“正在读取文件”),在工具运行期间显示为同一预览消息中的短状态行。在 Codex 应用服务器模式下,Codex 前言/评论消息同样走此路径。
支持通道:
- Discord、Slack、Telegram、Matrix:默认启用工具进度和 Codex 前言更新。
- Telegram 自
v2026.4.22已启用工具进度预览,保持启用以保留发布行为。 - Mattermost 已将其纳入单个预览帖中。
隐藏工具进度或命令文本
- 保持预览流式,但隐藏工具进度:设置
channels.<channel>.streaming.preview.toolProgress: false。 - 隐藏原始命令/执行文本:设置
streaming.preview.commandText: "status"(默认"raw")或streaming.progress.commandText: "status"。 - 该策略适用于所有使用 OpenClaw 紧凑进度渲染的起草/进度通道(Discord、Matrix、Teams、Mattermost、Slack 草稿预览、Telegram)。
- 完全禁用预览编辑:设置
streaming.mode: off。
Telegram 选中引用回复是个例外:当 replyToMode 不是 "off" 且存在选中引用文本时,该轮跳过预览流式,工具进度预览无法渲染。当前消息引用(无选中引用文本)仍保留预览流式。详见 Telegram 频道文档。
示例:保持进度可见但隐藏原始命令文本:
json
{
"channels": {
"telegram": {
"streaming": {
"mode": "partial",
"preview": {
"toolProgress": true,
"commandText": "status"
}
}
}
}
}进度起草模式下同理:
json
{
"channels": {
"telegram": {
"streaming": {
"mode": "progress",
"progress": {
"toolProgress": true,
"commandText": "status"
}
}
}
}
}常见问题
为什么开了流式还是只发一条消息
确认 blockStreamingDefault 已设为 "on",且目标频道显式设置了 *.blockStreaming: true(非 Telegram 频道必须)。另外检查 blockStreamingBreak 是否为 "message_end"——该模式下输出会在消息结束后集中刷新,可能只发一次。
Telegram 预览流式不生效怎么解决
检查 channels.telegram.streaming 是否配置了 mode(partial、block 或 progress)。旧版配置(streamMode、布尔值 streaming)需运行 openclaw doctor --fix 迁移。若 Telegram 区块流式已开启,预览流式会被自动跳过。
区块流式会不会发重复消息
区块流式中的 MEDIA: 指令重复会被识别:若最终回复包含已流式发送的相同媒体 URL,OpenClaw 会去重,不会再次发送附件。合并策略(coalescing)也通过 idleMs 和 maxChars 避免过度拆分的重复推送。