关于 ai-sdk-ui
ai-sdk-ui 是面向 React 前端开发者的 Vercel AI SDK UI 技能,介绍构建聊天与生成式界面的 Hook 用法。内容涵盖流式消息、工具审批和迁移排错。
主要功能
- 01React 聊天与补全 Hook
- 02流式消息和结构化输出
- 03工具调用与审批流程
- 04文件附件和消息持久化
- 05迁移指南与常见错误排查
适用场景
- 01构建 React 或 Next.js AI 聊天界面
- 02在界面中展示流式回复和工具调用
- 03为工具执行加入用户确认
- 04排查 useChat 集成问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill ai-sdk-ui安装后在 Claude Code 中输入/ai-sdk-ui确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.md.claude-plugin/plugin.jsonreferences/links-to-official-docs.mdnextjs-integration.mdstreaming-patterns.mdtop-ui-errors.mduse-chat-migration.mdrules/ai-sdk-ui.mdscripts/check-versions.shtemplates/custom-message-renderer.tsxmessage-persistence.tsxnextjs-api-route.tsnextjs-chat-app-router.tsxnextjs-chat-pages-router.tsxpackage.jsonuse-chat-attachments.tsxuse-chat-basic.tsxuse-chat-tools.tsxuse-completion-basic.tsxuse-object-streaming.tsx详细介绍
AI SDK UI - 前端 React Hooks
使用 Vercel AI SDK v6 构建 AI 驱动用户界面的前端 React Hooks。
版本:AI SDK v6.0.42(稳定版) 框架:React 18+/19、Next.js 14+/15+ 最后更新:2026-01-20
AI SDK v6 稳定版(2026 年 1 月)
状态: 稳定版 最新版本: [email protected]、@ai-sdk/[email protected]、@ai-sdk/[email protected] 迁移: 从 v5 → v6 的破坏性变更极少
v6 中的全新 UI 功能
1. 消息部分结构(破坏性变更)
在 v6 中,消息内容现在通过 .parts 数组访问,而不是 .content:
// ❌ v5 (OLD)
{messages.map(m => (
<div key={m.id}>{m.content}</div>
))}
// ✅ v6 (NEW)
{messages.map(m => (
<div key={m.id}>
{m.parts.map((part, i) => {
if (part.type === 'text') return <span key={i}>{part.text}</span>;
if (part.type === 'tool-invocation') return <ToolCall key={i} tool={part} />;
if (part.type === 'file') return <FilePreview key={i} file={part} />;
return null;
})}
</div>
))}
部分类型:
text- 文本内容,通过.text属性获取tool-invocation- 工具调用,包含.toolName、.args、.resultfile- 文件附件,包含.mimeType、.datareasoning- 模型推理(如果可用)source- 来源引用
3. Agent 集成
使用 InferAgentUIMessage<typeof agent> 实现类型安全的 Agent 消息传递:
import { useChat } from '@ai-sdk/react';
import type { InferAgentUIMessage } from 'ai';
import { myAgent } from './agent';
export default function AgentChat() {
const { messages, sendMessage } = useChat<InferAgentUIMessage<typeof myAgent>>({
api: '/api/chat',
});
// messages are now type-checked against agent schema
}
4. 工具审批工作流(人在回路中) 在执行工具之前请求用户确认:
import { useChat } from '@ai-sdk/react';
import { useState } from 'react';
export default function ChatWithApproval() {
const { messages, sendMessage, addToolApprovalResponse } = useChat({
api: '/api/chat',
});
const handleApprove = (toolCallId: string) => {
addToolApprovalResponse({
toolCallId,
approved: true, // or false to deny
});
};
return (
<div>
{messages.map(message => (
<div key={message.id}>
{message.toolInvocations?.map(tool => (
tool.state === 'awaiting-approval' && (
<div key={tool.toolCallId}>
<p>Approve tool call: {tool.toolName}?</p>
<button onClick={() => handleApprove(tool.toolCallId)}>
Approve
</button>
<button onClick={() => addToolApprovalResponse({
toolCallId: tool.toolCallId,
approved: false
})}>
Deny
</button>
</div>
)
))}
</div>
))}
</div>
);
}
5. 自动提交功能 处理完审批后自动继续对话:
import { useChat, lastAssistantMessageIsCompleteWithApprovalResponses } from '@ai-sdk/react';
export default function AutoSubmitChat() {
const { messages, sendMessage } = useChat({
api: '/api/chat',
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
// Automatically resubmit after all approval responses provided
});
}
6. 聊天中的结构化输出
在调用工具的同时生成结构化数据(此前仅在 useObject 中可用):
import { useChat } from '@ai-sdk/react';
import { z } from 'zod';
const schema = z.object({
summary: z.string(),
sentiment: z.enum(['positive', 'neutral', 'negative']),
});
export default function StructuredChat() {
const { messages, sendMessage } = useChat({
api: '/api/chat',
// Server can now stream structured output with chat messages
});
}
useChat Hook - v4 → v5 破坏性变更
重要:v5 中的 useChat 不再管理输入状态!
v4(旧版 - 请勿使用):
const { messages, input, handleInputChange, handleSubmit, append } = useChat();
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
</form>
v5(新版 - 正确用法):
const { messages, sendMessage } = useChat();
const [input, setInput] = useState('');
<form onSubmit={(e) => {
e.preventDefault();
sendMessage({ content: input });
setInput('');
}}>
<input value={input} onChange={(e) => setInput(e.target.value)} />
</form>
v5 变更摘要:
- 移除输入管理:不再提供
input、handleInputChange、handleSubmit append()→sendMessage():用于发送消息的新方法- 移除
onResponse:改用onFinish initialMessages→ 受控模式:使用messages属性进行完全控制- 移除
maxSteps:仅在服务端处理
完整的迁移指南请参阅 references/use-chat-migration.md。
useAssistant Hook(已弃用)
⚠️ 弃用通知:
useAssistant自 AI SDK v5 起已弃用。OpenAI Assistants API v2 将于 2026 年 8 月 26 日停止服务。新项目请改用useChat和自定义后端逻辑。 迁移指南请参阅 openai-assistants 技能。
通过自动管理 UI 状态,与兼容 OpenAI 的助手 API 交互。
导入:
import { useAssistant } from '@ai-sdk/react';
基本用法:
'use client';
import { useAssistant } from '@ai-sdk/react';
import { useState, FormEvent } from 'react';
export default function AssistantChat() {
const { messages, sendMessage, isLoading, error } = useAssistant({
api: '/api/assistant',
});
const [input, setInput] = useState('');
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
sendMessage({ content: input });
setInput('');
};
return (
<div>
{messages.map(m => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isLoading}
/>
</form>
{error && <div>{error.message}</div>}
</div>
);
}
使用场景:
- 构建由 OpenAI Assistant 驱动的 UI
- 管理助手线程和运行
- 在管理 UI 状态的同时流式传输助手回复
- 集成文件搜索和代码解释器
完整 API 参考请参阅官方文档:https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-assistant
常见 UI 错误及解决方案
完整文档请参阅 references/top-ui-errors.md。快速参考:
1. useChat 无法解析流
错误:SyntaxError: Unexpected token in JSON at position X
原因:API 路由未返回正确的流格式。
解决方案:
// ✅ CORRECT
return result.toDataStreamResponse();
// ❌ WRONG
return new Response(result.textStream);
2. useChat 没有响应
原因:API 路由未正确进行流式传输。
解决方案:
// App Router - use toDataStreamResponse()
export async function POST(req: Request) {
const result = streamText({ /* ... */ });
return result.toDataStreamResponse(); // ✅
}
// Pages Router - use pipeDataStreamToResponse()
export default async function handler(req, res) {
const result = streamText({ /* ... */ });
return result.pipeDataStreamToResponse(res); // ✅
}
3. 部署后无法进行流式传输
原因:部署平台正在缓冲响应。
解决方案:Vercel 会自动检测流式传输。其他平台可能需要配置。
4. useChat 的 body 值过时
原因:body 选项仅在首次渲染时捕获。
解决方案:
// ❌ WRONG - body captured once
const { userId } = useUser();
const { messages } = useChat({
body: { userId }, // Stale!
});
// ✅ CORRECT - use controlled mode
const { userId } = useUser();
const { messages, sendMessage } = useChat();
sendMessage({
content: input,
data: { userId }, // Fresh on each send
});
5. React 更新深度超限
原因:useEffect 中存在无限循环。
解决方案:
// ❌ WRONG
useEffect(() => {
saveMessages(messages);
}, [messages, saveMessages]); // saveMessages triggers re-render!
// ✅ CORRECT
useEffect(() => {
saveMessages(messages);
}, [messages]); // Only depend on messages
references/top-ui-errors.md 中还记录了 13 种常见错误(共 18 种)。
流式传输最佳实践
性能
始终使用流式传输,提升用户体验:
// ✅ GOOD - Streaming (shows tokens as they arrive)
const { messages } = useChat({ api: '/api/chat' });
// ❌ BAD - Non-streaming (user waits for full response)
const response = await fetch('/api/chat', { method: 'POST' });
用户体验模式
显示加载状态:
{isLoading && <div>AI is typing...</div>}
提供停止按钮:
{isLoading && <button onClick={stop}>Stop</button>}
自动滚动到最新消息:
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
加载期间禁用输入:
<input disabled={isLoading} />
全面的最佳实践请参阅 references/streaming-patterns.md。
React Strict Mode 注意事项
React Strict Mode 会有意双重调用 effect,以发现错误。在 effect 中使用 useChat 或 useCompletion(自动恢复、初始消息)时,请添加保护,避免重复执行,以防重复调用 API 并浪费令牌。
问题:
'use client';
import { useChat } from '@ai-sdk/react';
import { useEffect } from 'react';
export default function Chat() {
const { messages, sendMessage, resumeStream } = useChat({
api: '/api/chat',
resume: true,
});
useEffect(() => {
// ❌ Triggers twice in strict mode → two concurrent streams
sendMessage({ content: 'Hello' });
// or
resumeStream();
}, []);
}
解决方案:
// ✅ Use ref to track execution
import { useRef } from 'react';
const hasSentRef = useRef(false);
useEffect(() => {
if (hasSentRef.current) return;
hasSentRef.current = true;
sendMessage({ content: 'Hello' });
}, []);
// For resumeStream specifically:
const hasResumedRef = useRef(false);
useEffect(() => {
if (!autoResume || hasResumedRef.current || status === 'streaming') return;
hasResumedRef.current = true;
resumeStream();
}, [autoResume, resumeStream, status]);
发生原因: React Strict Mode 会双重调用 effect,以暴露副作用。SDK 不会防范并发请求,因此两次调用会分别创建独立的数据流,并争相更新状态。
影响: 消息重复、令牌用量翻倍,以及导致 TypeError: "Cannot read properties of undefined (reading 'state')" 的竞态条件。
来源: GitHub Issue #7891、Issue #6166
何时使用此技能
适用于以下场景:
- 构建 React 聊天界面
- 在 UI 中实现 AI 补全
- 将 AI 响应流式传输到前端
- 构建 Next.js AI 应用
- 处理聊天消息状态
- 在 UI 中显示工具调用
- 管理 AI 文件附件
- 从 v4 迁移到 v5(UI hooks)
- 遇到 useChat/useCompletion 错误
不适用于以下场景:
- 需要后端 AI 功能 → 改用 ai-sdk-core
- 构建非 React 前端(Svelte、Vue)→ 查阅官方文档
- 需要 Generative UI / RSC → 参见 https://ai-sdk.dev/docs/ai-sdk-rsc
- 构建原生应用 → 需要其他 SDK
相关技能:
- ai-sdk-core - 后端文本生成、结构化输出、工具和 Agent
- 将两者结合,用于构建全栈 AI 应用
软件包版本
稳定版(v6 - 推荐):
{
"dependencies": {
"ai": "^6.0.8",
"@ai-sdk/react": "^3.0.6",
"@ai-sdk/openai": "^3.0.2",
"react": "^18.3.0",
"zod": "^3.24.2"
}
}
旧版(v5):
{
"dependencies": {
"ai": "^5.0.99",
"@ai-sdk/react": "^1.0.0",
"@ai-sdk/openai": "^2.0.68"
}
}
版本说明:
- AI SDK v6.0.6(稳定版,2026 年 1 月)- 新项目推荐使用
- AI SDK v5.x(旧版)- 仍受支持,但不会新增功能
- 支持 React 18.3+ / React 19
- 推荐使用 Next.js 14+/15+
- 使用 Zod 3.24.2+ 进行架构验证
官方文档链接
核心 UI Hooks:
- AI SDK UI 概述:https://ai-sdk.dev/docs/ai-sdk-ui/overview
- useChat:https://ai-sdk.dev/docs/ai-sdk-ui/chatbot
- useCompletion:https://ai-sdk.dev/docs/ai-sdk-ui/completion
- useObject:https://ai-sdk.dev/docs/ai-sdk-ui/object-generation
高级主题(仅提供链接):
- Generative UI(RSC):https://ai-sdk.dev/docs/ai-sdk-rsc/overview
- 数据流协议:https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocols
- 消息元数据:https://ai-sdk.dev/docs/ai-sdk-ui/message-metadata
Next.js 集成:
- Next.js App Router:https://ai-sdk.dev/docs/getting-started/nextjs-app-router
- Next.js Pages Router:https://ai-sdk.dev/docs/getting-started/nextjs-pages-router
迁移与故障排除:
- v4→v5 迁移:https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- 故障排除:https://ai-sdk.dev/docs/troubleshooting
- 常见问题:https://ai-sdk.dev/docs/troubleshooting/common-issues
Vercel 部署:
- Vercel Functions:https://vercel.com/docs/functions
- 在 Vercel 上进行流式传输:https://vercel.com/docs/functions/streaming
模板
此技能在 templates/ 中包含以下模板:
- use-chat-basic.tsx - 使用手动输入的基础聊天(v5 模式)
- use-chat-tools.tsx - 支持工具调用 UI 渲染的聊天
- use-chat-attachments.tsx - 支持文件附件
- use-completion-basic.tsx - 基础文本补全
- use-object-streaming.tsx - 流式传输结构化数据
- nextjs-chat-app-router.tsx - Next.js App Router 完整示例
- nextjs-chat-pages-router.tsx - Next.js Pages Router 完整示例
- nextjs-api-route.ts - 适用于 App 和 Pages Router 的 API 路由
- message-persistence.tsx - 保存/加载聊天记录
- custom-message-renderer.tsx - 使用 markdown 的自定义消息组件
- package.json - 依赖项模板
参考文档
请参阅 references/:
- use-chat-migration.md - 完整的 v4→v5 迁移指南
- streaming-patterns.md - UI 流式传输最佳实践
- top-ui-errors.md - 18 个常见 UI 错误及解决方案
- nextjs-integration.md - Next.js 集成模式
- links-to-official-docs.md - 按类别整理的官方文档链接
生产环境测试:WordPress Auditor(https://wordpress-auditor.webfonts.workers.dev) 最后验证时间:2026-01-20 | 技能版本:3.1.0 | 更新内容:升级至 AI SDK v6.0.42(+19 个补丁)。新增 React Strict Mode 章节。扩展问题 #7(过时的 body),增加 3 种变通方案。新增 6 个问题:使用 resume+onFinish 时出现 TypeError(#13)、并发 sendMessage 导致状态损坏(#14)、工具审批回调边缘情况(#15)、提前停止时出现 ZodError(#16)、convertToModelMessages 工具审批错误(#17)、undefined id 导致无限循环(#18)。错误数量:12→18。