ai-sdk-core について
Vercel AI SDK v5 でバックエンドの AI 機能を構築するスキルです。アプリケーション開発者向けに、プロバイダー別のテキスト生成、ストリーミング、スキーマ検証済み出力、ツール利用、複数ステップのエージェントを扱います。
主な機能
- 01テキスト生成とストリーミング
- 02スキーマ検証済み構造化出力
- 03モデルプロバイダー連携
- 04ツール呼び出しと複数ステップエージェント
- 05生成時のエラー処理
活用シーン
- 01アプリへのストリーミングチャット追加
- 02テキストからの検証済み JSON 抽出
- 03ツールを使う AI ワークフローの構築
- 04一括テキスト生成タスクの実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill ai-sdk-coreインストール後、Claude Code で/ai-sdk-coreを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdSKILL.jsonVERIFICATION_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 を使用してください
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 を超えることがあります。次の方法で対処してください。
- インポートをハンドラー内に移動する:
// 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 });
// ...
});
- トップレベルの 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 から移行する場合は、このガイドに従ってください。
破壊的変更の概要
-
パラメーター名の変更
maxTokens→maxOutputTokensproviderMetadata→providerOptions
-
ツール定義
parameters→inputSchema- ツールのプロパティ:
args→input、result→output
-
メッセージの型
CoreMessage→ModelMessageMessage→UIMessageconvertToCoreMessages→convertToModelMessages
-
ツールのエラー処理
ToolExecutionErrorクラスを削除- 現在は
tool-errorコンテンツパーツを使用 - 自動再試行が可能に
-
複数ステップの実行
maxSteps→stopWhenstepCountIs()またはhasToolCall()を使用
-
メッセージ構造
- シンプルな
content文字列 →parts配列 - パーツ:text、file、reasoning、tool-call、tool-result
- シンプルな
-
ストリーミングのアーキテクチャ
- 単一のチャンク → start/delta/end のライフサイクル
- 同時ストリームに一意の ID を付与
-
ツールのストリーミング
- デフォルトで有効
toolCallStreamingオプションを削除
-
パッケージの再編成
ai/rsc→@ai-sdk/rscai/react→@ai-sdk/reactLangChainAdapter→@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
公式ドキュメントへのリンク
コアドキュメント
- AI SDK の概要: https://ai-sdk.dev/docs/introduction
- AI SDK Core の概要: https://ai-sdk.dev/docs/ai-sdk-core/overview
- テキストの生成: https://ai-sdk.dev/docs/ai-sdk-core/generating-text
- 構造化データの生成: https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data
- ツールとツール呼び出し: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling
- エージェントの概要: https://ai-sdk.dev/docs/agents/overview
- 基礎: https://ai-sdk.dev/docs/foundations/overview
高度なトピック(このスキルでは扱っていません)
- 埋め込み: https://ai-sdk.dev/docs/ai-sdk-core/embeddings
- 画像生成: https://ai-sdk.dev/docs/ai-sdk-core/generating-images
- 文字起こし: https://ai-sdk.dev/docs/ai-sdk-core/generating-transcriptions
- 音声: https://ai-sdk.dev/docs/ai-sdk-core/generating-speech
- MCP ツール: https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools
- テレメトリー: https://ai-sdk.dev/docs/ai-sdk-core/telemetry
- Generative UI: https://ai-sdk.dev/docs/ai-sdk-rsc
移行とトラブルシューティング
- v4→v5 移行ガイド: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- すべてのエラータイプ(合計 28 種類): https://ai-sdk.dev/docs/reference/ai-sdk-errors
- トラブルシューティングガイド: https://ai-sdk.dev/docs/troubleshooting
プロバイダーのドキュメント
- OpenAI プロバイダー: https://ai-sdk.dev/providers/ai-sdk-providers/openai
- Anthropic プロバイダー: https://ai-sdk.dev/providers/ai-sdk-providers/anthropic
- Google プロバイダー: https://ai-sdk.dev/providers/ai-sdk-providers/google
- すべてのプロバイダー(25 以上): https://ai-sdk.dev/providers/overview
- コミュニティプロバイダー: https://ai-sdk.dev/providers/community-providers
Cloudflare 連携
- Workers AI Provider(コミュニティ): https://ai-sdk.dev/providers/community-providers/cloudflare-workers-ai
- Cloudflare Workers AI ドキュメント: https://developers.cloudflare.com/workers-ai/
- workers-ai-provider GitHub: https://github.com/cloudflare/ai/tree/main/packages/workers-ai-provider
- Cloudflare AI SDK の設定: https://developers.cloudflare.com/workers-ai/configuration/ai-sdk/
Vercel / Next.js 連携
- Vercel AI SDK 5.0 ブログ: https://vercel.com/blog/ai-sdk-5
- 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
- Vercel Functions: https://vercel.com/docs/functions
- Vercel Streaming: https://vercel.com/docs/functions/streaming
GitHub とコミュニティ
- GitHub リポジトリ: https://github.com/vercel/ai
- GitHub のイシュー: https://github.com/vercel/ai/issues
- Discord コミュニティ: https://discord.gg/vercel
テンプレートとリファレンス
このスキルには、次のものが含まれています。
- 13 個のテンプレート:
templates/にある、そのまま使えるコード例 - 5 個のリファレンスドキュメント:
references/にある詳細なガイド - 1 個のスクリプト:
scripts/にあるバージョンチェッカー
すべてのファイルは、プロジェクトにコピーしてすぐに使えるよう最適化されています。
最終更新日: 2025-10-29 スキルのバージョン: 1.1.0 AI SDK のバージョン: 5.0.81+