Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

流式传输

流式传输由能力驱动。实现了流式方法并返回 supports_streaming() == true 的 Provider 可发送 token 增量;其他 Provider 则使用非流式响应路径。运行时将可用流转发给支持部分更新的 channel 适配器。

流式传输的内容

提供方 trait 会在模型生成输出时发出 StreamEvent 值:文本增量、结构化工具调用、提供方侧预执行的工具调用及其结果、令牌用量报告,以及最终的完成标记。各变体的权威定义随类型一起位于 crates/zeroclaw-api/src/model_provider.rsenum StreamEvent)中;推理令牌作为文本增量到达,而非单独的变体。

运行时会消费这些事件。通道编排器使用 Channel trait 的草稿投递方法和能力标志,在支持的场景下呈现渐进式输出。

功能标志

一个提供程序暴露了两个标志,以便运行时知道它可以期望什么:

#![allow(unused)]
fn main() {
fn supports_streaming(&self) -> bool { false }
fn supports_streaming_tool_events(&self) -> bool { false }
}
  • supports_streaming:仅当具体提供者选择启用流式传输时为 true;trait 默认值为 false
  • supports_streaming_tool_events:当提供方在流式传输过程中(而非结束时)发出 ToolCall 事件时为 true

OpenAI 兼容提供商的行为存在差异:有些提供商会逐块流式传输工具调用参数增量,而另一些提供商仅在调用完成后才发出调用。compatible.rs 中的 SSE 解析器能够处理这两种情况。

通道侧流式传输

通道通过 Channel trait 来声明自身的流式传输能力:

#![allow(unused)]
fn main() {
fn supports_draft_updates(&self) -> bool;           // 就地编辑消息
fn supports_multi_message_streaming(&self) -> bool; // 将一条回复拆分为多条消息
}

通道的能力由其配置决定:带有 stream_mode 枚举(off / partial / multi_message)的通道同时支持草稿更新和多消息;带有 stream_drafts 布尔值的通道仅支持草稿更新。此表由通道配置 schema 生成,因此当通道获得或失去流式传输支持时,它能始终保持正确:

通道草稿更新多消息
discord
lark
matrix
nextcloud_talk
slack
telegram
wecom_ws

当提供者和频道都支持流式传输时,流程如下:提供者发出 TextDelta → 运行时传递给频道 → 频道编辑已发送的消息。编辑节奏受该频道的 draft_update_interval_ms 设置限制,以避免触发速率限制;默认值因频道而异。

推理块

StreamEvent 没有单独的 ReasoningDelta 变体。当提供商在流式传输过程中暴露推理内容时,会使用 TextDelta 所携带的 StreamChunk 上的 reasoning 字段;是否请求或呈现该内容由提供商和运行时配置决定。消费者应遵循 StreamChunk 契约,而非匹配不存在的事件变体。

中途工具调用

当流式提供程序决定调用工具时,它会发出结构化的 ToolCall 流事件。运行时:

  1. 读取流直到完成,收集结构化的 ToolCall 事件,并转发可见文本,直到 Final
  2. 在流结束后恢复工具调用
  3. 运行工具(须通过安全验证,参见安全性 → 概述
  4. 向提供商发起新的流式调用,以获取下一轮助手回复,并将工具结果追加到对话中

当前的提供商流在读取过程中不会暂停和恢复;工具执行会在该流达到 Final 后进行,下一轮则是一次全新的流式调用。

从用户的角度来看:文本,然后是一个可见的指示器,表明代理通过特定于频道的提示运行了工具,然后是更多文本。对于没有输入指示器的频道,工具调用与下一个文本块之间的间隙是唯一的信号。

传输完成和超时

流式传输不依赖连接关闭作为成功信号。OpenAI 兼容流在 [DONE] 时结束,OpenAI Responses 流在其终止响应事件时结束,而 Anthropic 流在 message_stop 时结束。服务器可能会在这些事件发生后继续保持 HTTP 连接打开。

流式客户端使用字节空闲超时:OpenAI Responses 和 OpenAI 兼容提供商为 300 秒,Anthropic 为 90 秒。每次读取到正文都会重置相应的超时,因此,正在进行的生成不会受非流式调用所使用的整个请求超时限制。连接建立、响应标头和缓冲的错误正文仍处于超时限制之内。

非流式提供商

supports_streaming() 为 false 时,调用方使用提供程序的非流式聊天路径。Channel 适配器仍可发送已完成的回复,但不会接收增量提供程序流事件。

代码引用

  • crates/zeroclaw-api/src/model_provider.rsModelProvider trait、StreamEvent 枚举
  • crates/zeroclaw-providers/src/compatible.rs:OpenAI 兼容的 SSE 解析器
  • crates/zeroclaw-providers/src/anthropic.rs:Anthropic 流式传输
  • crates/zeroclaw-providers/src/ollama.rs:Ollama 流式传输
  • crates/zeroclaw-channels/src/orchestrator/mod.rs:通道侧的流消费