mcpField
A
ai-sdk-ui

ai-sdk-ui

github.com/jezweb开发1.1k517 次安装3 周前更新
代码仓库

关于 ai-sdk-ui

ai-sdk-ui 是面向 React 前端开发者的 Vercel AI SDK UI 技能,介绍构建聊天与生成式界面的 Hook 用法。内容涵盖流式消息、工具审批和迁移排错。

主要功能

  1. 01React 聊天与补全 Hook
  2. 02流式消息和结构化输出
  3. 03工具调用与审批流程
  4. 04文件附件和消息持久化
  5. 05迁移指南与常见错误排查

适用场景

  1. 01构建 React 或 Next.js AI 聊天界面
  2. 02在界面中展示流式回复和工具调用
  3. 03为工具执行加入用户确认
  4. 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.json
references/
links-to-official-docs.md
nextjs-integration.md
streaming-patterns.md
top-ui-errors.md
use-chat-migration.md
rules/
ai-sdk-ui.md
scripts/
check-versions.sh
templates/
custom-message-renderer.tsx
message-persistence.tsx
nextjs-api-route.ts
nextjs-chat-app-router.tsx
nextjs-chat-pages-router.tsx
package.json
use-chat-attachments.tsx
use-chat-basic.tsx
use-chat-tools.tsx
use-completion-basic.tsx
use-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、.result
  • file - 文件附件,包含 .mimeType、.data
  • reasoning - 模型推理(如果可用)
  • 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 变更摘要:

  1. 移除输入管理:不再提供 input、handleInputChange、handleSubmit
  2. append() → sendMessage():用于发送消息的新方法
  3. 移除 onResponse:改用 onFinish
  4. initialMessages → 受控模式:使用 messages 属性进行完全控制
  5. 移除 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:

高级主题(仅提供链接):

Next.js 集成:

迁移与故障排除:

Vercel 部署:


模板

此技能在 templates/ 中包含以下模板:

  1. use-chat-basic.tsx - 使用手动输入的基础聊天(v5 模式)
  2. use-chat-tools.tsx - 支持工具调用 UI 渲染的聊天
  3. use-chat-attachments.tsx - 支持文件附件
  4. use-completion-basic.tsx - 基础文本补全
  5. use-object-streaming.tsx - 流式传输结构化数据
  6. nextjs-chat-app-router.tsx - Next.js App Router 完整示例
  7. nextjs-chat-pages-router.tsx - Next.js Pages Router 完整示例
  8. nextjs-api-route.ts - 适用于 App 和 Pages Router 的 API 路由
  9. message-persistence.tsx - 保存/加载聊天记录
  10. custom-message-renderer.tsx - 使用 markdown 的自定义消息组件
  11. 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。

评论

支持 Markdown