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) 提供被引用的訊息。
