Chat 聊天功能
Chat 主要用于 Chatbot 聊天机器人的实现,帮助业务快速搭建自己的 Chatbot 功能。支持 React、Vue2、Vue3 和微信小程序等多个技术栈。
设计理念
Chat SDK 基于 Headless UI 概念设计,专注于提供数据状态管理和业务逻辑处理,不包含任何预置的 UI 组件。
优点:
- 🎨 高度可定制化:完全自由地设计和实现 UI 界面
- 🔧 灵活性强:适配各种设计系统和 UI 框架
- 📦 轻量级:不包含 UI 代码,包体积更小
- 🔄 技术栈无关:可与任何 UI 库或组件库结合使用
注意事项:
- ⚠️ 需要自行实现 UI:开发者需要根据业务需求自行设计和实现聊天界面
- 🛠️ 需要处理样式:消息展示、输入框、按钮等 UI 元素需要自行开发
- 📱 适配工作:不同平台的 UI 适配需要开发者自行处理
推荐组件库:
- React:Ant Design X
- Vue3:TD Chat for AI
架构图
下图展示了 Chat SDK 的三层架构关系:
架构说明
- UI 组件层:各种 UI 组件库和自定义组件,负责聊天界面展示
- Chat SDK 层:🎯 核心抽象层,提供 Headless UI 的状态管理和业务逻辑,支持多端适配
- AI 模型层:各种大语言模型,提供 AI 聊天能力
Chat SDK 的核心价值:
- 📦 解耦 UI 与逻辑:UI 层可以自由选择,SDK 专注于状态管理
- 🔄 统一多端接口:一套 API 适配多个技术栈和 AI 模型
- 🛠️ 简化开发复杂度:封装网络通信、状态管理等底层细节
使用方法
import React from 'react';
import { useChat } from '@tencent/ssv-ai-sdk-react';
import { HunyuanPlugin } from '@tencent/ssv-ai-sdk-plugin-hunyuan';
function ChatComponent() {
const {
input,
setInput,
messages,
assistantStatus,
status,
error,
chat,
stop,
} = useChat({
api: {
chatEndpoint: 'your-sse-endpoint'
},
mode: 'stream',
plugins: [new HunyuanPlugin()]
});
const handleSubmit = async (e) => {
e.preventDefault();
if (status === 'loading' || !input.trim()) return;
await chat({ prompt: input });
};
return (
<div className="chat-container">
{/* 消息列表 */}
<div className="messages">
{messages.map((message) => (
<div key={message.id} className={`message ${message.role}`}>
{message.role}: {message.content}
</div>
))}
</div>
{/* AI 状态显示 */}
<div className="status">
AI 状态: {assistantStatus}
</div>
{/* 输入表单 */}
<form onSubmit={handleSubmit} className="input-form">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="输入消息..."
disabled={status === 'loading'}
/>
{status === 'loading' ? (
<button type="button" onClick={stop}>停止</button>
) : (
<button type="submit">发送</button>
)}
</form>
</div>
);
}
export default ChatComponent;
<template>
<div class="chat-container">
<!-- 消息列表 -->
<div class="messages">
<div
v-for="message in chat.messages"
:key="message.id"
:class="['message', message.role]"
>
{{ message.role }}: {{ message.content }}
</div>
</div>
<!-- AI 状态显示 -->
<div class="status">AI 状态: {{ chat.assistantStatus }}</div>
<!-- 输入表单 -->
<form @submit.prevent="handleSubmit" class="input-form">
<input
:value="chat.input"
@input="(e) => ai.setInput(e.target.value)"
placeholder="输入消息..."
:disabled="chat.status === 'loading'"
/>
<button v-if="chat.status === 'loading'" type="button" @click="ai.stop">
停止
</button>
<button v-else type="submit">发送</button>
</form>
</div>
</template>
<script>
import { ChatMixin } from '@tencent/ssv-ai-sdk-vue2';
import { HunyuanPlugin } from '@tencent/ssv-ai-sdk-plugin-hunyuan';
export default {
mixins: [
ChatMixin({
api: {
chatEndpoint: 'your-sse-endpoint',
},
mode: 'stream',
plugins: [new HunyuanPlugin()],
}),
],
methods: {
async handleSubmit() {
if (this.chat.status === 'loading' || !this.chat.input.trim()) return;
await this.ai.chat({ prompt: this.chat.input });
},
},
};
</script>
<script setup>
import { useChat } from '@tencent/ssv-ai-sdk-vue';
import { HunyuanPlugin } from '@tencent/ssv-ai-sdk-plugin-hunyuan';
const {
messages,
assistantStatus,
status,
chat,
stop,
input,
handleInput,
} = useChat({
api: {
chatEndpoint: 'your-sse-endpoint',
},
mode: 'stream',
plugins: [new HunyuanPlugin()],
});
// 发送消息
const handleSubmit = async () => {
if (status.value === 'loading' || !input.value.trim()) return;
await chat({ prompt: input.value });
};
</script>
<template>
<div class="chat-container">
<!-- 消息列表 -->
<div class="messages">
<div
v-for="message in messages"
:key="message.id"
:class="['message', message.role]"
>
{{ message.role }}: {{ message.content }}
</div>
</div>
<!-- AI 状态显示 -->
<div class="status">
AI 状态: {{ assistantStatus }}
</div>
<!-- 输入表单 -->
<form @submit.prevent="handleSubmit" class="input-form">
<input
:value="input"
@input="handleInput($event.target.value)"
placeholder="输入消息..."
:disabled="status === 'loading'"
/>
<button v-if="status === 'loading'" type="button" @click="stop">
停止
</button>
<button v-else type="submit">发送</button>
</form>
</div>
</template>
// WXML 模板示例:
/*
<view class="chat-container">
<!-- 消息列表 -->
<view class="messages">
<block wx:for="{{chat.messages}}" wx:key="id">
<view class="message {{item.role}}">
{{item.role}}: {{item.content}}
</view>
</block>
</view>
<!-- AI 状态显示 -->
<view class="status">
AI 状态: {{chat.assistantStatus}}
</view>
<!-- 输入表单 -->
<form bindsubmit="handleSubmit" class="input-form">
<input
value="{{chat.input}}"
bindinput="handleInputChange"
placeholder="输入消息..."
disabled="{{chat.status === 'loading'}}"
/>
<button wx:if="{{chat.status === 'loading'}}" bindtap="ai.stop">
停止
</button>
<button wx:else form-type="submit">发送</button>
</form>
</view>
*/
import { ChatBehavior } from '@tencent/ssv-ai-sdk-miniprogram';
import { HunyuanPlugin } from '@tencent/ssv-ai-sdk-plugin-hunyuan';
Component({
behaviors: [
ChatBehavior({
api: {
chatEndpoint: 'your-sse-endpoint'
},
mode: 'stream',
plugins: [new HunyuanPlugin()]
}),
],
methods: {
async handleSubmit() {
if (this.data.chat.status === 'loading' || !this.data.chat.input.trim()) return;
await this.ai.chat({ prompt: this.data.chat.input });
},
handleInputChange(e) {
this.ai.setInput(e.detail.value);
},
},
});
配置 Config
api.chatEndpoint
定义 AI 聊天接口,配置 url
、requestInterceptor
和 responseInterceptor
。
{
// 忽略其他配置...
api: {
chatEndpoint: {
url: 'your-sse-endpoint',
requestInterceptor(options) {
// 可以对请求参数进行拦截和修改
options.headers = {
...options.headers,
'Authorization': 'Bearer your-token',
'Custom-Header': 'custom-value'
};
return options;
},
responseInterceptor(result) {
return {
...result,
messageID: result.id,
content: result.content
}
}
}
}
}
api.chatEndpoint.requestInterceptor
请求拦截器,用于对发送给 AI 接口的请求进行拦截和修改。主要用于添加自定义请求头、身份验证信息或其他请求参数。
interface RequestInterceptor {
(options: RequestOptions): RequestOptions;
}
interface RequestOptions {
// 请求头信息
headers?: Record<string, string>;
// 其他请求配置
[key: string]: any;
}
常见使用场景:
- 添加身份验证令牌
- 设置自定义请求头
- 添加 API 版本信息
- 修改请求超时时间等配置
api.chatEndpoint.responseInterceptor
协议转换器,可接收特定数据。
interface ChatRespInterceptor {
// 消息 ID
messageID: string;
// 回复内容
content: string;
// 推理信息
reason: string;
// 错误信息
error: Object;
}
mode 模式
接口模式,可选 http
和 stream
。
stream
,流式数据。http
,长连接返回。(不推荐)
{
// 忽略其他配置...
mode: 'stream';
}
streamFormat 流式输出方式
流式格式输出,可选 incremental
和 chunked
。会影响到的输出字段有回复内容 content
和思考推理内容 reason
。
incremental
,流式返回为内容叠加,每次后端返回的 content 都为最新的内容,需要在 SDK 内部进行拼接后输出。chunked
,流式返回为完整内容,需要 SDK 内部做覆盖。
{
// 忽略其他配置...
streamFormat: 'incremental';
}
数据 State
input 用户输入
用户输入的文本内容,可以在不同技术栈中使用:
function Component() {
const { input, setInput } = useChat({
// 忽略配置
});
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
</div>
);
}
<template>
<input :value="input" @input="handleInputChange" />
</template>
<script setup>
const { input, setInput } = useChat({
// 忽略配置
});
function handleInputChange(e) {
setInput(e.target.value);
}
</script>
<template>
<input v-model="chat.input" />
<!-- 或者使用 methods 处理 -->
<input :value="chat.input" @input="handleInputChange" />
</template>
<script>
export default {
// ...其他配置
methods: {
handleInputChange(e) {
this.ai.setInput(e.target.value);
},
},
};
</script>
<!-- WXML 模板 -->
<input value="{{chat.input}}" bindinput="handleInputChange" />
<!-- JavaScript -->
<script>
// 在 methods 中
handleInputChange(e) {
this.ai.setInput(e.detail.value);
}
</script>
messages 消息列表
用于存储用户与 AI 的对话记录的数组列表 Message[]
。
interface Message {
// 消息 ID
id: string;
// 角色
role: 'user' | 'assistant';
// 回复内容
content: string;
// 推理内容
reason?: any;
// 接口相关的原始数据
extraInfo: any;
// 文件列表(React、Vue3、Vue2)
files?: FileItem[];
// 错误内容
error?: any;
}
可以根据 Message 列表进行 UI 的渲染:
function Component() {
const { messages } = useChat({
// 忽略配置
});
return (
<div>
{messages.map((message) => (
<div key={message.id}>
{message.role}: {message.content}
</div>
))}
</div>
);
}
<template>
<div class="messages">
<div
v-for="message in messages"
:key="message.id"
:class="['message', message.role]"
>
<div class="content">{{ message.content }}</div>
<div v-if="message.error" class="error">
{{ message.error.message }}
</div>
</div>
</div>
</template>
<template>
<div class="message-list">
<div
v-for="message in chat.messages"
:key="message.id"
:class="['message', message.role]"
>
<div class="content">{{ message.content }}</div>
<div v-if="message.error" class="error">
{{ message.error.message }}
</div>
</div>
</div>
</template>
<!-- WXML 模板 -->
<view class="message-list">
<block wx:for="{{chat.messages}}" wx:key="id">
<view class="message {{item.role}}">
<view class="content">{{item.content}}</view>
<view wx:if="{{item.error}}" class="error"> {{item.error.message}} </view>
</view>
</block>
</view>
files 文件/图片列表
用户上传的文件/图片列表,支持图片等文件类型。
interface FileItem {
// 文件 URL
url?: string;
// 文件类型(小程序)
type?: 'image' | 'video' | 'audio' | 'file';
}
assistantStatus 助手 AI 状态
SDK 提供以下几种 AI 当前的运作状态,用于提供给业务进行精细化展示:
idle
,待开始。一般处于 AI 并没有开始回复的情况。loading
,连接中。用户发送内容后,AI 暂无返回内容信息。thinking
,思考中。AI 正在返回了思考推理(reason)信息。answering
,回答中。AI 正在回复内容(content)信息。
function Component() {
const { assistantStatus } = useChat({
// 忽略配置
});
return <div>{assistantStatus}</div>;
}
<template>
<div class="status-indicator">
<span v-if="assistantStatus === 'idle'">准备就绪</span>
<span v-else-if="assistantStatus === 'answering'">回答中...</span>
</div>
</template>
<template>
<div class="status-indicator">
<span v-if="chat.assistantStatus === 'idle'">准备就绪</span>
<span v-else-if="chat.assistantStatus === 'answering'">回答中...</span>
</div>
</template>
<!-- WXML 模板 -->
<view class="status">AI 状态: {{chat.assistantStatus}}</view>
assistantStatus
是对 status
的 loading 状态的一个拓展。
status 连接状态
status 是用于展示与当前网络接口的连接状态,可选值为:
idle
,连接未开始。loading
,接口连接中。success
,接口返回成功。failed
,接口返回失败。stopped
,接口被中断。
function Component() {
const { status, chat, stop } = useChat({});
return (
<div>
<button onClick={() => chat()} disabled={status === 'loading'}>
发送
</button>
{status === 'loading' && <button onClick={stop}>停止</button>}
</div>
);
}
<template>
<button @click="sendMessage" :disabled="status === 'loading'">发送</button>
<button v-if="status === 'loading'" @click="stopChat">停止</button>
</template>
<template>
<button @click="sendMessage" :disabled="chat.status === 'loading'">
发送
</button>
<button v-if="chat.status === 'loading'" @click="stopChat">停止</button>
</template>
<!-- WXML 模板 -->
<button bindtap="handleSubmit" disabled="{{chat.status === 'loading'}}">
发送
</button>
<button wx:if="{{chat.status === 'loading'}}" bindtap="stopChat">停止</button>
error 错误信息
展示错误信息,可用于直接展示错误信息代替文本回复的内容。
function Component() {
const { error } = useChat({});
return (
<div>
{error && (
<div className="error-message">{error.message || '网络错误'}</div>
)}
</div>
);
}
<template>
<div v-if="error" class="error-message">
{{ error.message || '网络错误' }}
</div>
</template>
<template>
<div v-if="chat.error" class="error-message">
{{ chat.error.message || '网络错误' }}
</div>
</template>
<!-- WXML 模板 -->
<view wx:if="{{chat.error}}" class="error-message">
{{chat.error.message || '网络错误'}}
</view>
方法 Action
chat 发起对话
发起用户对话,会对 API 的 chatEndpoint 配置的 url 接口发送数据,status
会转为 loading
。
参数说明:chat
方法的参数会直接发送给 chatEndpoint
接口,参数结构需要与后端接口保持一致,不是固定格式。用户输入框的内容可以通过 input
字段获取。
const { chat, input } = useChat({});
// 发送当前输入框中的内容
await chat({ prompt: input });
// 或者传入自定义参数(根据后端接口需求调整)
await chat({
message: '自定义问题',
user_id: 'user123',
session_id: 'session456',
// 其他业务相关参数...
});
const { chat, input } = useChat({});
// 发送当前输入框中的内容
chat({ prompt: input.value });
// 或者传入自定义参数(根据后端接口需求调整)
chat({
message: '自定义问题',
context: { user_id: 'user123' },
// 参数结构需要与 chatEndpoint 接口保持一致
});
// 发送当前输入框中的内容
this.ai.chat({ prompt: this.chat.input });
// 或者传入自定义参数(根据后端接口需求调整)
this.ai.chat({
text: '自定义问题',
metadata: { key: 'value' },
// 参数结构需要与 chatEndpoint 接口保持一致
});
// 发送当前输入框中的内容
this.ai.chat({ prompt: this.data.chat.input });
// 或者传入自定义参数(根据后端接口需求调整)
this.ai.chat({
content: '自定义问题',
extra_data: { key: 'value' },
// 参数结构需要与 chatEndpoint 接口保持一致
});
stop 停止对话
手动停止 AI 回复,会触发接口 AbortError,用于断开与 AI 接口的连接。手动停止后,status
会转为 stopped
,assistantStatus
会重置为 idle
。
const { stop } = useChat({});
// 触发停止,status 会转为 stopped
stop();
const { stop } = useChat({});
// 停止当前对话
stop();
// 停止当前对话
this.ai.stop();
// 停止当前对话
this.ai.stop();
setMessages 更新会话列表
用于手动更新会话列表数据,比如进行会话列表的编辑和删除时可以使用。
const { messages, setMessages } = useChat({});
// 清空信息列表
setMessages([]);
const { messages, setMessages } = useChat({});
// 清空信息列表
setMessages([]);
// 添加新消息
const newMessages = [
...messages.value,
{
id: 'new-id',
role: 'user',
content: '新的消息',
},
];
setMessages(newMessages);
// 清空信息列表
this.ai.setMessages([]);
// 添加新消息
const newMessages = [
...this.chat.messages,
{
id: 'new-id',
role: 'user',
content: '新的消息',
},
];
this.ai.setMessages(newMessages);
// 清空信息列表
this.ai.setMessages([]);
// 添加新消息
const newMessages = [
...this.data.chat.messages,
{
id: 'new-id',
role: 'user',
content: '新的消息',
},
];
this.ai.setMessages(newMessages);
setInput 设置输入内容
设置用户输入框内容。
const { setInput } = useChat({});
// 设置输入内容
setInput('预设的问题');
// 清空输入
setInput('');
const { setInput } = useChat({});
// 设置输入内容
setInput('预设的问题');
// 清空输入
setInput('');
// 设置输入内容
this.ai.setInput('预设的问题');
// 清空输入
this.ai.setInput('');
// 设置输入内容
this.ai.setInput('预设的问题');
// 清空输入
this.ai.setInput('');
setFiles 设置文件列表
设置用户上传的文件列表。
const { setFiles } = useChat({});
// 设置单个文件
setFiles([
{
id: 'file-1',
url: '图片链接',
type: 'image',
},
]);
// 清空文件
setFiles([]);
const { files, setFiles } = useChat({});
// 设置单个文件
setFiles([
{
id: 'file-1',
url: '图片链接',
type: 'image',
},
]);
// 增加文件
setFiles([...files.value, newFile]);
// 清空文件
setFiles([]);
// 设置单个文件
this.ai.setFiles([
{
id: 'file-1',
url: '图片链接',
type: 'image',
},
]);
// 增加文件
this.ai.setFiles([...this.chat.files, newFile]);
// 清空文件
this.ai.setFiles([]);
// 设置文件列表
this.ai.setFiles([
{
id: 'file-1',
type: 'image',
url: '图片链接',
},
]);
// 清空文件
this.ai.setFiles([]);
setOptions 更新选项
动态更新聊天配置选项。
const { setOptions } = useChat({});
setOptions({
api: {
chatEndpoint: {
url: 'new-endpoint-url',
},
},
});
const { setOptions } = useChat({});
setOptions({
api: {
chatEndpoint: {
url: 'new-endpoint-url',
},
},
});
this.ai.setOptions({
api: {
chatEndpoint: {
url: 'new-endpoint-url',
},
},
});
this.ai.setOptions({
api: {
chatEndpoint: {
url: 'new-endpoint-url',
},
},
});
on/off 事件监听和卸载
事件监听和卸载函数。
const { on, off } = useChat({});
// 在 useEffect 中监听
useEffect(() => {
const handleError = (error) => {
console.error('发生错误:', error);
};
on('error', handleError);
return () => {
off('error', handleError);
};
}, []);
import { onMounted, onBeforeUnmount } from 'vue';
const { on, off } = useChat({});
// 在组件挂载时设置监听
onMounted(() => {
on('error', handleError);
});
// 在组件卸载前取消监听
onBeforeUnmount(() => {
off('complete', handleComplete);
off('error', handleError);
});
// 事件处理函数
function handleComplete(data) {
console.log('对话完成:', data);
}
function handleError(err) {
console.error('对话错误:', err);
}
export default {
// 在组件创建时设置监听
created() {
this.ai.on('error', this.handleError);
},
// 在组件销毁前取消监听
beforeDestroy() {
this.ai.off('complete', this.handleComplete);
this.ai.off('error', this.handleError);
},
methods: {
handleComplete(data) {
console.log('对话完成:', data);
},
handleError(error) {
console.error('发生错误:', error);
},
},
};
Component({
// 其他配置...
attached() {
// 监听错误事件
this.ai.on('error', this.handleError);
},
detached() {
// 取消监听
this.ai.off('error', this.handleError);
},
methods: {
handleError(error) {
console.error('发生错误:', error);
},
},
});
事件 Events
message 消息
监听原始消息数据,每次接收到流式消息时触发。
const { on, off } = useChat({});
on('message', (data) => {
console.log('收到原始消息:', data);
});
const { on } = useChat({});
on('message', (data) => {
console.log('收到原始消息:', data);
});
this.ai.on('message', (data) => {
console.log('收到原始消息:', data);
});
this.ai.on('message', (data) => {
console.log('收到原始消息:', data);
});
stateChange 状态变化
状态变化事件,当任何状态发生变化时触发,包括消息列表、输入内容、文件列表等。
const { on } = useChat({});
on('stateChange', (state) => {
console.log('状态变化:', state);
// state 包含: messages, error, status, assistantStatus, input, files
});
const { on } = useChat({});
on('stateChange', (state) => {
console.log('状态变化:', state);
});
this.ai.on('stateChange', (state) => {
console.log('状态变化:', state);
});
this.ai.on('stateChange', (state) => {
console.log('状态变化:', state);
});
startReply 开始响应
AI 开始回复事件,在收到第一条流式消息时触发,仅触发一次。
const { on } = useChat({});
on('startReply', (state) => {
console.log('AI 开始回复:', state);
});
const { on } = useChat({});
on('startReply', (state) => {
console.log('AI 开始回复:', state);
});
this.ai.on('startReply', (state) => {
console.log('AI 开始回复:', state);
});
this.ai.on('startReply', (state) => {
console.log('AI 开始回复:', state);
});
startAnswer 开始回答
AI 开始回答事件,当助手状态从思考转为回答时触发。
const { on } = useChat({});
on('startAnswer', (state) => {
console.log('AI 开始回答:', state);
});
const { on } = useChat({});
on('startAnswer', (state) => {
console.log('AI 开始回答:', state);
});
this.ai.on('startAnswer', (state) => {
console.log('AI 开始回答:', state);
});
this.ai.on('startAnswer', (state) => {
console.log('AI 开始回答:', state);
});
error 错误
错误事件,当发生错误时触发。
const { on } = useChat({});
on('error', (error) => {
console.error('发生错误:', error);
});
const { on } = useChat({});
on('error', (error) => {
console.error('发生错误:', error);
});
this.ai.on('error', (error) => {
console.error('发生错误:', error);
});
this.ai.on('error', (error) => {
console.error('发生错误:', error);
});