# SSE 到底是什么?用 FastAPI 一次讲透流式响应 | BV1if7E64Ex5 Milky 整理 ## 一、三种通信协议对比 | 协议 | 类比 | 特点 | |------|------|------| | HTTP | 懒惰的服务员 | 你问一次,他答一次,服务器无法主动推送 | | SSE | 勤快的服务员 | 只需要开口说一次,他会主动汇报最新进度 | | WebSocket | 双方都带着对讲机 | 任何一方都可以随时主动说话,完全平等的双向通信 | ## 二、SSE 协议的适用场景 - **HTTP**:必须等模型生成完所有内容才能一次性返回,用户等待时间过长 - **WebSocket**:功能强大但成本高,且大多数 AI 场景中用户不需要主动发消息 - **SSE**:只发起一次请求,服务器边生成边推送,用户实时看到文字逐字出现 ## 三、SSE 工作原理详解 ### 完整流程 ``` 客户端 → 普通 HTTP 请求 → 服务器 客户端 ← Content-Type: text/event-stream ← 服务器 客户端 ← Connection: keep-alive ← 服务器 客户端 ← 持续推送事件数据 ← 服务器 客户端 ← event: done / data: [DONE] ← 服务器 ``` ### HTTP 响应头 ``` Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive ``` ### SSE 消息格式 | 字段 | 作用 | |------|------| | data | 消息内容 | | event | 事件类型 | | id | 消息编号 | | retry | 断线重连间隔(毫秒) | 每条消息之间用空行分隔。 ### 浏览器端接收 ```javascript const source = new EventSource('/stream'); source.onmessage = (event) => { console.log(event.data); }; ``` ## 四、FastAPI 核心前置知识 - 与 Pydantic 深度绑定,自动请求解析和响应序列化 - 自动生成交互式 API 文档(/docs) - 原生支持 async/await 异步编程 ## 五、生成器(Generator)与 yield 关键字 yield 函数的四个特点: 1. 用 yield 代替 return 2. 执行到 yield 暂停并返回值 3. 下次调用从 yield 后继续 4. 按需产生数据,适合流式场景 ## 六、完整 FastAPI SSE 实现 ### 环境要求 ``` FastAPI >= 0.135 ``` ### 代码 ```python from fastapi import FastAPI from fastapi.responses import EventSourceResponse from sse.starlette.sse import ServerSentEvent from pydantic import BaseModel app = FastAPI() class ChatRequest(BaseModel): message: str @app.post("/stream") async def stream_chat(request: ChatRequest): async for chunk in model_stream(request.message): if chunk == "[DONE]": return yield ServerSentEvent(data=chunk) ``` ### 核心公式 ``` EventSourceResponse + yield ServerSentEvent ``` ## 七、三种协议总结对比 | 协议 | 实现复杂度 | 推送方向 | 适用场景 | |------|-----------|----------|----------| | HTTP | ⭐ 最简单 | 仅服务端响应 | 简单的一问一答 | | SSE | ⭐⭐ 中等 | 服务端持续推送 | AI 流式输出、实时通知 | | WebSocket | ⭐⭐⭐ 复杂 | 双向通信 | 需要客户端主动发消息的场景 | ────────────────────────────── Generated by MilkyAi@Bilibili