最近一段时间一直在忙,好久没有更新了,最近做了个AI对话框的项目,现在闲下来了做个总结
这里是直接对接的腾讯的大模型知识引擎,调用的腾讯的开发API接口,前端页面腾讯提供了vue2版本的前端开源项目,但是博主是利用vue3开发的,所以只采用了腾讯的对话渲染组件
腾讯前端页面接入可参考:cloud.tencent.com/document/pr…
1.流式渲染对话
AI对话框最核心的一个点就是对话流式生成,腾讯大模型知识引擎提供了两种交互方式,一种是全双工通道,WebSocket ;另一种是单向通道HTTP SSE。因为该AI聊天框暂时不需要进行双向交互,所以采用的HTTP SSE交互方式。SSE之前我也没有接触过,但是也不难,下面是AI的介绍可以简单参考一下:
SSE的核心特性
- 单向通信 SSE 仅支持服务器到客户端的单向通信,适用于服务器主动推送实时数据的场景(如新闻推送、股票价格更新)。相比 WebSocket 的双向通信,SSE 更轻量且实现简单
- 流式返回机制 SSE 通过 HTTP 长连接实现流式传输,服务器将数据以事件流(Event Stream)的形式持续发送。每次推送的数据通过 data: 字段标记,客户端通过监听事件逐步接收并处理数据,从而实现“边生成边传输”的效果。例如,ChatGPT 的逐字回复即依赖此机制
- 数据格式规范
- 事件流格式:每个事件由字段组成(如 data、id、event),以换行符分隔,事件之间用两个换行符分隔。
下面是一个返回的数据
所以简单理解就是把消息一遍一遍返回,然后前端进行内容渲染就很简单了
调用方式
这里采用了fetchEventSource,一个基于 Fetch API 实现的 JavaScript 库,专为处理 Server-Sent Events(SSE) 设计,旨在克服浏览器原生 EventSource
API 的局限性,提供更灵活、可控的实时数据流处理能力
-
安装
npm install @microsoft/fetch-event-source
-
基本代码结构
import { fetchEventSource } from '@microsoft/fetch-event-source'; fetchEventSource('/api/stream', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: 'data' }), onopen: (response) => { /* 连接验证逻辑 */ }, onmessage: (msg) => { console.log(msg.data); }, onerror: (err) => { /* 错误处理 */ } });
onmessage里就是返回的内容,腾讯给的字段很丰富,这里根据字段判断进行渲染就可以了
2.每次生成对话自动定位到对话框底部
这个功能算是一个增加用户体验的功能点,实现也很简单,主要利用原生scrollTo方法
初始化时增加滚动监听,并增加判断是用户手动滚动还是自动滚动
sDom.addEventListener('scroll', () => {
//msgLists为消息内容列表,is_final来判断是否回答完毕
if (msgLists.value[msgLists.value.length - 1].is_final === false && !jsScrolling.value) {
//若满足条件,则设置 userScrolling.value = true,标记用户正在手动干预滚动位置,暂停自动滚动,
userScrolling.value = true;
} else {
//消息已处于最终状态,滚动行为结束
jsScrolling.value = false;
}
});
每次接收消息时,在onmessage中执行滚动
// 对话框滚动至底部
const sDom = document.querySelector('.client-chat');
if (!sDom) return;
//通过 !userScrolling.value 判断用户未手动滚动,此时允许程序触发自动滚动
if (!userScrolling.value) {
jsScrolling.value = true;
sDom.scrollTo({
top: sDom.scrollHeight
});
}
//当最后一条消息的 is_final 属性为 true(流式响应结束),设置 userScrolling.value = false,允许后续新消息触发自动滚动。
if (msgLists.value.length > 0 && msgLists.value[msgLists.value.length - 1].is_final === true) {
userScrolling.value = false;
}
其他
AI对话框还是其他很多功能点,比如暂停回答、发送内容、历史对话获取、点赞评论等等功能,这些也都是比较常见的功能点,不再一一列举,其实主要核心点还是对话流式渲染,腾讯这方面很给力,给了模版
题外话
在完成这个项目后,进行了一些测试,发现腾讯渲染组件的一个bug,当回答内容过快且是第一条回答内容时,组件内容会截断,就是停止渲染
就像下面这种,页面展示内容:
而实际接口返回:
这里可以已经看到返回完了,一开始还是以为是自己的问题,但经过一段排查发现是组件的问题。
试了同样vue2版本未发现这个问题,而vue3版本组件有这个问题,很奇怪。vue3渲染组件地址
目前采用的解决方法是判断返回内容是最后一条时,通过v-if进行重新渲染该组件,返回内容会重新渲染
不知道各位有没有遇到过这个问题?