Server-Sent Events (SSE) :ChatGPT打印机式输出

发布于 2025-7-22 07:22
浏览
0收藏

Server-Sent Events 提供了一种健壮、简洁且高效的解决方案,用于实现从服务器到客户端的实时、单向数据传输。其基于 HTTP 的基础、内置的重连机制以及易于实现的特点,使其非常适合用于广播更新、通知以及流式传输大型语言模型 (LLM) 响应等增量内容。

1.实时Web通信简介

2. 理解Server-Sent Events (SSE)

2.1. 关键特性

2.2. 常见场景

3. SSE协议的消息结构

3.1 完整HTTP响应示例

4. 使用SSE实现类似ChatGPT的打字机效果

4.2. 前端实现(HTML+JS)

4.1. 后端实现(FastAPI)

4.3. 运行方法

4.4. 效果图

4.5. 抓包来往HTTP消息

4.6 SSE流式通信时序图

5. 浏览器兼容性

6. SSE 与 WebSockets

在大语言模型(LLM)蓬勃发展的今天,我们经常看到聊天界面中LLM能够像打字机一样逐字输出回复。这种流畅的交互体验背后,离不开实时Web通信技术的支持。

1.实时Web通信简介

历史上,为了获取新数据,客户端通常需要反复向服务器发送请求,这种方式被称为轮询。这种传统方法效率低下,会产生大量的网络流量,并引入不可避免的延迟。

为了解决这些问题,Server-Sent Events (SSE) 和 WebSocket 等推送技术应运而生,它们允许服务器主动向客户端发起数据传输,从而实现即时更新,无需客户端持续请求。

2. 理解Server-Sent Events (SSE)

Server-Sent Events (SSE) 是一种服务器推送技术,它允许服务器通过单个 HTTP 连接向客户端发送数据更新。

SSE 定义了服务器如何在建立初始客户端连接后,主动向客户端发起数据传输。它通常用于向浏览器客户端发送消息更新或连续的数据流。

2.1. 关键特性

  • 单向性
    SSE 的一个显著特点是其单向通信模式:数据消息仅从服务器流向客户端(例如,用户的网络浏览器)。
    SSE 的单向性并非局限,而是一种设计选择。通过限制通信方向,协议本身的复杂性得以降低,从而优化了其在广播场景中的性能。这意味着 SSE 完美地适用于客户端主要接收更新的场景,避免了管理双向协议中固有的开销和复杂性。
  • HTTP 协议基础
    SSE 完全基于标准 HTTP 协议运行。它使用标准的端口(80/443),并且通常无需特殊配置即可穿透代理和防火墙。SSE 依赖于长连接和分块传输编码(transfer-encoding: chunked),因此至少需要 HTTP/1.1 版本。
  • 自动重连
    SSE 的一个重要优势是其内置的自动重连机制。如果连接意外中断,客户端会自动尝试重新连接,确保数据流不中断。在重新连接时,客户端可以发送一个​​​Last-Event-ID​​ 头,允许服务器从上次已知的位置恢复数据流。
  • 文本数据
    SSE 只能发送基于文本的事件数据,通常以 UTF-8 编码的字符串形式。它不支持发送二进制数据。

2.2. 常见场景

  • 实时更新: 新闻推送、社交媒体状态更新、实时体育赛事比分、股票价格波动 。
  • 监控: 服务器或应用程序监控仪表板、物联网设备数据 。
  • 通知: Web 应用程序的实时通知、电子邮件通知、系统警报 。
  • AI 生成内容流式传输: SSE 非常适合流式传输大型语言模型 (LLM) 的增量响应,以创建类似“打字机”的效果 。

3. SSE协议的消息结构

SSE(Server-Sent Events)协议基于HTTP协议,服务端通过标准的HTTP响应持续推送事件。

3.1 完整HTTP响应示例

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive


data: 你好,世界

data: 这是第二条消息

event: custom
data: 自定义事件内容
id: 42

响应头

  • ​Content-Type: text/event-stream​​  必须,表明是SSE流。
  • ​Cache-Control: no-cache​​  建议,防止中间缓存。
  • ​Connection: keep-alive​​  建议,保持连接不断开。

消息体

  • 每条消息以​​\n\n​​结尾。
  • ​data:​​字段为主要内容,可多行。
  • 可选​​event:​​​、​​id:​​​、​​retry:​​等字段。

字段名称

描述

data

事件的主要内容。

id

可选的事件标识符,用于客户端重连时恢复流。

event

可选的事件类型字符串。如果指定,客户端将分派命名事件。

retry

可选的毫秒数,指定连接丢失后的重连等待时间。

4. 使用SSE实现类似ChatGPT的打字机效果

AI 并不是等待一段时间再一次性返回完整的答案,而是 边生成边显示,逐步展示 AI 的思考过程。这种方式不仅减少了等待时间,而且让 AI 的回答看起来更自然,仿佛它在思考时逐渐给出答案。这种交互体验显得更加生动、真实,用户可以感觉到 AI “在实时作答”。

如果不使用流式输出,模型需要等到所有文本生成完毕后才返回结果,用户可能会感到延迟很长。而流式调用能够逐步生成输出,减少等待时间,提升交互体验,类似于 ChatGPT 的打字效果。

普通 vs. 流式输出

模式

特点

普通输出(非流式)

用户提交问题 → 等待几秒 → 一次性返回完整答案

流式输出(像 ChatGPT)

用户提交问题 → AI 边生成边显示 → 逐步输出答案

相关阅读:​​​从0开始:用 Streamlit + LangChain 搭建个简易ChatGPT​

SSE 非常适合这种增量输出生成,因为它专为从服务器到客户端的连续、单向数据流而设计。LLM 后端生成的每个“令牌”或小块文本都可以作为独立的 SSE ​​data​​ 字段发送。

服务器只需将新生成的内容逐块写入 ​​text/event-stream​​​ 连接,并在每个块后加上 ​​\n\n​​ 分隔符 。这种“原生令牌流式传输”使用户能够自然地体验 AI 交互,仿佛正在观察 AI 思考的过程。

4.1. 前端实现(HTML+JS)

建立连接

要打开连接并开始从服务器接收事件,需要创建一个新的 EventSource 对象,并提供生成事件的服务器端的 URL 。

例如:

const evtSource = new EventSource("/sse");

监听 message 或自定义 event 类型

  • onmessage 处理程序:

服务器如果没有发送 ​​event​​​ 字段,那么默认将作为 ​​message​​​ 事件接收,并由 ​​EventSource​​​ 对象的 ​​onmessage​​​ 属性处理 。数据可以通过 ​​event.data​​ 访问 。

例如:

evtSource.onmessage = (e) => { console.log(e.data); };
  • addEventListener() 用于命名事件:

服务器可以发送带有 ​​event​​​ 字段的消息,指定自定义事件类型。客户端可以使用 ​​EventSource.addEventListener()​​ 监听这些命名事件。

例如:

sse.addEventListener("notice", (e) => { console.log(e.data); });

实际代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE 打字机 Demo</title>
    <style>
        body { font-family: Consolas, monospace; background: #f9f9f9; padding: 2em; }
        #output { font-size: 1.5em; background: #fff; padding: 1em; border-radius: 8px; min-height: 2em; }
    </style>
</head>
<body>
    <h2>SSE 打字机效果演示</h2>
    <div id="output"></div>
    <script>
        // 连接SSE接口
        const output = document.getElementById('output');
        const evtSource = new EventSource('/sse');
        evtSource.onmessage = function(event) {
            if (event.data === '[END]') {
                evtSource.close();
                return;
            }
            output.textContent += event.data;
        };
        evtSource.onerror = function() {
            output.textContent += '\n[连接已断开]';
        };
    </script>
</body>
</html>
  • ​EventSource('/sse')​​ 连接后端SSE接口,自动接收流式数据。
  • 每收到一个字符就追加到页面,实现打字机效果。
  • 收到​​[END]​​时关闭连接。

4.2. 后端实现(FastAPI)

设置 Content-Type: text/event-stream 头

负责发送事件的服务器端脚本必须以 MIME 类型 Content-Type: text/event-stream 响应 。这会告知浏览器将传入数据解释为事件流。

实际代码示例

from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from fastapi.staticfiles import StaticFiles
import asyncio

app = FastAPI()

# 挂载静态文件目录
app.mount('/static', StaticFiles(directory='static'), name='static')

asyncdef gpt_stream(text: str, delay: float = 0.05):
    """
    模拟GPT打字机效果,逐字发送文本。
    :param text: 要发送的完整文本
    :param delay: 每个字符之间的延迟(秒)
    """
    for char in text:
        yieldf"data: {char}\n\n"
        await asyncio.sleep(delay)
    yield"data: [END]\n\n"

@app.get('/sse')
asyncdef sse():
    """
    SSE接口,流式返回文本内容。
    """
    with open('novel.txt', 'r', encoding='utf-8') as f:
        text = f.read()
    return StreamingResponse(gpt_stream(text), media_type='text/event-stream')

4.3. 运行方法

1.启动服务:

uvicorn main:app --reload

2.在浏览器访问:

http://127.0.0.1:8000/static/index.html

即可看到SSE打字机效果。

4.4. 效果图

Server-Sent Events (SSE) :ChatGPT打印机式输出-AI.x社区

4.5. 抓包来往HTTP消息

  • 每个​​data:​​字段后跟一个字符或一段文本,前端逐条接收。
  • 结尾用​​[END]​​标记流式输出结束。

Server-Sent Events (SSE) :ChatGPT打印机式输出-AI.x社区

4.6 SSE流式通信时序图

Server-Sent Events (SSE) :ChatGPT打印机式输出-AI.x社区

5. 浏览器兼容性

Server-Sent Events (SSE) :ChatGPT打印机式输出-AI.x社区

6. SSE 与 WebSockets

特性

Server-Sent Events (SSE)

WebSockets

通信方向

单向(服务器到客户端)

双向(客户端与服务器)

底层协议

HTTP/HTTPS

自定义 WebSocket 协议 (ws://, wss://)

支持数据格式

仅文本(UTF-8)

文本(UTF-8)和二进制

实现复杂性

简单

相对复杂

防火墙/代理兼容性

良好(基于标准 HTTP)

可能需要特定配置

理想用例

实时新闻、股票报价、通知、仪表板、LLM流式响应

聊天应用、在线游戏、协作工具、实时交互式仪表板


Server-Sent Events 提供了一种健壮、简洁且高效的解决方案,用于实现从服务器到客户端的实时、单向数据传输。其基于 HTTP 的基础、内置的重连机制以及易于实现的特点,使其非常适合用于广播更新、通知以及流式传输大型语言模型 (LLM) 响应等增量内容。

本文转载自AI取经路,作者:AI取经路

已于2025-7-22 09:32:38修改
收藏
回复
举报
回复
相关推荐