流式对话看起来像「一个聊天框」,前端真正要处理的是:半包、中断、重连体感、列表滚动与来源展示。我在 ChatAI 多端产品和本站 AI Assistant 里反复做过这件事。
为什么选 SSE
对「模型按 token 往外吐」的场景,SSE 足够简单:
- 一条长连接,服务端持续
data:推送 - 浏览器原生
ReadableStream/EventSource友好 - 比整段轮询延迟低,比硬上 WebSocket 协议轻
ChatAI 与本站助手都以 SSE 为主:ChatAI 侧重多端收流差异与会话展示,本站匹配「问答 + 可停止」的演示目标。
前端最小闭环
一次完整交互大致是:
- 用户提问 →
POST /api/ai/chat - 立刻插入 user / assistant 气泡(assistant 先空)
- 读 stream:拼
text,可选更新mode/sources - 用户点停止 →
AbortController.abort() - 结束:固化正文,展示「参考资料」链接
关键体验点:
- 中断:半包内容要保留,并标明已停止
- 滚动:流式过程中跟随底部,但用户上翻时别硬拽
- 空态:第一次进入不要空白,用推荐问题降低冷启动
本站多了一层:本地 / LLM 双模式
没有 AI_API_KEY 时,助手走 知识库检索 + 本地流式切片,保证 Demo 永远能跑;有 Key 时切 LLM,仍只允许基于知识库上下文作答。
这对前端的意义是:产品不能「没模型就白屏」。流式 UI 与检索结果、引用映射(项目页 / Lab)是同一条体验链。
和业务项目的对应
| 能力 | ChatAI | 本站 Assistant |
|---|---|---|
| 流式协议 | SSE | SSE |
| 可中断 | 需要 | AbortController |
| 多端差异 | H5 / 小程序 / App 收流 | Web 单端,聚焦作品集叙事 |
| 引用 | 产品内消息 | 映射到 /projects/* 等站内页 |
如果你也在做 AI 前端:先把 stream + abort + 气泡状态机 做稳,再谈 RAG 花样。这是面试里最容易讲清楚、也最容易被追问细节的一块。