自定义框架适配器
为什么需要自定义框架适配器
AI SDK 采用了分层架构设计,核心功能集中在 @tencent/ssv-ai-sdk-shared
包中,通过 AIChat
类提供统一的 AI 聊天能力。然而,不同的前端框架(React、Vue、Angular 等)都有各自独特的:
- 响应式系统:React 的 state/hooks、Vue 的 reactive、Angular 的 RxJS 等
- 生命周期管理:组件挂载、更新、销毁的时机和方式不同
- API 风格:Hook 函数、Class 组件、Options API 等不同的编程范式
直接使用核心的 AIChat
类虽然可行,但无法与框架的响应式系统完美集成,开发者需要手动处理状态同步、生命周期管理等复杂问题。因此需要为不同框架创建适配器,将 AI SDK 的能力无缝集成到各个框架的开发体验中。
适配器连接 UI 框架需要做的几点
创建自定义框架适配器主要需要处理以下几个核心问题:
1. 创建和管理 AIChat 实例
在适当的时机初始化 AIChat
实例,选择合适的平台适配器(浏览器环境使用 BrowserAdapter
,小程序环境使用 MiniprogramAdapter
)。
2. 状态同步机制
将 AIChat
的状态变化同步到框架的响应式系统中,确保 UI 能够实时响应状态变化。通过监听 AIEvents.STATE_CHANGE
事件来实现。
3. 生命周期管理
在组件创建时初始化 AI 实例,在组件销毁时正确释放资源,避免内存泄漏。
4. API 封装
提供符合框架习惯的 API 接口,隐藏底层 AIChat
的复杂性,让开发者能够用熟悉的方式使用 AI 功能。
React 适配器实现示例
以下是一个完整的 React Hook 适配器实现,展示了上述四个要点的具体实现:
typescript
import { useState, useEffect, useRef, useCallback } from 'react';
import { AIChat, AIEvents, BrowserAdapter } from '@tencent/ssv-ai-sdk-shared';
import type {
ChatOptions,
ChatParams,
ChatState,
Message,
FileItem,
} from '@tencent/ssv-ai-sdk-shared';
interface ChatResult extends ChatState {
chat: (params: ChatParams) => Promise<void>;
stop: () => void;
setInput: (value: string) => void;
setFiles: (files: FileItem[]) => void;
setMessages: (messages: Message[]) => void;
setOptions: (options: Partial<ChatOptions>) => void;
// 事件监听器
on: (event: string, callback: (...args: any[]) => void) => void;
off: (event: string, callback: (...args: any[]) => void) => void;
}
export function useChat(options: ChatOptions): ChatResult {
// 2. 状态同步机制:使用 React 的 useState 管理 AI 状态
const [state, setState] = useState<ChatState>({
messages: [],
error: null,
status: 'idle',
input: '',
files: [],
assistantStatus: 'idle',
});
// 1. 创建和管理 AIChat 实例:使用 useRef 保持实例引用
const aiInstanceRef = useRef<AIChat | null>(null);
// 3. 生命周期管理:在组件挂载时初始化,卸载时清理
useEffect(() => {
// 创建 AIChat 实例,选择浏览器适配器
aiInstanceRef.current = new AIChat({
adapter: new BrowserAdapter(),
...options,
});
// 2. 状态同步机制:监听状态变化并同步到 React state
aiInstanceRef.current.on(AIEvents.STATE_CHANGE, (newState: ChatState) => {
setState(newState);
});
// 3. 生命周期管理:组件卸载时清理资源
return () => {
aiInstanceRef.current?.dispose();
};
}, []);
// 4. API 封装:提供符合 React Hook 习惯的方法
const chat = useCallback(async (params: ChatParams): Promise<void> => {
if (!aiInstanceRef.current) return;
// 获取最新状态并进行输入验证
const { input, files } = aiInstanceRef.current.getState();
if (!input.trim() && (!files || files.length === 0)) {
console.warn(
'chat 输入为空且无文件上传,用户消息可能显示异常。请在 chat 调用前,通过 setInput 和 setFiles 设置用户内容。'
);
}
try {
await aiInstanceRef.current.chat(params);
} catch (err: any) {
setState((prev) => ({
...prev,
error: err instanceof Error ? err : new Error('Unknown error occurred'),
status: 'failed',
}));
}
}, []);
const stop = useCallback(() => {
aiInstanceRef.current?.stop();
}, []);
const setInput = useCallback((value: string) => {
aiInstanceRef.current?.setInput(value);
}, []);
const setFiles = useCallback((files: FileItem[]) => {
aiInstanceRef.current?.setFiles(files);
}, []);
const setMessages = useCallback((messages: Message[]) => {
aiInstanceRef.current?.updateMessages(messages);
}, []);
const setOptions = useCallback((options: Partial<ChatOptions>) => {
aiInstanceRef.current?.setOptions(options);
}, []);
// 事件监听器方法
const on = useCallback(
(event: string, callback: (...args: any[]) => void) => {
aiInstanceRef.current?.on(event, callback);
},
[]
);
const off = useCallback(
(event: string, callback: (...args: any[]) => void) => {
aiInstanceRef.current?.off(event, callback);
},
[]
);
// 4. API 封装:返回状态和操作方法的组合
return {
...state,
chat,
stop,
setInput,
setFiles,
setMessages,
setOptions,
on,
off,
};
}
使用示例
typescript
// 在 React 组件中使用自定义适配器
function ChatComponent() {
const chatResult = useChat({
api: {
apiUrl: 'https://your-api-endpoint.com',
headers: {
Authorization: 'Bearer your-token',
},
},
mode: 'stream',
});
// 使用事件监听器监听特定事件
useEffect(() => {
const handleMessageReceived = (data: any) => {
console.log('收到新消息:', data);
};
// 添加事件监听
chatResult.on('message', handleMessageReceived);
// 清理事件监听
return () => {
chatResult.off('message', handleMessageReceived);
};
}, []);
const handleSendMessage = async () => {
await chatResult.chat({
messages: [
...chatResult.messages,
{ role: 'user', content: chatResult.input },
],
});
};
return (
<div>
<div>
{chatResult.messages.map((msg, index) => (
<div key={index}>{msg.content}</div>
))}
</div>
{chatResult.error && (
<div style={{ color: 'red' }}>错误: {chatResult.error.message}</div>
)}
<input
value={chatResult.input}
onChange={(e) => chatResult.setInput(e.target.value)}
/>
<button
onClick={handleSendMessage}
disabled={chatResult.status === 'loading'}
>
{chatResult.status === 'loading' ? '发送中...' : '发送'}
</button>
{chatResult.status === 'loading' && (
<button onClick={chatResult.stop}>停止</button>
)}
</div>
);
}
总结
通过以上四个核心步骤,你可以为任何前端框架创建自定义的 AI SDK 适配器:
- 实例管理:正确创建和管理
AIChat
实例 - 状态同步:将 AI 状态同步到框架的响应式系统
- 生命周期:处理组件的创建和销毁
- API 设计:提供符合框架习惯的接口
参考官方适配器实现:@tencent/ssv-ai-sdk-react
、@tencent/ssv-ai-sdk-vue
、@tencent/ssv-ai-sdk-vue2
、@tencent/ssv-ai-sdk-miniprogram
。