AI 聊天的逐字回复,到底是怎么实现的?
SSE 是什么用过豆包、ChatGPT 这类 AI 产品的人对逐字输出的「打字机效果」一定不陌生。不少小伙伴可能会以为这是前端做的模拟打字动画或是通过 WebSocket 实现的实时推送。实际上这类流式输出的核心技术是 SSEServer-Sent Events服务端推送事件。目前大模型流式接口、Agent 任务进度推送等场景普遍采用这项技术。理解 SSE 最直观的方式不是先背协议条文而是打开浏览器抓包亲眼观察它的运行过程。以豆包为例随便发起一个提问等回复开始逐字输出时按下 F12 打开开发者工具切换到网络面板找到 /chat/completion 请求点进去再切到 EventStream 标签页。这时就能看到清晰的事件流界面。左侧是页面上正在逐字渲染的回答内容右侧则是浏览器自动解析后呈现的结构化 SSE 事件列表。图片EventStream 列表里每新增一条记录页面上就会每多渲染一些文字。这就是 SSE 的核心工作模式服务端生成一点就推送一点前端收到一点就渲染一点。把 SSE 和普通 HTTP 请求放在一起对比两者的表现差异十分明显现象 普通 HTTP SSE请求状态 很快变成 200 OKTimeline 里一条短竖线 长时间停在 PendingTimeline 拉得很长Response 面板 响应一次性完整显示 EventStream 里事件持续追加Content-Type application/json 等 text/event-stream连接生命周期 响应返回即结束 连接保持打开直到回答推完简单来说二者的交互模式有本质区别普通 HTTP 是「一问一答响应结束即断开」。客户端发起一次请求服务端返回完整响应后连接随即关闭页面拿到全部数据再统一渲染。SSE 是「一次请求连接保持分段推送」。客户端仅发起一次请求连接持续保持服务端生成一段数据就推送一段全部内容发送完成后才关闭连接。Chrome 开发者工具的 EventStream 标签会自动解析原始流式响应将其呈现为逐条排列的事件列表正是这种推送模式的直观体现。SSE 是一种基于 HTTP 的服务端到客户端单向推送协议。 连接建立后服务端按照标准文本格式持续推送数据浏览器可逐条接收事件并处理。它的核心特性可以归纳为三点基于 HTTP 协议复用标准 HTTP 长连接无需额外协议栈对防火墙、代理网关天然兼容。单向数据推送数据仅从服务端流向客户端通信方向固定实现逻辑简单。事件流形式传输数据以独立事件为单位分段传输消息边界清晰解析处理方便。二、为什么需要 SSE前面我们通过浏览器抓包直观看到了 SSE 的流式推送效果也对比了它和普通 HTTP 请求的表现差异。此时你可能会产生一个疑问HTTP 已经是通用的网络协议为什么还需要专门的 SSE 技术来做推送答案藏在 HTTP 协议的原生设计局限里。HTTP 协议从诞生起就遵循严格的请求 - 响应模型所有交互必须由客户端主动发起请求服务端被动处理后返回结果响应交付后本次交互即宣告结束。在未收到新请求的前提下服务端没有任何机制主动向客户端推送数据。图片即便 HTTP/1.1 引入了 Keep-Alive 长连接机制也只是让多个 HTTP 请求可以复用同一条 TCP 连接减少建连开销并没有改变「客户端主动请求、服务端被动响应」的核心逻辑。这套模型可以满足页面加载、数据查询等绝大多数常规场景但遇到「服务端数据持续产生、需要实时同步给客户端」的需求时就显得力不从心。比如大模型逐 token 生成回答、后台任务进度更新、实时日志输出这类场景服务端不可能等全部内容生成完再一次性返回用户也无法接受长时间的空白等待。为了突破这个局限业界在实践中有三类主流技术路线用轮询在 HTTP 上模拟推送、换 WebSocket 做全双工通信、基于 HTTP 标准实现单向推送能力。SSE 正是第三条路线的官方标准实现。轮询做过实时需求的同学第一个想到的方案大概率是轮询。既然服务端不会主动发那就让前端隔几秒就查一次有没有新数据。这种方案完全基于普通 HTTP 实现不需要任何额外协议支持开发成本极低。但它的缺陷也同样十分突出无效开销大网络面板里刷刷刷一堆请求大部分都是空结果带宽和服务端资源都浪费在无效查询上延迟和成本天然矛盾想更新快就得缩短轮询间隔间隔一短请求量就上去了想省资源就得拉长间隔实时性又下来了两头没法兼顾轮询本质是「用客户端的勤快弥补 HTTP 不能主动推送的短板」属于妥协方案仅适合对实时性要求不高的低频场景。WebSocket想做真正的主动推送另一个大家耳熟能详的方案是 WebSocket。它先通过一次 HTTP 请求完成握手升级服务端返回 101 Switching Protocols 之后就切换成了 WebSocket 协议变成一条双向通信通道。连接不断开的话客户端和服务端想什么时候发消息就什么时候发不受请求 - 响应的限制。这种双向对等的通信能力非常适合即时通讯、多人协同编辑、实时对战游戏这类双方都需要高频收发消息的场景。但对应的落地成本也显著更高协议栈独立WebSocket 是独立于 HTTP 的完整协议体系网关、负载均衡、防火墙、CDN 都需要单独做适配。运维复杂鉴权设计、运维监控、问题排查的复杂度也远高于普通 HTTP 服务。回到 AI 对话场景交互模式其实是典型的「单请求、长响应」用户只需要发送一次 Prompt后续全程都是服务端单向输出生成结果客户端几乎没有上行数据。这种单向流式场景使用 WebSocket 相当于用双向通信的重型工具去解决单向推送的轻型需求协议能力冗余运维成本偏高投入产出比并不理想。SSESSE 填补了轮询与 WebSocket 之间的空白它不更换底层协议完全在 HTTP 原生框架之内实现了标准化的服务端单向推送能力。客户端只需发起一次普通的 HTTP 请求连接建立后就持续保持打开状态服务端生成一段数据就推送一段直到全部内容发送完成再正常关闭连接。比起轮询它不用反复建连、反复发请求没有那么多无效开销比起 WebSocket它不用引入一套新的协议体系HTTP 现有的鉴权、网关、安全策略都能直接复用落地和维护成本低很多。这种轻量的单向流式特性和大模型的生成模式天然高度匹配。大模型逐 token 生成内容的过程本身就是持续的流式输出用户提交一次请求后服务端全程单向返回数据这也是 OpenAI、豆包等主流大模型厂商都选择 SSE 作为流式接口底层方案的核心原因。图片方案对比我们可以用一张表快速对比几种方案的核心差异技术方案 协议基础 通信模型 网络特征 典型适用场景 落地与运维成本普通 HTTP HTTP 请求 - 响应无主动推送 请求快速完成响应一次性返回 静态资源加载、常规数据查询 最低轮询 HTTP 客户端定时拉取伪推送 大量重复短请求多数为空响应 低频非实时状态刷新 低WebSocket 独立 WebSocket 协议 全双工双向通信 ws/wss 协议双向数据帧传输 即时通讯、协同编辑、实时游戏 高SSE HTTP 服务端单向真实推送 单条 HTTP 长连接响应体持续增长 AI 流式输出、任务进度推送 低基于以上对比可以做出以下选型逻辑常规的数据查询、状态刷新对实时性没那么高要求的普通 HTTP 就够了别为了「看起来高级」平白增加技术复杂度核心需求就是服务端单向持续输出比如流式对话、日志实时查看、进度条推送优先选 SSE实现简单、生态成熟踩坑也少只有当业务真的需要两边高频互发消息的时候再考虑上 WebSocket。放到 AI 应用这个场景里结论就更直接了绝大多数流式需求都是服务端单向吐数据SSE 基本是当前最均衡、最划算的选择。三、SSE 协议搞懂了 SSE 的定位和适用场景再看它的协议设计会发现格外简洁。它没有复杂的二进制封包全程基于 UTF-8 纯文本仅靠换行和空行做消息边界理解和实现的门槛都很低。第一节我们在 EventStream 面板里看到的那些结构化数据拆解到底就是一行行约定好格式的响应文本。报文格式SSE 本质是一种特殊格式的 HTTP 响应。服务端首先要设置正确的响应头浏览器才会将其识别为事件流Content-Type: text/event-stream浏览器识别 SSE 响应的核心标识是必填字段。Cache-Control: no-cache禁止代理、CDN 等中间节点缓存响应避免流式内容被缓冲导致无法实时推送。Connection: keep-alive维持 HTTP 长连接保证数据流可以持续传输。SSE 的报文格式非常简单核心只有两条每行一条字段格式为 字段名: 字段值以换行符\n结尾连续两个换行\n\n即一个空行代表一条完整的消息结束浏览器会立即触发对应的事件回调。标准一共定义了 5 种字段覆盖了正文、事件类型、断线续传、重连配置、心跳保活的需求字段 说明 示例data: 消息正文。单条消息可包含多行 data:最终会拼接成完整内容 data: Helloevent: 自定义事件类型。前端可按事件名分别监听不写则默认触发 message 事件 event: progressid: 消息唯一 ID。断线重连时浏览器会通过 Last-Event-ID 请求头带给服务端 id: 4102retry: 重连间隔。告知浏览器在连接断开后等待多少毫秒再进行重连尝试。 retry: 3000: 注释/心跳。以冒号开头的行会被浏览器忽略。常用于发送心跳包防止网关超时断连。 : ping报文示例 1一条标准的消息event: messageid: 1data: {“role”: “assistant”, “content”: “你好”}浏览器解析后会触发一个名为 message的事件event.data的值为 {“role”: “assistant”, “content”: “你好”}。报文示例 2多行 Data 拼接如果内容较长可以拆分为多行 data: 提升可读性。浏览器会自动将所有行拼接行与行之间自动插入一个换行符data: {data: “role”: “assistant”,data: “content”: “Hello World”data: }拼接后的完整内容为{ “role”: “assistant”, “content”: “Hello World” }开发者只需进行一次 JSON.parse即可。客户端对接方式浏览器消费 SSE 流主要有两种方案原生 EventSource API以及手动解析流式响应。1原生 EventSource API浏览器提供了原生的 EventSource 接口内置了报文解析、自动重连、事件分发能力无需手动逐行拆包基础场景使用成本极低。// 建立 SSE 连接const es new EventSource(“/stream”);// 连接建立成功es.onopen () {console.log(“SSE 连接已建立”);};// 监听默认 message 事件es.onmessage (event) {console.log(“收到消息:”, event.data);};// 监听自定义事件对应服务端的 event: progresses.addEventListener(“progress”, (event) {console.log(“任务进度:”, event.data);});// 连接异常时触发es.onerror () {console.log(“连接异常浏览器会自动尝试重连”);};但原生 API 存在两个明确的限制也是绝大多数生产环境不直接使用它的核心原因只支持 GET 请求无法使用 POST 发送请求体复杂参数只能拼接在 URL 中对于需要传递大量参数的大模型接口并不友好。无法自定义请求头不支持添加 Authorization 之类的自定义请求头难以实现标准的 Token 鉴权。2手动解析为了突破原生 API 的限制现代前端项目包括豆包、OpenAI 的官方 Web SDK普遍采用 fetch 配合 ReadableStream 手动解析 SSE 格式。核心思路是通过 fetch 获取响应的可读流分块读取二进制数据并解码为文本按换行符拆分逐行识别字段遇到空行时将累积的字段组装为完整事件抛出。以下是一个简化版的实现示例仅处理核心的 data 字段async function connectSSE() {const response await fetch(‘/api/chat’, {method: ‘POST’,headers: {‘Content-Type’: ‘application/json’,‘Authorization’: ‘Bearer your_token’ // 支持自定义Header},body: JSON.stringify({ prompt: ‘Hello’ }) // 支持携带请求体});const reader response.body.getReader(); const decoder new TextDecoder(utf-8); let buffer ; while (true) { const { done, value } await reader.read(); if (done) break; // 将新的二进制块解码为文本追加到缓冲区 buffer decoder.decode(value, { stream: true }); // 按换行拆分所有完整行 const lines buffer.split(\n); // 最后一行可能不完整放回缓冲区等待后续内容 buffer lines.pop(); lines.forEach(line { if (line.startsWith(data: )) { const data line.substring(6); if (data [DONE]) { console.log(Stream finished); return; } // 解析并处理业务数据 const payload JSON.parse(data); console.log(收到数据:, payload); } }); }}

相关新闻

C++ 构造函数细解--编译器总是确保所有成员对象在进入函数体执行前必须已经初始化完成

C++ 构造函数细解--编译器总是确保所有成员对象在进入函数体执行前必须已经初始化完成

c对象的构造过程并非发生在花括号{}内部,而是严格分为两个阶段:初始化阶段 发生在进入构造函数函数体之前 在此阶段,所有的非静态成员变量(包括基类子对象)都必须被初始化 如果程序员提供了初始化列表,则按照列表中的指…

2026/7/23 12:40:56 阅读更多 →
“捏脸“背后的工程逻辑:3D数字人全维度DIY定制系统

“捏脸“背后的工程逻辑:3D数字人全维度DIY定制系统

在游戏领域,"捏脸"早已是角色创建的标配功能——玩家通过滑块调整五官比例、身材参数,打造专属游戏角色。而在数字人行业,这一能力长期缺失。传统2D数字人基于提前录制的真人视频,形象一旦确定便彻底锁死,从…

2026/7/23 12:24:27 阅读更多 →
VirtualLab Fusion 超透镜设计与仿真教程

VirtualLab Fusion 超透镜设计与仿真教程

本文将引导您在 VirtualLab Fusion 中完成超透镜的完整设计与仿真工作流程。该工作流程包含四个主要步骤:配置超透镜创建代理模型设计与仿真导出结构1超透镜配置将超透镜组件添加到系统后,需配置其基本属性:组件后方的介质以及孔径直径&#…

2026/7/23 12:25:03 阅读更多 →

最新新闻

低成本论文降AI方案:TextHumanizer与StyleTransferPro实战

低成本论文降AI方案:TextHumanizer与StyleTransferPro实战

1. 项目概述:低成本论文降AI方案解析去年帮学弟修改毕业论文时,我发现Turnitin等主流查重系统开始标记AI生成内容。当时用Grammarly改写三遍仍被识别,最终在GitHub某个学术工具讨论区发现了这套组合方案。实测用47.5元成本,成功将…

2026/7/23 12:40:08 阅读更多 →
K8s 部署 Kafka (KRaft) + SASL/SCRAM-SHA-512 踩坑与终极实战指南

K8s 部署 Kafka (KRaft) + SASL/SCRAM-SHA-512 踩坑与终极实战指南

这是一份基于前面排坑与实践沉淀的 Kafka (KRaft 模式) SASL/SCRAM-SHA-512 安全认证 的完整 Helm 部署教程。架构包含了声明式的用户管理、动态注册脚本、全流程对齐的 SCRAM 加密机制以及高可用存储配置。📖 教程目录项目目录结构完整配置文件values.yamltemplat…

2026/7/23 12:40:08 阅读更多 →
太好了!千问App给新用户发8元红包啦!下载后只要输入 千问新人福利uqo6UY 即可领取8元通用立减券,简单又好用,快来领取吧!

太好了!千问App给新用户发8元红包啦!下载后只要输入 千问新人福利uqo6UY 即可领取8元通用立减券,简单又好用,快来领取吧!

千问官方给的最新福利券,只要是新用户下载千问官方App然后输入千问新人福利uqo6UY 这个最新口令最后就可以直接领取8元新用户无门槛优惠券这个8元的立减券可以免费喝一杯奶茶,可用于点外卖、打车等生活服务场景,这炎热的夏季,让我…

2026/7/23 12:40:08 阅读更多 →
虚拟桌面切换

虚拟桌面切换

虚拟桌面——一键切换,互不干扰开会投屏演示时,微信消息弹窗突然出现在大屏幕上,满屋子人都看到了。上班摸鱼时,娱乐窗口和聊天窗口混在工作桌面里,万一同事临时借用电脑也不方便。还有那种需要多个窗口同时打开、切换…

2026/7/23 12:40:08 阅读更多 →
Midjourney AI绘画实战:30天从入门到商业应用

Midjourney AI绘画实战:30天从入门到商业应用

1. 项目概述:AI绘画新时代的创作革命三年前我第一次接触Midjourney时,AI绘画还只是科技极客们的玩具。如今它已经成为设计师、插画师甚至普通上班族的日常生产力工具。这个基于Discord平台的AI绘画工具,通过简单的文本描述就能生成令人惊叹的…

2026/7/23 12:40:08 阅读更多 →
EIP低代码平台-菜单与菜单按钮配置

EIP低代码平台-菜单与菜单按钮配置

EIP低代码平台-菜单与菜单按钮配置功能讲解 开源框架模块详解|码云开源EIP低代码平台 一、模块基础概念 1.1 菜单配置模块作用 菜单模块是EIP低代码平台负责系统导航架构、页面入口管控、访问权限隔离的基础核心模块。主要用于搭建系统左侧树形导航结构&#xf…

2026/7/23 12:39:08 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/22 12:54:44 阅读更多 →

月新闻