Vercel AI SDK 中的生成式 UI 开发指南
ai 项目地址: https://gitcode.com/gh_mirrors/ai1/ai
什么是生成式 UI?
生成式 UI 是一种由 AI 模型动态决定渲染内容的用户界面范式。随着 GPT-3.5+ 等语言模型引入函数调用功能,开发者现在可以创建更加智能和交互式的用户界面。Vercel AI SDK 通过 ai/rsc
包,结合 React Server Components 和 Server Actions,为开发者提供了无缝集成这种能力的工具。
核心概念解析
AIState 与 UIState 的分离
Vercel AI SDK 引入了两个关键状态概念:
-
AIState:存储在服务器端的 JSON 数据结构,包含 LLM 需要的所有上下文信息。在聊天应用中,通常存储用户与助手之间的对话历史,也可以包含其他元数据如消息创建时间。
-
UIState:完全客户端的状态(类似于 useState),用于存储和显示 LLM 返回的数据和 UI 元素。这个状态可以是任何形式,但不能在服务器端访问。
这种分离设计既保证了 AI 操作的安全性,又确保了 UI 渲染的高效性。
实战开发指南
环境准备
- 确保已安装 Node.js 18+ 版本
- 获取 OpenAI API 密钥
- 创建 Next.js 应用(推荐使用 App Router)
基础配置步骤
-
安装必要依赖:
pnpm install ai openai zod
-
配置环境变量:
OPENAI_API_KEY=your_api_key_here
核心实现代码
服务器端 AI 实例创建
import { createAI, getMutableAIState, render } from "ai/rsc";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
async function submitUserMessage(userInput: string) {
'use server';
const aiState = getMutableAIState<typeof AI>();
aiState.update([...aiState.get(), { role: 'user', content: userInput }]);
const ui = render({
model: 'gpt-4',
provider: openai,
messages: [
{ role: 'system', content: 'You are a helpful assistant' },
...aiState.get()
],
text: ({ content, done }) => {
if (done) {
aiState.done([...aiState.get(), { role: "assistant", content }]);
}
return <p>{content}</p>
},
tools: {
// 工具函数定义
}
});
return { id: Date.now(), display: ui };
}
export const AI = createAI({
actions: { submitUserMessage },
initialUIState: [],
initialAIState: []
});
客户端集成
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<AI>{children}</AI>
</body>
</html>
);
}
消息收发实现
export default function Page() {
const [inputValue, setInputValue] = useState('');
const [messages, setMessages] = useUIState<typeof AI>();
const { submitUserMessage } = useActions<typeof AI>();
const handleSubmit = async (e) => {
e.preventDefault();
setMessages([...messages, { id: Date.now(), display: <div>{inputValue}</div> }]);
const response = await submitUserMessage(inputValue);
setMessages([...messages, response]);
setInputValue('');
};
return (
<div>
{messages.map((message) => (
<div key={message.id}>{message.display}</div>
))}
<form onSubmit={handleSubmit}>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Send a message..."
/>
</form>
</div>
);
}
高级应用场景
服务器端更新请求
生成式 UI 经常需要从服务器获取更新数据。例如,天气应用可能需要定期获取最新天气数据:
async function getCityWeather() {
'use server';
const card = createStreamableUI(<Spinner />);
// 获取天气数据逻辑
const temperature = await fetchWeatherData();
card.done(
<WeatherCard
temperature={temperature}
refreshAction={async () => {
'use server';
return fetchWeatherData(); // 可刷新的服务器操作
}}
/>
);
return { ui: card.value };
}
客户端状态更新
当用户与 UI 交互(如滑动滑块)时,可以更新 AI 状态:
function StockSlider({ name, price }) {
const [aiState, setAIState] = useAIState<typeof AI>();
const id = useId();
const handleChange = (e) => {
const newValue = Number(e.target.value);
const info = {
role: 'assistant',
content: `[User selected ${newValue} shares of ${name}]`,
id
};
// 智能更新 AI 状态
if (aiState[aiState.length - 1]?.id === id) {
setAIState([...aiState.slice(0, -1), info]);
} else {
setAIState([...aiState, info]);
}
};
return <input type="range" onChange={handleChange} />;
}
嵌套 UI 流式传输
Vercel AI SDK 支持在 UI 组件中嵌套流式组件,构建复杂界面:
async function getStockInfo() {
'use server';
const ui = createStreamableUI(<Spinner />);
const chart = createStreamableUI(<Spinner />);
(async () => {
const price = await fetchStockPrice();
ui.done(<StockCard chart={chart.value} price={price} />);
const history = await fetchStockHistory();
chart.done(<HistoryChart data={history} />);
})();
return ui;
}
最佳实践建议
-
状态管理:合理区分 AIState 和 UIState 的使用场景,避免不必要的状态同步
-
错误处理:为所有异步操作添加适当的错误处理逻辑
-
性能优化:对于频繁更新的 UI 元素,考虑使用防抖或节流技术
-
可访问性:确保生成的 UI 符合无障碍访问标准
-
测试策略:针对 AI 生成的 UI 建立完善的测试方案
通过 Vercel AI SDK 的生成式 UI 功能,开发者可以创建更加智能、动态和个性化的用户体验,同时保持代码的可维护性和性能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考