mcpField
A
ai-sdk-core

ai-sdk-core

github.com/jackspace开发1645 次安装12 周前更新
代码仓库

关于 ai-sdk-core

使用 Vercel AI SDK v5 构建后端 AI 功能的技能,面向应用开发者。内容涵盖按提供方配置文本生成、流式输出、经模式验证的结构化结果、工具调用和多步骤 Agent。

主要功能

  1. 01文本生成与流式输出
  2. 02经模式验证的结构化结果
  3. 03模型提供方集成
  4. 04工具调用与多步骤 Agent
  5. 05生成错误处理

适用场景

  1. 01为应用添加流式聊天
  2. 02从文本提取并验证 JSON
  3. 03构建可调用工具的 AI 工作流
  4. 04运行批量文本生成任务

安装

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

$npx skills add https://github.com/jackspace/claudeskillz --skill ai-sdk-core

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
SKILL.json
VERIFICATION_REPORT.md

详细介绍

AI SDK 核心

使用 Vercel AI SDK v5 构建可用于生产环境的后端 AI。

快速入门(5 分钟)

安装
# Core package
npm install ai

# Provider packages (install what you need)
npm install @ai-sdk/openai       # OpenAI (GPT-5, GPT-4, GPT-3.5)
npm install @ai-sdk/anthropic    # Anthropic (Claude Sonnet 4.5, Opus 4, Haiku 4)
npm install @ai-sdk/google       # Google (Gemini 2.5 Pro/Flash/Lite)
npm install workers-ai-provider  # Cloudflare Workers AI

# Schema validation
npm install zod
环境变量
# .env
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_GENERATIVE_AI_API_KEY=...
第一个示例:生成文本
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';

const result = await generateText({
  model: openai('gpt-4-turbo'),
  prompt: 'What is TypeScript?',
});

console.log(result.text);
第一个示例:流式聊天
import { streamText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';

const stream = streamText({
  model: anthropic('claude-sonnet-4-5-20250929'),
  messages: [
    { role: 'user', content: 'Tell me a story' },
  ],
});

for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
}
第一个示例:结构化输出
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const result = await generateObject({
  model: openai('gpt-4'),
  schema: z.object({
    name: z.string(),
    age: z.number(),
    skills: z.array(z.string()),
  }),
  prompt: 'Generate a person profile for a software engineer',
});

console.log(result.object);
// { name: "Alice", age: 28, skills: ["TypeScript", "React"] }

核心函数

generateText()

生成文本补全,可选使用工具并执行多步操作。

签名:

async function generateText(options: {
  model: LanguageModel;
  prompt?: string;
  messages?: Array<ModelMessage>;
  system?: string;
  tools?: Record<string, Tool>;
  maxOutputTokens?: number;
  temperature?: number;
  stopWhen?: StopCondition;
  // ... other options
}): Promise<GenerateTextResult>

基本用法:

import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';

const result = await generateText({
  model: openai('gpt-4-turbo'),
  prompt: 'Explain quantum computing',
  maxOutputTokens: 500,
  temperature: 0.7,
});

console.log(result.text);
console.log(`Tokens: ${result.usage.totalTokens}`);

使用消息(聊天格式):

const result = await generateText({
  model: openai('gpt-4-turbo'),
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'What is the weather?' },
    { role: 'assistant', content: 'I need your location.' },
    { role: 'user', content: 'San Francisco' },
  ],
});

使用工具:

import { tool } from 'ai';
import { z } from 'zod';

const result = await generateText({
  model: openai('gpt-4'),
  tools: {
    weather: tool({
      description: 'Get the weather for a location',
      inputSchema: z.object({
        location: z.string(),
      }),
      execute: async ({ location }) => {
        // API call here
        return { temperature: 72, condition: 'sunny' };
      },
    }),
  },
  prompt: 'What is the weather in Tokyo?',
});

适用场景:

  • 需要最终响应(非流式)
  • 希望等待工具执行完成
  • 无需流式处理时使用更简单的代码
  • 构建批处理/定时任务

错误处理:

import { AI_APICallError, AI_NoContentGeneratedError } from 'ai';

try {
  const result = await generateText({
    model: openai('gpt-4-turbo'),
    prompt: 'Hello',
  });
  console.log(result.text);
} catch (error) {
  if (error instanceof AI_APICallError) {
    console.error('API call failed:', error.message);
    // Check rate limits, API key, network
  } else if (error instanceof AI_NoContentGeneratedError) {
    console.error('No content generated');
    // Prompt may have been filtered
  } else {
    console.error('Unknown error:', error);
  }
}

streamText()

以实时分块的方式流式生成文本补全。

签名:

function streamText(options: {
  model: LanguageModel;
  prompt?: string;
  messages?: Array<ModelMessage>;
  system?: string;
  tools?: Record<string, Tool>;
  maxOutputTokens?: number;
  temperature?: number;
  stopWhen?: StopCondition;
  // ... other options
}): StreamTextResult

基本流式处理:

import { streamText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';

const stream = streamText({
  model: anthropic('claude-sonnet-4-5-20250929'),
  prompt: 'Write a poem about AI',
});

// Stream to console
for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
}

// Or get final result
const finalResult = await stream.result;
console.log(finalResult.text);

使用工具进行流式处理:

const stream = streamText({
  model: openai('gpt-4'),
  tools: {
    // ... tools definition
  },
  prompt: 'What is the weather?',
});

// Stream text chunks
for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
}

处理数据流:

const stream = streamText({
  model: openai('gpt-4-turbo'),
  prompt: 'Explain AI',
});

// Option 1: Text stream
for await (const text of stream.textStream) {
  console.log(text);
}

// Option 2: Full stream (includes metadata)
for await (const part of stream.fullStream) {
  if (part.type === 'text-delta') {
    console.log(part.textDelta);
  } else if (part.type === 'tool-call') {
    console.log('Tool called:', part.toolName);
  }
}

// Option 3: Wait for final result
const result = await stream.result;
console.log(result.text, result.usage);

适用场景:

  • 面向用户的实时响应
  • 长篇内容生成
  • 希望展示进度
  • 提升感知性能

生产环境模式:

// Next.js API Route
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';

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

  const stream = streamText({
    model: openai('gpt-4-turbo'),
    messages,
  });

  // Return stream to client
  return stream.toDataStreamResponse();
}

错误处理:

// Recommended: Use onError callback (added in v4.1.22)
const stream = streamText({
  model: openai('gpt-4-turbo'),
  prompt: 'Hello',
  onError({ error }) {
    console.error('Stream error:', error);
    // Custom error handling
  },
});

for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
}

// Alternative: Manual try-catch
try {
  const stream = streamText({
    model: openai('gpt-4-turbo'),
    prompt: 'Hello',
  });

  for await (const chunk of stream.textStream) {
    process.stdout.write(chunk);
  }
} catch (error) {
  console.error('Stream error:', error);
}

generateObject()

生成由 Zod 架构验证的结构化输出。

签名:

async function generateObject<T>(options: {
  model: LanguageModel;
  schema: z.Schema<T>;
  prompt?: string;
  messages?: Array<ModelMessage>;
  system?: string;
  mode?: 'auto' | 'json' | 'tool';
  // ... other options
}): Promise<GenerateObjectResult<T>>

基本用法:

import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const result = await generateObject({
  model: openai('gpt-4'),
  schema: z.object({
    recipe: z.object({
      name: z.string(),
      ingredients: z.array(z.object({
        name: z.string(),
        amount: z.string(),
      })),
      instructions: z.array(z.string()),
    }),
  }),
  prompt: 'Generate a recipe for chocolate chip cookies',
});

console.log(result.object.recipe);

嵌套架构:

const PersonSchema = z.object({
  name: z.string(),
  age: z.number(),
  address: z.object({
    street: z.string(),
    city: z.string(),
    country: z.string(),
  }),
  hobbies: z.array(z.string()),
});

const result = await generateObject({
  model: openai('gpt-4'),
  schema: PersonSchema,
  prompt: 'Generate a person profile',
});

数组和联合类型:

// Array of objects
const result = await generateObject({
  model: openai('gpt-4'),
  schema: z.object({
    people: z.array(z.object({
      name: z.string(),
      role: z.enum(['engineer', 'designer', 'manager']),
    })),
  }),
  prompt: 'Generate a team of 5 people',
});

// Union types
const result = await generateObject({
  model: openai('gpt-4'),
  schema: z.discriminatedUnion('type', [
    z.object({ type: z.literal('text'), content: z.string() }),
    z.object({ type: z.literal('image'), url: z.string() }),
  ]),
  prompt: 'Generate content',
});

适用场景:

  • 需要结构化数据(JSON、表单等)
  • 验证至关重要
  • 从非结构化输入中提取数据
  • 构建使用 JSON 的 AI 工作流

错误处理:

import { AI_NoObjectGeneratedError, AI_TypeValidationError } from 'ai';

try {
  const result = await generateObject({
    model: openai('gpt-4'),
    schema: z.object({ name: z.string() }),
    prompt: 'Generate a person',
  });
} catch (error) {
  if (error instanceof AI_NoObjectGeneratedError) {
    console.error('Model did not generate valid object');
    // Try simplifying schema or adding examples
  } else if (error instanceof AI_TypeValidationError) {
    console.error('Zod validation failed:', error.message);
    // Schema doesn't match output
  }
}

streamObject()

以增量更新的方式流式生成结构化输出。

签名:

function streamObject<T>(options: {
  model: LanguageModel;
  schema: z.Schema<T>;
  prompt?: string;
  messages?: Array<ModelMessage>;
  mode?: 'auto' | 'json' | 'tool';
  // ... other options
}): StreamObjectResult<T>

基本用法:

import { streamObject } from 'ai';
import { google } from '@ai-sdk/google';
import { z } from 'zod';

const stream = streamObject({
  model: google('gemini-2.5-pro'),
  schema: z.object({
    characters: z.array(z.object({
      name: z.string(),
      class: z.string(),
      stats: z.object({
        hp: z.number(),
        mana: z.number(),
      }),
    })),
  }),
  prompt: 'Generate 3 RPG characters',
});

// Stream partial updates
for await (const partialObject of stream.partialObjectStream) {
  console.log(partialObject);
  // { characters: [{ name: "Aria" }] }
  // { characters: [{ name: "Aria", class: "Mage" }] }
  // { characters: [{ name: "Aria", class: "Mage", stats: { hp: 100 } }] }
  // ...
}

UI 集成模式:

// Server endpoint
export async function POST(request: Request) {
  const { prompt } = await request.json();

  const stream = streamObject({
    model: openai('gpt-4'),
    schema: z.object({
      summary: z.string(),
      keyPoints: z.array(z.string()),
    }),
    prompt,
  });

  return stream.toTextStreamResponse();
}

// Client (with useObject hook from ai-sdk-ui)
const { object, isLoading } = useObject({
  api: '/api/analyze',
  schema: /* same schema */,
});

// Render partial object as it streams
{object?.summary && <p>{object.summary}</p>}
{object?.keyPoints?.map(point => <li key={point}>{point}</li>)}

适用场景:

  • 实时结构化数据(表单、仪表板)
  • 展示渐进式完成过程
  • 大型结构化输出
  • 改善生成较慢时的用户体验

提供方设置与配置

OpenAI
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';

// API key from environment (recommended)
// OPENAI_API_KEY=sk-...
const model = openai('gpt-4-turbo');

// Or explicit API key
const model = openai('gpt-4', {
  apiKey: process.env.OPENAI_API_KEY,
});

// Available models
const gpt5 = openai('gpt-5');           // Latest (released August 2025)
const gpt4 = openai('gpt-4-turbo');
const gpt35 = openai('gpt-3.5-turbo');

const result = await generateText({
  model: gpt4,
  prompt: 'Hello',
});

常见错误:

  • AI_LoadAPIKeyError:检查 OPENAI_API_KEY 环境变量
  • 429 Rate Limit:实施指数退避,升级套餐
  • 401 Unauthorized:API 密钥格式无效

速率限制: OpenAI 对 RPM(每分钟请求数)和 TPM(每分钟 Token 数)设有限制。请实现重试逻辑:

const result = await generateText({
  model: openai('gpt-4'),
  prompt: 'Hello',
  maxRetries: 3,  // Built-in retry
});

Anthropic
import { anthropic } from '@ai-sdk/anthropic';

// ANTHROPIC_API_KEY=sk-ant-...
const claude = anthropic('claude-sonnet-4-5-20250929');

// Available models (Claude 4.x family, released 2025)
const sonnet45 = anthropic('claude-sonnet-4-5-20250929');  // Latest, recommended
const sonnet4 = anthropic('claude-sonnet-4-20250522');     // Released May 2025
const opus4 = anthropic('claude-opus-4-20250522');         // Highest quality

// Legacy models (Claude 3.x, deprecated)
// const sonnet35 = anthropic('claude-3-5-sonnet-20241022');  // Use Claude 4.x instead
// const opus3 = anthropic('claude-3-opus-20240229');
// const haiku3 = anthropic('claude-3-haiku-20240307');

const result = await generateText({
  model: sonnet45,
  prompt: 'Explain quantum entanglement',
});

常见错误:

  • AI_LoadAPIKeyError:检查 ANTHROPIC_API_KEY 环境变量
  • overloaded_error:使用指数退避重试
  • rate_limit_error:等待后重试

最佳实践:

  • Claude 擅长处理长上下文任务(200K+ Token)
  • 推荐使用 Claude 4.x:Anthropic 已于 2025 年弃用 Claude 3.x
  • 使用 Sonnet 4.5,在速度和质量之间取得平衡(最新模型)
  • 如需避免使用最新模型,可使用 Sonnet 4,获得稳定的生产环境表现
  • 使用 Opus 4,获得最高质量的推理能力并处理复杂任务

Google
import { google } from '@ai-sdk/google';

// GOOGLE_GENERATIVE_AI_API_KEY=...
const gemini = google('gemini-2.5-pro');

// Available models (all GA since June-July 2025)
const pro = google('gemini-2.5-pro');
const flash = google('gemini-2.5-flash');
const lite = google('gemini-2.5-flash-lite');

const result = await generateText({
  model: pro,
  prompt: 'Analyze this data',
});

常见错误:

  • AI_LoadAPIKeyError:检查 GOOGLE_GENERATIVE_AI_API_KEY
  • SAFETY:内容被安全设置过滤
  • QUOTA_EXCEEDED:触发速率限制

最佳实践:

  • Gemini Pro:最适合推理和分析
  • Gemini Flash:速度快、成本效益高,适用于大多数任务
  • 免费套餐的限额较为宽松
  • 适用于多模态任务(结合图像输入)

Cloudflare Workers AI
import { Hono } from 'hono';
import { generateText } from 'ai';
import { createWorkersAI } from 'workers-ai-provider';

interface Env {
  AI: Ai;
}

const app = new Hono<{ Bindings: Env }>();

app.post('/chat', async (c) => {
  // Create provider inside handler (avoid startup overhead)
  const workersai = createWorkersAI({ binding: c.env.AI });

  const result = await generateText({
    model: workersai('@cf/meta/llama-3.1-8b-instruct'),
    prompt: 'What is Cloudflare?',
  });

  return c.json({ response: result.text });
});

export default app;

wrangler.jsonc:

{
  "name": "ai-sdk-worker",
  "compatibility_date": "2025-10-21",
  "ai": {
    "binding": "AI"
  }
}

重要说明:

启动优化: AI SDK v5 + Zod 可能导致 Workers 启动时间超过 270ms。解决方案:

  1. 将导入移至处理程序内部:
// BAD (startup overhead)
import { createWorkersAI } from 'workers-ai-provider';
const workersai = createWorkersAI({ binding: env.AI });

// GOOD (lazy init)
app.post('/chat', async (c) => {
  const { createWorkersAI } = await import('workers-ai-provider');
  const workersai = createWorkersAI({ binding: c.env.AI });
  // ...
});
  1. 尽量减少顶层 Zod 架构:
// Move complex schemas into route handlers

适用 workers-ai-provider 的场景:

  • 多提供方场景(OpenAI + Workers AI)
  • 使用 AI SDK UI hooks 搭配 Workers AI
  • 需要在不同提供方之间使用一致的 API

适用原生绑定的场景: 对于不需要多提供方支持的纯 Cloudflare 部署,请改用 cloudflare-workers-ai 技能,以获得最高性能。


工具调用与 Agent

基本工具定义
import { generateText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const result = await generateText({
  model: openai('gpt-4'),
  tools: {
    weather: tool({
      description: 'Get the weather for a location',
      inputSchema: z.object({
        location: z.string().describe('The city and country, e.g. "Paris, France"'),
        unit: z.enum(['celsius', 'fahrenheit']).optional(),
      }),
      execute: async ({ location, unit = 'celsius' }) => {
        // Simulate API call
        const data = await fetch(`https://api.weather.com/${location}`);
        return { temperature: 72, condition: 'sunny', unit };
      },
    }),
    convertTemperature: tool({
      description: 'Convert temperature between units',
      inputSchema: z.object({
        value: z.number(),
        from: z.enum(['celsius', 'fahrenheit']),
        to: z.enum(['celsius', 'fahrenheit']),
      }),
      execute: async ({ value, from, to }) => {
        if (from === to) return { value };
        if (from === 'celsius' && to === 'fahrenheit') {
          return { value: (value * 9/5) + 32 };
        }
        return { value: (value - 32) * 5/9 };
      },
    }),
  },
  prompt: 'What is the weather in Tokyo in Fahrenheit?',
});

console.log(result.text);
// Model will call weather tool, potentially convertTemperature, then answer

v5 工具变更:

  • parameters → inputSchema(Zod schema)
  • 工具属性:args → input,result → output
  • 移除 ToolExecutionError(现在使用 tool-error 内容部分)

Agent 类

Agent 类简化了使用工具进行多步执行的过程。

import { Agent, tool } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';

const weatherAgent = new Agent({
  model: anthropic('claude-sonnet-4-5-20250929'),
  system: 'You are a weather assistant. Always convert temperatures to the user\'s preferred unit.',
  tools: {
    getWeather: tool({
      description: 'Get current weather for a location',
      inputSchema: z.object({
        location: z.string(),
      }),
      execute: async ({ location }) => {
        return { temp: 72, condition: 'sunny', unit: 'fahrenheit' };
      },
    }),
    convertTemp: tool({
      description: 'Convert temperature between units',
      inputSchema: z.object({
        fahrenheit: z.number(),
      }),
      execute: async ({ fahrenheit }) => {
        return { celsius: (fahrenheit - 32) * 5/9 };
      },
    }),
  },
});

const result = await weatherAgent.run({
  messages: [
    { role: 'user', content: 'What is the weather in SF in Celsius?' },
  ],
});

console.log(result.text);
// Agent will call getWeather, then convertTemp, then respond

何时使用 Agent,何时使用原始 generateText:

  • 在以下情况下使用 Agent: 多个工具、复杂工作流、多步推理
  • 在以下情况下使用 generateText: 简单的单步任务、使用一两个工具、需要完全掌控

多步执行

使用 stopWhen 条件控制何时停止多步执行。

import { generateText, stopWhen, stepCountIs, hasToolCall } from 'ai';
import { openai } from '@ai-sdk/openai';

// Stop after specific number of steps
const result = await generateText({
  model: openai('gpt-4'),
  tools: { /* ... */ },
  prompt: 'Research TypeScript and create a summary',
  stopWhen: stepCountIs(5),  // Max 5 steps (tool calls + responses)
});

// Stop when specific tool is called
const result = await generateText({
  model: openai('gpt-4'),
  tools: {
    research: tool({ /* ... */ }),
    finalize: tool({ /* ... */ }),
  },
  prompt: 'Research and finalize a report',
  stopWhen: hasToolCall('finalize'),  // Stop when finalize is called
});

// Combine conditions
const result = await generateText({
  model: openai('gpt-4'),
  tools: { /* ... */ },
  prompt: 'Complex task',
  stopWhen: (step) => step.stepCount >= 10 || step.hasToolCall('finish'),
});

v5 变更: 已移除 maxSteps 参数。改用 stopWhen(stepCountIs(n))。


动态工具(v5 新功能)

根据上下文在运行时添加工具:

const result = await generateText({
  model: openai('gpt-4'),
  tools: (context) => {
    // Context includes messages, step count, etc.
    const baseTool = {
      search: tool({ /* ... */ }),
    };

    // Add tools based on context
    if (context.messages.some(m => m.content.includes('weather'))) {
      baseTool.weather = tool({ /* ... */ });
    }

    return baseTools;
  },
  prompt: 'Help me with my task',
});

v4→v5 关键迁移指南

AI SDK v5 引入了大量破坏性变更。如果要从 v4 迁移,请遵循本指南。

破坏性变更概览
  1. 参数重命名

    • maxTokens → maxOutputTokens
    • providerMetadata → providerOptions
  2. 工具定义

    • parameters → inputSchema
    • 工具属性:args → input,result → output
  3. 消息类型

    • CoreMessage → ModelMessage
    • Message → UIMessage
    • convertToCoreMessages → convertToModelMessages
  4. 工具错误处理

    • 移除 ToolExecutionError 类
    • 现在使用 tool-error 内容部分
    • 支持自动重试
  5. 多步执行

    • maxSteps → stopWhen
    • 使用 stepCountIs() 或 hasToolCall()
  6. 消息结构

    • 简单的 content 字符串 → parts 数组
    • 部分类型:文本、文件、推理、工具调用、工具结果
  7. 流式架构

    • 单个数据块 → start/delta/end 生命周期
    • 并发流使用唯一 ID
  8. 工具流式传输

    • 默认启用
    • 移除 toolCallStreaming 选项
  9. 包重组

    • ai/rsc → @ai-sdk/rsc
    • ai/react → @ai-sdk/react
    • LangChainAdapter → @ai-sdk/langchain
迁移示例

之前(v4):

import { generateText } from 'ai';

const result = await generateText({
  model: openai.chat('gpt-4'),
  maxTokens: 500,
  providerMetadata: { openai: { user: 'user-123' } },
  tools: {
    weather: {
      description: 'Get weather',
      parameters: z.object({ location: z.string() }),
      execute: async (args) => { /* args.location */ },
    },
  },
  maxSteps: 5,
});

之后(v5):

import { generateText, tool, stopWhen, stepCountIs } from 'ai';

const result = await generateText({
  model: openai('gpt-4'),
  maxOutputTokens: 500,
  providerOptions: { openai: { user: 'user-123' } },
  tools: {
    weather: tool({
      description: 'Get weather',
      inputSchema: z.object({ location: z.string() }),
      execute: async ({ location }) => { /* input.location */ },
    }),
  },
  stopWhen: stepCountIs(5),
});
迁移检查清单
  • 将所有 maxTokens 更新为 maxOutputTokens
  • 将 providerMetadata 更新为 providerOptions
  • 将工具的 parameters 转换为 inputSchema
  • 更新工具执行函数:args → input
  • 用 stopWhen(stepCountIs(n)) 替换 maxSteps
  • 更新消息类型:CoreMessage → ModelMessage
  • 移除 ToolExecutionError 处理
  • 更新包导入(ai/rsc → @ai-sdk/rsc)
  • 测试流式行为(架构已变更)
  • 更新 TypeScript 类型
自动迁移

AI SDK 提供了迁移工具:

npx ai migrate

该工具会自动更新大多数破坏性变更。请仔细检查变更。

官方迁移指南: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0


12 大常见错误及解决方案

1. AI_APICallError

原因: API 请求失败(网络、身份验证、速率限制)。

解决方案:

import { AI_APICallError } from 'ai';

try {
  const result = await generateText({
    model: openai('gpt-4'),
    prompt: 'Hello',
  });
} catch (error) {
  if (error instanceof AI_APICallError) {
    console.error('API call failed:', error.message);
    console.error('Status code:', error.statusCode);
    console.error('Response:', error.responseBody);

    // Check common causes
    if (error.statusCode === 401) {
      // Invalid API key
    } else if (error.statusCode === 429) {
      // Rate limit - implement backoff
    } else if (error.statusCode >= 500) {
      // Provider issue - retry
    }
  }
}

预防措施:

  • 启动时验证 API 密钥
  • 使用指数退避实现重试逻辑
  • 监控速率限制
  • 妥善处理网络错误

2. AI_NoObjectGeneratedError

原因: 模型未能生成符合 schema 的有效对象。

解决方案:

import { AI_NoObjectGeneratedError } from 'ai';

try {
  const result = await generateObject({
    model: openai('gpt-4'),
    schema: z.object({ /* complex schema */ }),
    prompt: 'Generate data',
  });
} catch (error) {
  if (error instanceof AI_NoObjectGeneratedError) {
    console.error('No valid object generated');

    // Solutions:
    // 1. Simplify schema
    // 2. Add more context to prompt
    // 3. Provide examples in prompt
    // 4. Try different model (gpt-4 better than gpt-3.5 for complex objects)
  }
}

预防措施:

  • 从简单的 schema 开始,逐步增加复杂度
  • 在提示词中加入示例:“生成一个类似这样的人员:{ name: 'Alice', age: 30 }”
  • 对于复杂的结构化输出,使用 GPT-4
  • 先用示例数据测试 schema

3. Worker 启动时间限制(270ms+)

原因: AI SDK v5 加上 Zod 初始化开销,导致 Cloudflare Workers 启动时间超出限制。

解决方案:

// BAD: Top-level imports cause startup overhead
import { createWorkersAI } from 'workers-ai-provider';
import { complexSchema } from './schemas';

const workersai = createWorkersAI({ binding: env.AI });

// GOOD: Lazy initialization inside handler
export default {
  async fetch(request, env) {
    const { createWorkersAI } = await import('workers-ai-provider');
    const workersai = createWorkersAI({ binding: env.AI });

    // Use workersai here
  }
}

预防措施:

  • 将 AI SDK 导入移至路由处理程序内部
  • 尽量减少顶层 Zod schema
  • 监控 Worker 启动时间(必须小于 400ms)
  • 使用 Wrangler 的启动时间报告

GitHub 问题: 在 Vercel AI SDK 问题中搜索 “Workers startup limit”


4. streamText 静默失败

原因: createDataStreamResponse 可能会吞掉流错误。

状态: ✅ 已解决 — 已在 [email protected] 中修复(2025 年 2 月)

解决方案(推荐):

// Use the onError callback (added in v4.1.22)
const stream = streamText({
  model: openai('gpt-4'),
  prompt: 'Hello',
  onError({ error }) {
    console.error('Stream error:', error);
    // Custom error logging and handling
  },
});

// Stream safely
for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
}

替代方案(手动 try-catch):

// Fallback if not using onError callback
try {
  const stream = streamText({
    model: openai('gpt-4'),
    prompt: 'Hello',
  });

  for await (const chunk of stream.textStream) {
    process.stdout.write(chunk);
  }
} catch (error) {
  console.error('Stream error:', error);
}

预防措施:

  • 使用 onError 回调正确捕获错误(推荐)
  • 实现服务端错误监控
  • 明确测试流错误处理
  • 在生产环境中始终在服务端记录日志

GitHub Issue: #4726(已解决)


5. AI_LoadAPIKeyError

原因: API 密钥缺失或无效。

解决方案:

import { AI_LoadAPIKeyError } from 'ai';

try {
  const result = await generateText({
    model: openai('gpt-4'),
    prompt: 'Hello',
  });
} catch (error) {
  if (error instanceof AI_LoadAPIKeyError) {
    console.error('API key error:', error.message);

    // Check:
    // 1. .env file exists and loaded
    // 2. Correct env variable name (OPENAI_API_KEY)
    // 3. Key format is valid (starts with sk-)
  }
}

预防措施:

  • 在应用启动时验证 API 密钥
  • 使用环境变量验证(例如 zod)
  • 在开发环境中提供清晰的错误消息
  • 说明必需的环境变量

6. AI_InvalidArgumentError

原因: 传递给函数的参数无效。

解决方案:

import { AI_InvalidArgumentError } from 'ai';

try {
  const result = await generateText({
    model: openai('gpt-4'),
    maxOutputTokens: -1,  // Invalid!
    prompt: 'Hello',
  });
} catch (error) {
  if (error instanceof AI_InvalidArgumentError) {
    console.error('Invalid argument:', error.message);
    // Check parameter types and values
  }
}

预防措施:

  • 使用 TypeScript 进行类型检查
  • 在调用 AI SDK 函数之前验证输入
  • 仔细阅读函数签名
  • 查看官方文档,了解参数限制

7. AI_NoContentGeneratedError

原因: 模型未生成任何内容(安全过滤器等)。

解决方案:

import { AI_NoContentGeneratedError } from 'ai';

try {
  const result = await generateText({
    model: openai('gpt-4'),
    prompt: 'Some prompt',
  });
} catch (error) {
  if (error instanceof AI_NoContentGeneratedError) {
    console.error('No content generated');

    // Possible causes:
    // 1. Safety filters blocked output
    // 2. Prompt triggered content policy
    // 3. Model configuration issue

    // Handle gracefully:
    return { text: 'Unable to generate response. Please try different input.' };
  }
}

预防措施:

  • 清理用户输入
  • 避免可能触发安全过滤器的提示词
  • 准备备用提示信息
  • 记录发生次数以便分析

8. AI_TypeValidationError

原因: 生成的输出未通过 Zod 架构验证。

解决方案:

import { AI_TypeValidationError } from 'ai';

try {
  const result = await generateObject({
    model: openai('gpt-4'),
    schema: z.object({
      age: z.number().min(0).max(120),  // Strict validation
    }),
    prompt: 'Generate person',
  });
} catch (error) {
  if (error instanceof AI_TypeValidationError) {
    console.error('Validation failed:', error.message);

    // Solutions:
    // 1. Relax schema constraints
    // 2. Add more guidance in prompt
    // 3. Use .optional() for unreliable fields
  }
}

预防措施:

  • 从宽松的架构开始,逐步收紧
  • 对可能并非总是存在的字段使用 .optional()
  • 在字段描述中添加验证提示
  • 使用各种提示词进行测试

9. AI_RetryError

原因: 所有重试均失败。

解决方案:

import { AI_RetryError } from 'ai';

try {
  const result = await generateText({
    model: openai('gpt-4'),
    prompt: 'Hello',
    maxRetries: 3,  // Default is 2
  });
} catch (error) {
  if (error instanceof AI_RetryError) {
    console.error('All retries failed');
    console.error('Last error:', error.lastError);

    // Check root cause:
    // - Persistent network issue
    // - Provider outage
    // - Invalid configuration
  }
}

预防措施:

  • 调查失败的根本原因
  • 如有需要,调整重试配置
  • 在提供商服务中断时实现熔断器模式
  • 准备备用提供商

10. 速率限制错误

原因: 超出提供商的速率限制(RPM/TPM)。

解决方案:

// Implement exponential backoff
async function generateWithBackoff(prompt: string, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await generateText({
        model: openai('gpt-4'),
        prompt,
      });
    } catch (error) {
      if (error instanceof AI_APICallError && error.statusCode === 429) {
        const delay = Math.pow(2, i) * 1000;  // Exponential backoff
        console.log(`Rate limited, waiting ${delay}ms`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
  throw new Error('Rate limit retries exhausted');
}

预防措施:

  • 监控速率限制标头
  • 对请求进行排队,以确保不超出限制
  • 如有需要,升级提供商套餐
  • 实现请求限流

11. 使用 Zod 时的 TypeScript 性能问题

原因: 复杂的 Zod 架构会减慢 TypeScript 类型检查。

解决方案:

// Instead of deeply nested schemas at top level:
// const complexSchema = z.object({ /* 100+ fields */ });

// Define inside functions or use type assertions:
function generateData() {
  const schema = z.object({ /* complex schema */ });
  return generateObject({ model: openai('gpt-4'), schema, prompt: '...' });
}

// Or use z.lazy() for recursive schemas:
type Category = { name: string; subcategories?: Category[] };
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
  z.object({
    name: z.string(),
    subcategories: z.array(CategorySchema).optional(),
  })
);

预防措施:

  • 避免使用顶层复杂架构
  • 对递归类型使用 z.lazy()
  • 将大型架构拆分为较小的架构
  • 在适当情况下使用类型断言

官方文档: https://ai-sdk.dev/docs/troubleshooting/common-issues/slow-type-checking


12. 无效 JSON 响应(特定于提供商)

原因: 某些模型偶尔会返回无效 JSON。

解决方案:

// Use built-in retry and mode selection
const result = await generateObject({
  model: openai('gpt-4'),
  schema: mySchema,
  prompt: 'Generate data',
  mode: 'json',  // Force JSON mode (supported by GPT-4)
  maxRetries: 3,  // Retry on invalid JSON
});

// Or catch and retry manually:
try {
  const result = await generateObject({
    model: openai('gpt-4'),
    schema: mySchema,
    prompt: 'Generate data',
  });
} catch (error) {
  // Retry with different model
  const result = await generateObject({
    model: openai('gpt-4-turbo'),
    schema: mySchema,
    prompt: 'Generate data',
  });
}

预防措施:

  • 在可用时使用 mode: 'json'
  • 结构化输出优先使用 GPT-4
  • 实现重试逻辑
  • 验证响应

GitHub Issue: #4302(Imagen 3.0 无效 JSON)


更多错误: 请参阅完整错误参考:https://ai-sdk.dev/docs/reference/ai-sdk-errors


生产环境最佳实践

性能

1. 对长篇内容始终使用流式传输:

// User-facing: Use streamText
const stream = streamText({ model: openai('gpt-4'), prompt: 'Long essay' });
return stream.toDataStreamResponse();

// Background tasks: Use generateText
const result = await generateText({ model: openai('gpt-4'), prompt: 'Analyze data' });

2. 设置合适的 maxOutputTokens:

const result = await generateText({
  model: openai('gpt-4'),
  prompt: 'Short answer',
  maxOutputTokens: 100,  // Limit tokens to save cost
});

3. 缓存提供商实例:

// Good: Reuse provider instances
const gpt4 = openai('gpt-4-turbo');
const result1 = await generateText({ model: gpt4, prompt: 'Hello' });
const result2 = await generateText({ model: gpt4, prompt: 'World' });

4. 优化 Zod 架构:

// Avoid complex nested schemas at top level in Workers
// Move into route handlers to prevent startup overhead
错误处理

1. 将所有 AI 调用包装在 try-catch 中:

try {
  const result = await generateText({ /* ... */ });
} catch (error) {
  // Handle specific errors
  if (error instanceof AI_APICallError) { /* ... */ }
  else if (error instanceof AI_NoContentGeneratedError) { /* ... */ }
  else { /* ... */ }
}

2. 实现重试逻辑:

const result = await generateText({
  model: openai('gpt-4'),
  prompt: 'Hello',
  maxRetries: 3,
});

3. 正确记录错误:

console.error('AI SDK Error:', {
  type: error.constructor.name,
  message: error.message,
  statusCode: error.statusCode,
  timestamp: new Date().toISOString(),
});
成本优化

1. 选择合适的模型:

// Simple tasks: Use cheaper models
const simple = await generateText({ model: openai('gpt-3.5-turbo'), prompt: 'Hello' });

// Complex reasoning: Use GPT-4
const complex = await generateText({ model: openai('gpt-4'), prompt: 'Analyze...' });

2. 合理设置 maxOutputTokens:

const result = await generateText({
  model: openai('gpt-4'),
  prompt: 'Summarize in 2 sentences',
  maxOutputTokens: 100,  // Prevent over-generation
});

3. 尽可能缓存结果:

const cache = new Map();

async function getCachedResponse(prompt: string) {
  if (cache.has(prompt)) return cache.get(prompt);

  const result = await generateText({ model: openai('gpt-4'), prompt });
  cache.set(prompt, result.text);
  return result.text;
}
Cloudflare Workers 专项

1. 将导入移到处理程序内部:

// Avoid startup overhead
export default {
  async fetch(request, env) {
    const { generateText } = await import('ai');
    const { openai } = await import('@ai-sdk/openai');
    // Use here
  }
}

2. 监控启动时间:

# Wrangler reports startup time
wrangler deploy
# Check output for startup duration (must be <400ms)

3. 正确处理流式传输:

// Return ReadableStream for streaming responses
const stream = streamText({ model: openai('gpt-4'), prompt: 'Hello' });
return new Response(stream.toTextStream(), {
  headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
Next.js / Vercel 专属

1. 使用 Server Actions 执行变更:

'use server';

export async function generateContent(input: string) {
  const result = await generateText({
    model: openai('gpt-4'),
    prompt: input,
  });
  return result.text;
}

2. 使用 Server Components 执行初始加载:

// app/page.tsx
export default async function Page() {
  const result = await generateText({
    model: openai('gpt-4'),
    prompt: 'Welcome message',
  });

  return <div>{result.text}</div>;
}

3. 实现加载状态:

'use client';

import { useState } from 'react';
import { generateContent } from './actions';

export default function Form() {
  const [loading, setLoading] = useState(false);

  async function handleSubmit(formData: FormData) {
    setLoading(true);
    const result = await generateContent(formData.get('input'));
    setLoading(false);
  }

  return (
    <form action={handleSubmit}>
      <input name="input" />
      <button disabled={loading}>
        {loading ? 'Generating...' : 'Submit'}
      </button>
    </form>
  );
}

4. 关于部署: 请参阅 Vercel 的官方部署文档:https://vercel.com/docs/functions


何时使用此技能

以下情况使用 ai-sdk-core:
  • 构建后端 AI 功能(服务端文本生成)
  • 实现服务端文本生成(Node.js、Workers、Next.js)
  • 创建结构化 AI 输出(JSON、表单、数据提取)
  • 使用工具构建 AI Agent(多步工作流)
  • 集成多个 AI 提供商(OpenAI、Anthropic、Google、Cloudflare)
  • 从 AI SDK v4 迁移到 v5
  • 遇到 AI SDK 错误(AI_APICallError、AI_NoObjectGeneratedError 等)
  • 在 Cloudflare Workers 中使用 AI(配合 workers-ai-provider)
  • 在 Next.js Server Components/Actions 中使用 AI
  • 需要跨不同 LLM 提供商使用一致的 API
以下情况不要使用此技能:
  • 构建 React 聊天 UI(改用 ai-sdk-ui 技能)
  • 需要 useChat 等前端钩子(改用 ai-sdk-ui 技能)
  • 需要嵌入或图像生成等高级主题(请查阅官方文档)
  • 在不使用多提供商的情况下构建原生 Cloudflare Workers AI 应用(改用 cloudflare-workers-ai 技能)
  • 需要生成式 UI / RSC(请参阅 https://ai-sdk.dev/docs/ai-sdk-rsc)

依赖项与版本

{
  "dependencies": {
    "ai": "^5.0.81",
    "@ai-sdk/openai": "^2.0.56",
    "@ai-sdk/anthropic": "^2.0.38",
    "@ai-sdk/google": "^2.0.24",
    "workers-ai-provider": "^2.0.0",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@types/node": "^20.11.0",
    "typescript": "^5.3.3"
  }
}

版本说明:

  • AI SDK v5.0.81+(稳定版,截至 2025 年 10 月的最新版本)
  • v6 仍处于 Beta 阶段,本技能不涉及
  • Zod 兼容性:本技能使用 Zod 3.x,但 AI SDK 5 官方同时支持 Zod 3.x 和 Zod 4.x(最新版本为 4.1.12)
    • 新项目推荐使用 Zod 4(于 2025 年 8 月发布)
    • Zod 4 存在不兼容变更:错误 API、.default() 行为、移除了 ZodError.errors
    • 使用 Zod 4 时,zod-to-json-schema 可能会出现一些对等依赖项警告
    • 迁移指南请参阅 https://zod.dev/v4/changelog
  • 为兼容 v5,提供商包需使用 2.0+

检查最新版本:

npm view ai version
npm view @ai-sdk/openai version
npm view @ai-sdk/anthropic version
npm view @ai-sdk/google version
npm view workers-ai-provider version
npm view zod version  # Check for Zod 4.x updates

官方文档链接

核心文档
高级主题(本技能未涵盖)
迁移与故障排查
提供商文档
Cloudflare 集成
Vercel / Next.js 集成
GitHub 与社区

模板与参考资料

此技能包含:

  • 13 个模板: 位于 templates/ 的即用型代码示例
  • 5 份参考文档: 位于 references/ 的详细指南
  • 1 个脚本: 位于 scripts/ 的版本检查器

所有文件均已优化,可直接复制粘贴到你的项目中。


最后更新: 2025-10-29 技能版本: 1.1.0 AI SDK 版本: 5.0.81+

评论

支持 Markdown