AI 回复
用户和 AI 机器人单聊时,机器人的回复是一条 type 为 ai 的消息,内容边生成边推送过来。Web SDK 的 im.ai 负责接收这些实时内容:按顺序拼接、断线后续传、重新上线时补发,回复结束后以消息正文为准;你只需要显示。React UIKit 和 Vue UIKit 已内置 AI 回复的显示。机器人和回复由你的服务端创建,见 AI 对话。
版本
AI 回复从 npm 1.0.6 起提供:@deeprespond/im-web、@deeprespond/im-web-react、@deeprespond/im-web-vue、@deeprespond/im-web-react-uikit、@deeprespond/im-web-vue-uikit。安装见概述与安装。
机器人
机器人在客户端就是一个普通用户:用户资料的 kind 为 bot,可以加好友、出现在会话列表中,用户像平常一样给它发文字消息即可。机器人不能被拉进群,在群里邀请机器人会失败(permission_denied,details.reason 为 bot_account)。
AI 消息
message.type 为 ai 时,用 im.ai.bodyOf(message) 读取正文:
const body = im.ai.bodyOf(message); // 不是 ai 消息时为 null
if (body) {
console.log(body.status); // 'streaming' | 'completed' | 'stopped' | 'failed'
console.log(body.parts); // 结束后的完整内容;生成中为空数组
}| 字段 | 说明 |
|---|---|
stream_id | 这条回复的流 ID,读取实时内容、停止生成时使用 |
status | streaming 生成中,completed 已完成,stopped 已停止,failed 生成中断 |
parts | 片段:text 正文(Markdown),reasoning 思考过程,image、file 附件,tool 工具调用的进度(state 为 running、done、failed) |
text | 正文去掉 Markdown 后的纯文本,最多 2000 个字符,会话列表预览、复制时使用 |
finish_reason、error | 结束原因;生成中断时 error.message 是要显示给用户的说明 |
片段的完整说明见 AI 消息。会话列表的预览、未读数、搜索与普通消息相同,使用 text。
显示生成中的内容
生成中的消息 parts 为空,实时内容在 im.ai.state(streamId) 中,每次更新触发 ai.streamUpdated:
function renderAI(message: MessageView) {
const body = im.ai.bodyOf(message);
if (!body) return;
const parts = body.status === 'streaming' ? im.ai.state(body.stream_id)?.parts ?? [] : body.parts;
draw(message, parts, body.status);
}
im.on('ai.streamUpdated', (state) => {
// state.stream_id、state.parts(当前完整内容,不是增量)、state.seq
redrawByStream(state.stream_id, state.parts);
});
im.on('ai.streamEnded', ({ stream_id, status }) => {
// 回复结束:随后(或已经)收到这条消息的 messages.changed,重新读取消息、以正文为准
});| 事件 | 时机 |
|---|---|
ai.streamStarted | 收到一条生成中的 AI 消息 |
ai.streamUpdated | 内容更新:收到新的内容,或断线续传、重新上线后补齐;parts 为当前完整内容 |
ai.streamEnded | 回复结束;最终内容在消息正文中,消息会以 messages.changed 更新 |
- 推送合并为每 50 毫秒或 2 KB 一次,界面直接按
parts整体重绘即可。 - 断线、切到后台再回来、刷新页面、换设备登录时,SDK 自动补齐正在生成的内容,不需要处理。
- 多个标签页共用一个连接时,各标签页都会收到这些事件。
im.ai.state()在回复结束后返回null,之后读取消息正文。
在 React 和 Vue 中
React 绑定和 Vue 绑定提供 useAIStream(streamId),返回 im.ai.state(streamId) 并随 ai.* 事件更新,回复结束后为 null:
// React(@deeprespond/im-web-react)
function AIMessage({ message }: { message: MessageView }) {
const im = useDRClient();
const body = im?.ai.bodyOf(message);
const live = useAIStream(body?.status === 'streaming' ? body.stream_id : null);
const parts = live?.parts ?? body?.parts ?? [];
return <AIParts parts={parts} streaming={body?.status === 'streaming'} />;
}// Vue(@deeprespond/im-web-vue):参数可以是 ref 或 getter
const live = useAIStream(() => (body.value?.status === 'streaming' ? body.value.stream_id : null));整理成视图
自己绘制时,@deeprespond/im-web/render 的 aiView(message, live) 把一条 AI 消息整理成视图:思考过程、工具调用的状态(结束时仍在进行的标为 canceled)、正文块(Markdown 转成节点数组,链接只保留文字)、附件、生成中断的说明和复制用的纯文本;markdownNodes(text) 单独转换一段 Markdown。小程序、uni-app、Tauri 的示例都用它显示,字段见小程序 SDK 的 AI 回复。
import { aiView } from '@deeprespond/im-web/render';
const view = aiView(message, im.ai.state(streamId)); // 不是 ai 消息时为 null停止生成
const stream = await im.ai.stop(body.stream_id);
// stream.status 为 'stopped';已结束的回复返回当前状态,不报错只有接收回复的用户可以停止。停止后回复立即结束,已生成的内容保留,机器人的服务端会收到停止通知。
需要从服务端读取一条回复的当前内容(如排查问题)时用 im.ai.get(streamId);结束超过 10 分钟的返回 not_found,改为读取消息。
重新生成
平台没有单独的“重新生成”接口:再发一次被回复的问题,机器人的服务端会开始一条新的回复。AI 消息的 reply_to 指向它回答的那条消息。
React UIKit
React UIKit 的聊天界面已内置 AI 消息的显示,不需要额外配置:
- 正文按 Markdown 渲染(标题、列表、引用、代码块、表格、链接),生成中末尾显示光标;
- 思考过程默认折叠,生成中显示“思考中”;
- 工具调用显示进度(进行中、完成、失败、已取消);
- 图片、文件附件;
- 生成中显示“停止生成”按钮;结束后提供“复制”和“重新生成”;
- 已停止、生成中断(带原因说明)的提示。
自定义消息列表时,AI 消息可以继续交给 UIKit 导出的 MessageBubble 显示,或按上一节自己绘制。
Vue UIKit
Vue UIKit 的聊天界面同样内置 AI 消息的显示,效果与 React UIKit 一致。“重新生成”在 AI 消息引用了用户的提问(reply_to)、并且这条提问在当前消息列表中时显示,点击后再发一次这条提问;独立使用 MessageBubble 时通过 findMessage(seq) 提供被引用的消息。
