mcpField
A
ai-sdk-core

ai-sdk-core

github.com/jackspace開発1645 回インストール12 週間前に更新
リポジトリ

ai-sdk-core について

Vercel AI SDK v5 でバックエンドの AI 機能を構築するスキルです。アプリケーション開発者向けに、プロバイダー別のテキスト生成、ストリーミング、スキーマ検証済み出力、ツール利用、複数ステップのエージェントを扱います。

主な機能

  1. 01テキスト生成とストリーミング
  2. 02スキーマ検証済み構造化出力
  3. 03モデルプロバイダー連携
  4. 04ツール呼び出しと複数ステップエージェント
  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 Core

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>)}

使用する場面:

  • リアルタイムの構造化データ(フォーム、ダッシュボードなど)
  • 段階的な生成結果を表示する場合
  • 大規模な構造化出力
  • 生成に時間がかかる場合の UX 向上

プロバイダーのセットアップと設定

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(1 分あたりのリクエスト数)と TPM(1 分あたりのトークン数)に制限を設けています。再試行ロジックを実装してください。

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+ トークン)に優れています
  • 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 など)を使用する場合
  • Workers AI で AI SDK UI フックを使用する場合
  • プロバイダー間で一貫した API が必要な場合

ネイティブバインディングを使用する場面: 複数プロバイダーのサポートを必要としない Cloudflare 専用のデプロイでは、最大限のパフォーマンスを得るために、代わりに cloudflare-workers-ai スキルを使用してください。


ツール呼び出しとエージェント

基本的なツール定義
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 スキーマ)
  • ツールのプロパティ: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 を使う場合: シンプルな単一ステップ、1~2 個のツール、完全な制御が必要な場合

複数ステップの実行

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 配列
    • パーツ:text、file、reasoning、tool-call、tool-result
  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 に変換する
  • ツールの execute 関数を更新する:args → input
  • maxSteps を stopWhen(stepCountIs(n)) に置き換える
  • メッセージの型を更新する: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

原因: モデルがスキーマに一致する有効なオブジェクトを生成しませんでした。

解決策:

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)
  }
}

予防策:

  • シンプルなスキーマから始め、段階的に複雑さを加える
  • プロンプトに例を含める:「次のような人物を生成してください:{ name: 'Alice', age: 30 }」
  • 複雑な構造化出力には GPT-4 を使用する
  • まずサンプルデータでスキーマをテストする

3. Worker の起動時間制限(270ms 以上)

原因: Cloudflare Workers では、AI SDK v5 と Zod の初期化にかかるオーバーヘッドが起動時間の制限を超えます。

解決策:

// 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 スキーマを最小限にする
  • Worker の起動時間を監視する(400ms 未満である必要があります)
  • Wrangler の起動時間レポート機能を使用する

GitHub Issue: 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 エージェント(複数ステップのワークフロー)を構築する場合
  • 複数の 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 スキルを使用してください)
  • Generative 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 はベータ版のため、このスキルでは対象外です
  • 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+

コメント