在 Coze API 中,流式响应(Streaming Response)是 LLM 交互的一个关键特性,能够让模型生成的内容逐步返回给前端,而不是等整个响应完成后再一次性返回。这样可以提高用户体验,使得 AI 回复更加自然、即时。
协议
Coze API 采用 HTTP 长连接(Long Polling) 的 Server-Sent Events (SSE) 或 WebSocket 来实现流式响应。其中,主流实现方式是 SSE,它基于 HTTP/1.1 的 chunked transfer encoding(分块传输编码),允许服务器逐步推送数据到客户端。
SSE(Server-Sent Events)工作原理
SSE是一种在网页开发中使用的、基于HTTP长连接技术,允许服务器向客户端浏览器实时推送更新。客户端通过创建一个EventSource对象并指向服务器上的一个URL来发起请求,这个请求保持打开状态,服务器可以在这个单一的TCP连接上不断发送新的数据块。这些数据块被称为“事件”,每个事件包含类型(可选)、数据和一些元数据(如事件ID,重新连接时间间隔等)。服务器端以简单的文本格式(通常为UTF-8编码的纯文本)发送数据。
SSE 是基于 HTTP 的单向服务器推送技术,主要特点:
-
服务器可以持续向客户端发送数据,而客户端不需要轮询。
-
数据是通过 文本流(text/event-stream) 逐步发送的,前端可以实时监听并解析流数据。
-
适用于消息推送、实时聊天等场景。
SSE响应格式
event: message
data: {"content": "Hello"}
event: message
data: {"content": " how can I help you?"}
event: done
data: [DONE]
其中:
-
event: message
表示服务器发送的新数据块。 -
data: {"content": "Hello"}
是具体的消息内容。 -
event: done
代表流式响应结束。
在前端,我们可以解析这些 data 数据并逐步渲染到对话框中,实现类似 逐行打印 的效果。
在项目中怎么利用cozeAPI建立sse长连接
1.使用CozeAPI类初始化一个API客户端实例,同时传入必要的参数,比如token,基地址等等
2.调用实例方法apiClient.chat.stream
发起流式请求,同时传入请求体参数,得到stream
对象
3.利用 for await...of
循环来迭代 stream
对象,从而逐步处理服务端推送的数据
4.根据不同的事件类型(如 conversation.message.delta
、conversation.message.completed
等),对数据进行不同的处理,比如拼接消息内容、更新状态、存储结果等。
底层技术和原理:
在浏览器环境中,apiClient.chat.stream
方法内部大概率使用了 EventSource
对象来建立 SSE(Server - Sent Events)连接。这种连接方式允许服务端向客户端实时推送数据。服务端需要设置特定的响应头,像 Content - Type: text/event - stream
、Cache - Control: no - cache
和 Connection: keep - alive
,以此来表明这是一个 SSE 连接。客户端则借助监听 EventSource
的 message
事件来接收服务端推送的数据。
结合VUE3实现
// 初始化 Coze API 客户端
const apiClient = new CozeAPI({
token: '',
baseURL: 'https://api.coze.cn',
allowPersonalAccessTokenInBrowser: true, // 强制启用
})
async function fetchChatStream() {
try {
// 发起流式请求
const stream = await apiClient.chat.stream({
bot_id: '',
user_id: 'tay',
conversation_id: conversation_id.value,
additional_messages: [
{
content: textarea.value,
content_type: 'text',
role: 'user',
type: 'question',
},
],
auto_save_history: true,
})
// 先占位,逐步填充内容
// let botResponse = { role: 'assistant', content: '' }
// messages.value.push(botResponse)
// 监听流式数据
for await (const chunk of stream) {
if (chunk.event === 'conversation.message.delta' && chunk.data?.content) {
messages.value += chunk.data.content // 逐步拼接
} else if (chunk.event === 'conversation.message.completed') {
if (chunk.data.type === 'answer') {
isStreaming.value = false // 结束流状态
messages.value = ''
content_list.value = content_list.value.concat(chunk.data) // 将结果添加到 content_list 数组中
} else if (chunk.data.type === 'follow_up') {
follow_up_list.value = follow_up_list.value.concat(chunk.data) // 筛选 type 为 'verbose' 的对象
}
} else if (chunk.event === 'conversation.chat.completed') {
break // 结束
}
}
} catch (error) {
console.error('流式请求失败', error)
}
}
SSE 连接管理
LLM 对话框组件 采用了 SSE(Server-Sent Events) 进行流式消息传输。
但在生产环境中,可能会遇到 服务器限流、网络波动、响应超时 等问题,导致流式对话体验不稳定,例如:
-
启动 SSE 请求
-
调用fetchChatStream()进行对话流式请求
-
设置 timeoutTimer 监测 10s 内是否有数据返回
-
收到数据时,重置 timeoutTimer,防止误触发超时
-
-
处理超时
-
10s 内未收到数据,主动断开 SSE 连接并触发
handleReconnect()
-
-
SSE 连接意外断开
-
进入
catch
语句,调用handleReconnect()
进行重连
-
-
自动重连
-
指数退避 + Jitter 控制重试间隔,避免服务器压力过大
-
最大重试 5 次,如果失败,提示用户
-
-
服务器限流
-
如果
error.response.status === 429
,系统自动等待后重试
-