Vue3 接 AI 对话框,SSE 流式渲染我踩的几个坑

上周接了个需求:给后台加一个 AI 对话窗口,要求消息一个字一个字往外蹦,像打字机那样。听起来不难,真上手 SSE 才知道坑在哪。记几笔,给后面要做的同学省点时间。

先说背景

后端给的是一个 SSE 接口,前端这边用 Vue3 + <script setup>。我一开始想当然,以为 EventSource 一把梭就完了。结果第一个坑就来了。

坑一:EventSource 不能带 POST,也不好带 header

我们的对话接口要传一长串上下文,得用 POST,还要在 header 里塞鉴权 token。EventSource 只支持 GET,header 也加不了。折腾半天放弃,改用 fetch + ReadableStream 自己读流:

javascript 复制代码
const res = await fetch('/api/chat', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}` },
  body: JSON.stringify({ messages }),
})
const reader = res.body.getReader()
const decoder = new TextDecoder()
let buffer = ''
while (true) {
  const { done, value } = await reader.read()
  if (done) break
  buffer += decoder.decode(value, { stream: true })
  // 下面要按行切 data: 块
}

坑二:一个 chunk 不等于一条 SSE 消息

我最早天真地拿到 chunk 就 JSON.parse,直接报错。后来打日志才发现,一次 read() 拿到的可能是半条消息,也可能是两条半。SSE 是按 \n\n 分隔事件、data: 开头的,必须自己拿 buffer 缓着按分隔符切,切不出完整的就留在 buffer 里等下一轮。

ini 复制代码
const parts = buffer.split('\n\n')
buffer = parts.pop()  // 最后一段可能不完整,留着
for (const part of parts) {
  const line = part.replace(/^data:\s*/, '')
  if (line === '[DONE]') return
  const json = JSON.parse(line)
  current.value += json.delta  // 追加到响应式变量
}

这个 buffer.pop() 留尾巴的细节,没踩过坑真想不到。

坑三:响应式数组整体替换,DOM 全量重渲染

我一开始每来一个字就 messages.value = [...messages.value] 整个替换,长对话下肉眼可见卡。后来改成只动最后一条消息对象的 content 字段,让 Vue 的细粒度响应只更新那一个节点,顺多了。

一个没做好的地方

中断逻辑我做得很糙。用户点"停止"我只是把 reader cancel 掉,但后端那边其实还在跑,token 照烧。理想做法是发个 abort 信号给后端真正掐断,这块我留了个 TODO 一直没补。

模型这次我直接走的讯飞 MaaS,现成接口调,省得自己部署推理。前端同学接 SSE 还有啥独门技巧,评论区聊聊。

相关推荐
QCodingDev1 天前
Spring AI Alibaba ReAct Agent实战:从Tool Calling到Agent,企业AI复杂业务该如何设计?
java·人工智能·agent·ai编程·spring ai
Json____1 天前
AI内容创作平台项目源码
人工智能·ai·agent·内容创作·wwwoop.com
冬奇Lab1 天前
Code Agent 解剖(02):agent 是怎么一轮一轮思考和行动的?
人工智能·llm·agent
小马过河R1 天前
不只是又一个 Agent 框架:DeepSeek Harness 如何重新定义“可组合”
人工智能·机器学习·系统架构·agent·ai编程·harness
海兰1 天前
【agent应用】DeepSeek Harness (dsh)介绍及安装部署(Ubuntu24.04)使用指南
人工智能·agent
leeyi1 天前
HITL 源码:8 种人机协同模式的设计(第85篇-E71)
aigc·agent·ai编程
武子康1 天前
Pi 怎样决定模型看见什么:AGENTS.md、SYSTEM.md 与 Skills 的加载边界
人工智能·llm·agent
也非1 天前
制作一键安装DeepSeek Harness安装包,以及创造模式实测
agent·deepseek
宋哥转AI1 天前
深入理解 AI Agent · MEMORY #01:从认知科学到记忆分层,建立完整的记忆认知框架
人工智能·agent·ai编程
TonyLee0171 天前
关于大模型LLM的应用技术栈简记
大模型·agent·提示词工程