一、前言:为什么我们需要流式传输?

当我们在与ChatGPT、DeepSeek和Kimi这样的大模型应用"聊天"时,你有没有发现它们的回复不是一下子蹦出来的,而是像老式打字机那样逐字逐句地展现?这可不是为了制造悬念哦!🎬

技术揭秘时刻:大模型收到输入后并不是一次性生成最终结果,而是像挤牙膏一样逐步生成中间结果。那么问题来了——这种流畅的"打字机效果"是怎么实现的呢?是通过不断刷新的轮询?还是全双工的WebSocket?

正确答案是:SSE(Server-Sent Events)技术!这项技术让大模型能够像快递小哥一样,实时推送中间生成结果,带来双重优势:

  1. ⏱️ 缩短等待时间:不用等全部内容生成完就能看到部分结果

  2. 🛡️ 规避超时风险:长文本生成再也不怕请求超时啦!

下面就让咱们一起揭开这项"黑科技"的神秘面纱吧!🔍


二、SSE技术深度解析

什么是SSE?

Server-Sent Events (SSE) 是一种允许服务器主动推送消息给客户端的技术。和WebSocket这个"电话"(双向通信)不同,SSE更像是个"广播喇叭"(单向通信),特别适合服务器需要不断推送信息的场景。

技术特点

  • 📡 基于HTTP协议(不像WebSocket需要额外协议)

  • 🔄 每次消息发送后连接会关闭,客户端需要重新连接

  • ✉️ 消息格式有严格规范(后面会详细讲解)

SSE消息格式说明书

每条SSE消息就像一封信✉️,由多个字段组成,每个字段的格式为:

[field]: [value]\n

信件之间用两个换行符\n\n隔开,常见字段包括:

字段名 作用 示例
data 消息内容 data: Hello SSE!\n\n
event 自定义事件类型 event: notification\n
id 事件唯一ID id: 12345\n
retry 重连时间(ms) retry: 5000\n

代码示例

// 发送简单消息
res.write('data: Hello, SSE!\n\n');
​
// 发送多行消息(会自动合并)
res.write('data: 第一行\n');
res.write('data: 第二行\n\n');
​
// 发送自定义事件
res.write('event: systemAlert\n');
res.write('data: 服务器即将维护!\n\n');

三、SSE实战手册

3.1 基础篇 - EventSource

场景1:简单消息推送

服务端代码

app.get("/sse", (req, res) => {
  // 必须设置的HTTP头部
  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    Connection: "keep-alive",
  });
​
  // 每秒推送一次当前时间
  setInterval(() => {
    res.write(`data: ${new Date().toLocaleString()}\n\n`);
  }, 1000)
});

客户端代码

const eventSource = new EventSource("http://localhost:3000/sse");
eventSource.onmessage = (event) => {
  console.log("收到消息:", event.data);
};
场景2:自定义事件处理

服务端升级版

// 添加自定义事件
res.write('event: stockUpdate\n');
res.write('data: {"symbol":"AAPL","price":182.73}\n\n');

客户端监听

eventSource.addEventListener("stockUpdate", (event) => {
  const data = JSON.parse(event.data);
  console.log(`股票${data.symbol}最新价格:$${data.price}`);
});
场景3:连接管理

优雅地分手

// 服务端主动结束
res.end();
​
// 客户端主动关闭
eventSource.close();
​
// 错误处理
eventSource.onerror = (err) => {
  console.error("SSE连接异常:", err);
  eventSource.close();
};

3.2 进阶篇 - POST请求支持

默认的EventSource只支持GET请求,这就像只能用明信片通信📮,太不安全了!下面教你怎么用"加密信封"✉️:

方案1:Token中转站
async function getSecureSSE(url, data) {
  // 第一步:用POST获取临时通行证
  const { sseToken } = await fetch("/get-sse-token", {
    method: "POST",
    body: JSON.stringify(data)
  }).then(res => res.json());
​
  // 第二步:用Token建立SSE连接
  return new EventSource(`/sse?token=${sseToken}`);
}
方案2:Fetch API黑科技
async function postSSE(url, data, callbacks) {
  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "text/event-stream",
    },
    body: JSON.stringify(data),
  });
​
  const reader = response.body.getReader();
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    const text = new TextDecoder().decode(value);
    callbacks.onMessage(text);
  }
}
方案3:使用现成轮子
import { fetchEventSource } from "@microsoft/fetch-event-source";
​
fetchEventSource("/api/chat", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ question: "你好啊!" }),
  onmessage(msg) {
    console.log("AI回复:", msg.data);
  }
});

四、技术选型大比拼

技术 通信方向 协议 复杂度 适用场景
SSE 服务器→客户端 HTTP ★★☆ 实时通知、大模型对话
WebSocket 双向通信 ws/wss ★★★ 聊天室、协同编辑
短轮询 客户端→服务器 HTTP ★☆☆ 简单实时性要求低
长轮询 客户端→服务器 HTTP ★★☆ 兼容性要求高

五、结语:SSE的未来展望

SSE技术正在这些领域大放异彩:

  • 🤖 大模型对话:实现流畅的"打字机效果"

  • 📈 金融实时数据:股价瞬息万变也不怕

  • 📱 即时通讯:消息已读回执实时更新

  • 🏗️ 长任务监控:构建进度条不再头疼

随着Web技术的演进,SSE这个"单向广播"能手,必将在实时通信领域继续发光发热!

思考题:如果你的应用需要实现以下功能,你会选择哪种技术?

  1. 股票价格实时看板 📉

  2. 在线多人白板协作 🎨

  3. 后台任务进度查询 ⏳

欢迎在评论区分享你的技术选型思路!💡

(本文完整代码示例可参考:streaming-learn

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐