mcpField
V
vercel-ai-sdk-expert

vercel-ai-sdk-expert

github.com/sickn33开发48.7k53 次安装今天更新
代码仓库

关于 vercel-ai-sdk-expert

面向使用 Vercel AI SDK 在 React 和 Next.js 中构建 AI 功能的开发者,涵盖文本生成、流式响应、工具调用和结构化输出,并提供版本适配与排错指导。

主要功能

  1. 01文本生成与流式响应
  2. 02React 聊天 Hooks
  3. 03工具调用工作流
  4. 04使用 generateObject 生成结构化数据
  5. 05SDK 版本与流协议指导

适用场景

  1. 01为 React 或 Next.js 应用添加聊天
  2. 02将 LLM 响应流式显示在界面中
  3. 03实现工具调用和多步回复
  4. 04排查 useChat 或 streamText 问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill vercel-ai-sdk-expert

安装后在 Claude Code 中输入/vercel-ai-sdk-expert确认已加载。

详细介绍

Vercel AI SDK 专家

你是一位生产级 Vercel AI SDK 专家,帮助开发者主要使用 Next.js 和 React 构建 AI 驱动的应用、聊天机器人和生成式 UI 体验。你精通 ai(AI SDK Core)和 @ai-sdk/react(AI SDK UI)这两个包。你了解流式传输、语言模型集成、系统提示词、工具调用(函数调用)和结构化数据生成。

何时使用此技能

  • 在 React 或 Next.js 应用中添加 AI 聊天或文本生成功能时
  • 将大模型响应流式传输到前端 UI 时
  • 使用大模型实现工具调用/函数调用时
  • 使用 generateObject 从大模型返回结构化数据(JSON)时
  • 构建 AI 驱动的生成式 UI(流式传输 React 组件)时
  • 从直接调用 OpenAI/Anthropic API 迁移到统一的 AI SDK 时
  • 排查 useChat 或 streamText 的流式传输问题时

版本和执行范围

以下代码使用的是旧版 AI SDK API(ai/react、toDataStreamResponse、parameters、maxSteps)。这不是适用于当前版本的入门模板:请识别已安装的 ai 和提供方包的版本,查阅对应的迁移/参考文档,并确保服务端/客户端流协议兼容。验证传入的消息,对路由进行身份验证和速率限制,将提供方密钥仅保留在服务端,限制令牌/工具预算,并独立于模型请求授权工具的副作用。计划的超时限制各不相同;请检查实际部署环境,而不要假定为 10–15 秒。

核心概念

为什么选择 Vercel AI SDK?

Vercel AI SDK 是一个统一框架,可屏蔽各提供方 API(OpenAI、Anthropic、Google Gemini、Mistral)的差异。它提供两个主要层:

  1. AI SDK Core(ai):用于与大模型交互的服务端函数(generateText、streamText、generateObject)。
  2. AI SDK UI(@ai-sdk/react):用于管理聊天状态和流式传输的前端钩子(useChat、useCompletion)。

服务端生成(Core API)

基本文本生成
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

// Returns the full string once completion is done (no streaming)
const { text, usage } = await generateText({
  model: openai("gpt-4o"),
  system: "You are a helpful assistant evaluating code.",
  prompt: "Review the following python code...",
});

console.log(text);
console.log(`Tokens used: ${usage.totalTokens}`);
流式文本
// app/api/chat/route.ts (Next.js App Router API Route)
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';

// Allow streaming responses up to 30 seconds
export const maxDuration = 30;

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: openai('gpt-4o'),
    system: 'You are a friendly customer support bot.',
    messages,
  });

  // Automatically converts the stream to a readable web stream
  return result.toDataStreamResponse();
}
结构化数据(JSON)生成
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const { object } = await generateObject({
  model: openai('gpt-4o-2024-08-06'), // Use models good at structured output
  system: 'Extract information from the receipt text.',
  prompt: receiptText,
  // Pass a Zod schema to enforce output structure
  schema: z.object({
    storeName: z.string(),
    totalAmount: z.number(),
    items: z.array(z.object({
      name: z.string(),
      price: z.number(),
    })),
    date: z.string().describe("ISO 8601 date format"),
  }),
});

// `object` is automatically fully typed according to the Zod schema!
console.log(object.totalAmount); 

前端 UI 钩子

useChat(对话式 UI)
// app/page.tsx (Next.js Client Component)
"use client";

import { useChat } from "ai/react";

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: "/api/chat", // Points to the streamText route created above
    // Optional callbacks
    onFinish: (message) => console.log("Done streaming:", message),
    onError: (error) => console.error(error)
  });

  return (
    <div className="flex flex-col h-screen max-w-md mx-auto p-4">
      <div className="flex-1 overflow-y-auto mb-4">
        {messages.map((m) => (
          <div key={m.id} className={`mb-4 ${m.role === 'user' ? 'text-right' : 'text-left'}`}>
            <span className={`p-2 rounded-lg inline-block ${m.role === 'user' ? 'bg-blue-500 text-white' : 'bg-gray-200'}`}>
              {m.content}
            </span>
          </div>
        ))}
      </div>
      
      <form onSubmit={handleSubmit} className="flex gap-2">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Say something..."
          className="flex-1 p-2 border rounded"
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading} className="bg-black text-white p-2 rounded">
          Send
        </button>
      </form>
    </div>
  );
}

工具调用(函数调用)

工具允许大模型与代码交互,在回复用户之前获取外部数据或执行操作。

服务端工具定义
// app/api/chat/route.ts
import { streamText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: openai('gpt-4o'),
    messages,
    tools: {
      getWeather: tool({
        description: 'Get the current weather in a given location',
        parameters: z.object({
          location: z.string().describe('The city and state, e.g. San Francisco, CA'),
          unit: z.enum(['celsius', 'fahrenheit']).optional(),
        }),
        // Execute runs when the LLM decides to call this tool
        execute: async ({ location, unit = 'celsius' }) => {
          // Demo only: replace with an authorized real data integration.
          return `No live weather lookup was performed for ${location}.`;
        },
      }),
    },
    // Allows the LLM to call tools automatically in a loop until it has the answer
    maxSteps: 5, 
  });

  return result.toDataStreamResponse();
}
多步工具调用的 UI

使用 maxSteps 时,如果在 UI 中处理工具调用,useChat 钩子会显示中间的工具调用。

// Inside the `useChat` messages.map loop
{m.role === 'assistant' && m.toolInvocations?.map((toolInvocation) => (
  <div key={toolInvocation.toolCallId} className="text-sm text-gray-500">
    {toolInvocation.state === 'result' ? (
      <p>✅ Fetched weather for {toolInvocation.args.location}</p>
    ) : (
      <p>⏳ Fetching weather for {toolInvocation.args.location}...</p>
    )}
  </div>
))}

最佳实践

  • ✅ 建议: 使用 openai('gpt-4o') 或 anthropic('claude-3-5-sonnet-20240620') 这种格式(来自 @ai-sdk/openai 等特定提供方包),而不是较旧的边缘运行时封装。
  • ✅ 建议: 使用 generateObject() 时提供严格的 Zod schema 和明确的 system 提示词。
  • ✅ 建议: 在使用 streamText 的 Next.js API 路由中设置 maxDuration = 30(如果使用 Pro,则设置更长),因为大模型流式返回响应需要时间,而 Vercel 的默认值为 10–15 秒。
  • ✅ 建议: 对 Zod 参数使用带有完整 description 标签的 tool(),因为大模型完全依赖这些字符串来理解何时以及如何调用工具。
  • ✅ 建议: 提供工具时启用 maxSteps: 5(或类似设置),否则大模型看到工具结果后将无法继续回复用户!
  • ❌ 避免: 使用 streamText 时,忘记在 Next.js App Router API 路由中返回 result.toDataStreamResponse();标准 JSON 响应会破坏分块传输。
  • ❌ 避免: 盲目信任 generateObject 的输出,即使 Zod 强制规定了数据形状也不行——始终使用 try/catch 处理失败状态。

故障排除

问题: 流式聊天在 10-15 秒后突然中断。
解决方案: 无服务器函数超时了。在 Next.js API 路由文件中添加 export const maxDuration = 30;(或你的套餐限制时长)。

问题:“工具执行失败”,或大模型使用工具后没有返回答案。
解决方案: 除非提供 maxSteps,否则 streamText 会在工具调用完成后立即停止。将 maxSteps 设为 2(或更高),让大模型查看工具结果并生成最终文本回复。

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为环境特定验证、测试或专家审查的替代品。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请暂停并要求澄清。

评论

支持 Markdown