※本記事には広告(楽天アフィリエイト)リンクが含まれる場合があります。

「Claude・OpenAI・Geminiを使い分けたいが、APIの呼び出し方がバラバラで面倒」——AI開発者なら誰もが感じる悩みを解決するのがVercel AI SDKです。

Vercel AI SDKは、複数のAIプロバイダーを統一インターフェースで扱えるTypeScriptライブラリです。テキスト生成・ストリーミング・構造化データ生成・ツール呼び出しといったAIアプリの主要機能を、わずか数行のコードで実装できます。React/Next.jsとの連携も強力で、AIチャットUIをフルスクラッチなしで作れる点が大きな魅力です。

本記事では、Vercel AI SDKの基本概念からReact Hooksを使った実践的なチャットアプリ構築まで、個人開発者がAIサービスを1から作れるレベルまで丁寧に解説します。

広告・楽天アフィリエイト

プログラミング技術書

AI開発・TypeScript実践書を探す。

楽天ポイント還元

技術書を楽天で見る →

Vercel AI SDKとは?

Vercel AI SDKは、Vercelが開発・メンテナンスするオープンソースのTypeScriptライブラリです。OpenAI・Anthropic(Claude)・Google(Gemini)・Mistral・Groqなど20以上のAIプロバイダーを、共通のAPIで扱えるようにします。

2024年にリリースされたv3以降、急速に普及し、2026年現在ではAI系スタートアップや個人開発者の標準ライブラリと言っても過言ではありません。GitHubのスター数は10万を超えています。

Vercel AI SDKが解決する問題

AIプロバイダーを直接使うと、次のような問題が発生します。

  • APIの差異:OpenAIとAnthropicではリクエスト形式がまったく異なる
  • ストリーミングの煩雑さ:Server-Sent Eventsの扱いを自前で実装する必要がある
  • 型安全性の欠如:プロバイダーごとに型定義が違い、TypeScriptの恩恵を受けにくい
  • UI統合の難しさ:チャットUIを作るには大量のボイラープレートが必要

Vercel AI SDKはこれらを抽象化し、プロバイダーを1行変えるだけで切り替えられる設計になっています。

パッケージ構成

パッケージ 役割
ai コア機能(generateText, streamText等)
@ai-sdk/openai OpenAIプロバイダー(GPT-4o等)
@ai-sdk/anthropic Anthropicプロバイダー(Claude Sonnet等)
@ai-sdk/google Googleプロバイダー(Gemini 2.0等)
@ai-sdk/react React Hooks(useChat, useCompletion)

インストールとセットアップ

Next.js 15でClaude Sonnetを使うケースを例に、セットアップ手順を説明します。

# コアパッケージとAnthropicプロバイダーをインストール
npm install ai @ai-sdk/anthropic

# または OpenAI の場合
npm install ai @ai-sdk/openai

APIキーは環境変数で設定します。

# .env.local
ANTHROPIC_API_KEY=sk-ant-xxxx

テキスト生成(generateText / streamText)

Vercel AI SDKの基本はgenerateTextとstreamTextの2関数です。

generateText — 完了まで待つ

レスポンス全体を待ってから使いたい場合はgenerateTextを使います。

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

const { text } = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  prompt: 'TypeScriptの型ガードを説明してください',
});

console.log(text);

プロバイダーをOpenAIに切り替えたい場合は1行変えるだけです。

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

const { text } = await generateText({
  model: openai('gpt-4o'),  // ここだけ変更
  prompt: 'TypeScriptの型ガードを説明してください',
});

streamText — ストリーミング

チャットUIなど、リアルタイムで文字を表示したい場合はstreamTextを使います。

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

const result = streamText({
  model: anthropic('claude-sonnet-4-6'),
  prompt: 'Rustの所有権について詳しく説明してください',
});

// ストリームをリアルタイムで処理
for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}

systemプロンプトとmessages

会話履歴を渡す場合はmessages配列を使います。

const { text } = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  system: 'あなたはTypeScriptの専門家です。簡潔に回答してください。',
  messages: [
    { role: 'user', content: 'Zodとは何ですか?' },
    { role: 'assistant', content: 'Zodは...' },
    { role: 'user', content: 'React Hook Formとの連携方法を教えてください' },
  ],
});

構造化データ生成(generateObject / streamObject)

Vercel AI SDKの強力な機能のひとつが構造化データ生成です。Zodスキーマを渡すと、AIが型安全なオブジェクトを返してくれます。JSONを自前でパースする必要がありません。

generateObject — JSON生成

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

const { object } = await generateObject({
  model: anthropic('claude-sonnet-4-6'),
  schema: z.object({
    title: z.string().describe('記事タイトル'),
    summary: z.string().describe('200字以内の要約'),
    tags: z.array(z.string()).describe('関連タグ(3〜5個)'),
    difficulty: z.enum(['beginner', 'intermediate', 'advanced']),
  }),
  prompt: 'Next.js App RouterとReact Server Componentsについての記事を提案してください',
});

console.log(object.title);   // "【2026年版】Next.js App Router完全ガイド..."
console.log(object.tags);    // ["Next.js", "React", "SSR", ...]

型推論が自動で効くため、object.titleにはstring型が付き、誤ったプロパティへのアクセスはコンパイルエラーになります。

streamObject — ストリーミング構造化生成

大きなオブジェクトを生成しながらUIを段階的に更新したい場合はstreamObjectが便利です。

import { streamObject } from 'ai';

const { partialObjectStream } = streamObject({
  model: anthropic('claude-sonnet-4-6'),
  schema: z.object({
    items: z.array(z.object({
      name: z.string(),
      description: z.string(),
    })),
  }),
  prompt: 'TypeScript学習ロードマップを10ステップで作成してください',
});

for await (const partial of partialObjectStream) {
  // 生成されるたびにUIを更新
  console.log(partial.items?.length);
}

ツール呼び出し(Tool Use)

AIが外部APIやデータベースを呼び出せるようにするのがツール呼び出しです。Vercel AI SDKではtool関数でツールを定義し、generateTextに渡します。

ツールの定義と使用

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

const result = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  tools: {
    getWeather: tool({
      description: '指定した都市の天気を取得します',
      parameters: z.object({
        city: z.string().describe('都市名(例: Tokyo)'),
      }),
      execute: async ({ city }) => {
        // 実際のAPIを呼び出す
        const res = await fetch(`https://api.weather.example.com/${city}`);
        return res.json();
      },
    }),
  },
  prompt: '東京と大阪の今日の天気を教えてください',
});

AIは必要と判断した場合にgetWeatherを呼び出し、結果を受け取ってから最終回答を生成します。

maxSteps — 多段階ツール呼び出し

複雑なタスクでは、ツールを複数回呼び出す必要があります。maxStepsで最大ステップ数を指定できます。

const result = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  tools: { searchWeb, fetchPage, summarize },
  maxSteps: 5,  // 最大5ステップ実行
  prompt: 'React Server Componentsの最新情報をまとめてください',
});

これにより、検索→ページ取得→要約というエージェント的な動作を実現できます。

React Hooks(useChat / useCompletion)

Next.jsなどのReactアプリでAIチャットUIを作る場合、useChatフックがほぼすべての面倒を引き受けてくれます。

useChat — チャットUI

フロントエンド(app/chat/page.tsx)

'use client';
import { useChat } from '@ai-sdk/react';

export default function ChatPage() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: '/api/chat',
  });

  return (
    <div>
      {messages.map((m) => (
        <div key={m.id} className={m.role === 'user' ? 'user' : 'ai'}>
          {m.content}
        </div>
      ))}

      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="メッセージを入力..."
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading}>送信</button>
      </form>
    </div>
  );
}

バックエンド(app/api/chat/route.ts)

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

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

  const result = streamText({
    model: anthropic('claude-sonnet-4-6'),
    system: 'あなたは親切なアシスタントです。',
    messages,
  });

  return result.toDataStreamResponse();
}

toDataStreamResponse()がストリーミングレスポンスを自動生成するため、SSE(Server-Sent Events)の実装が不要です。

useCompletionフック

会話履歴が不要なシンプルなテキスト補完にはuseCompletionを使います。

import { useCompletion } from '@ai-sdk/react';

export function TextGenerator() {
  const { completion, input, handleInputChange, handleSubmit } = useCompletion({
    api: '/api/completion',
  });

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input value={input} onChange={handleInputChange} />
        <button type="submit">生成</button>
      </form>
      <p>{completion}</p>
    </div>
  );
}

マルチモーダル対応(画像入力)

Claude SonnetやGPT-4oなど対応モデルでは、画像をプロンプトに含められます。

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

const { text } = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  messages: [
    {
      role: 'user',
      content: [
        { type: 'text', text: 'この画像に映っているUIの問題点を指摘してください' },
        {
          type: 'image',
          image: fs.readFileSync('./screenshot.png'),  // Bufferでも URL でも可
          mimeType: 'image/png',
        },
      ],
    },
  ],
});

プロバイダー別の特徴と選び方

Vercel AI SDKがサポートする主要プロバイダーを比較します。

プロバイダー 主なモデル 強み パッケージ
Anthropic Claude Sonnet 4.6
Claude Haiku 4.5
コーディング・長文・指示追従 @ai-sdk/anthropic
OpenAI GPT-4o
GPT-4o mini
画像生成・音声・汎用性 @ai-sdk/openai
Google Gemini 2.0 Flash
Gemini 2.0 Pro
長コンテキスト・速度・コスト @ai-sdk/google
Groq Llama 3.1・Mixtral 超高速推論(無料枠あり) @ai-sdk/groq
Mistral Mistral Large 欧州データ規制・コスト効率 @ai-sdk/mistral

個人開発での選び方

  • コーディングアシスタント系:Claude Sonnet(精度と速度のバランスが最良)
  • コスト重視・高頻度API:Gemini Flash または Groq(無料枠が充実)
  • 画像・音声を含むアプリ:GPT-4o(マルチモーダルが最も成熟)
  • プロトタイプ・検証:Claude Haiku / Gemini Flash(安く素早く試せる)

ミドルウェアとロギング

Vercel AI SDKはミドルウェアによってモデルの動作をカスタマイズできます。ロギングやキャッシュ、プロンプト変換などを挿入できます。

import { wrapLanguageModel, extractReasoningMiddleware } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';

const model = wrapLanguageModel({
  model: anthropic('claude-sonnet-4-6'),
  middleware: {
    wrapGenerate: async ({ doGenerate, params }) => {
      // リクエストをログ
      console.log('[AI Request]', params.prompt);

      const result = await doGenerate();

      // レスポンスをログ
      console.log('[AI Response]', result.text?.slice(0, 100));

      return result;
    },
  },
});

また、テレメトリ(OpenTelemetry)との統合もサポートしており、Jaeger・Zipkin・LangFuseなどのオブザーバビリティツールにトレースを送れます。

const result = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  prompt: '...',
  experimental_telemetry: {
    isEnabled: true,
    functionId: 'chat-completion',
    metadata: { userId: 'user-123' },
  },
});

実践:Next.jsでAIチャットアプリを作る

ここまでの機能を組み合わせて、コンテキストを保持するチャットアプリを作ります。

プロジェクト構成

app/
  api/
    chat/
      route.ts    # ストリーミングAPIエンドポイント
  chat/
    page.tsx      # チャットUI
  layout.tsx
.env.local        # ANTHROPIC_API_KEY

APIルート(app/api/chat/route.ts)

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

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

  const result = streamText({
    model: anthropic('claude-sonnet-4-6'),
    system: `あなたは個人開発者をサポートするAIアシスタントです。
技術的な質問に対して、具体的なコード例を交えながら回答してください。`,
    messages,
    tools: {
      calculateTokenCost: tool({
        description: 'トークン数からAPIコストを計算します',
        parameters: z.object({
          tokens: z.number().describe('トークン数'),
          model: z.enum(['claude-sonnet-4-6', 'gpt-4o', 'gemini-2.0-flash']),
        }),
        execute: async ({ tokens, model }) => {
          const prices: Record<string, number> = {
            'claude-sonnet-4-6': 0.000003,
            'gpt-4o': 0.0000025,
            'gemini-2.0-flash': 0.000001,
          };
          return { cost: tokens * (prices[model] ?? 0), currency: 'USD' };
        },
      }),
    },
    maxSteps: 3,
  });

  return result.toDataStreamResponse();
}

チャットUI(app/chat/page.tsx)

'use client';
import { useChat } from '@ai-sdk/react';
import { useState } from 'react';

export default function ChatPage() {
  const { messages, input, handleInputChange, handleSubmit, isLoading, error } =
    useChat({ api: '/api/chat' });

  return (
    <main style={{ maxWidth: '800px', margin: '0 auto', padding: '2rem' }}>
      <h1>AI アシスタント</h1>

      <div style={{ minHeight: '400px', border: '1px solid #ccc', padding: '1rem', marginBottom: '1rem' }}>
        {messages.map((m) => (
          <div key={m.id} style={{ marginBottom: '1rem', textAlign: m.role === 'user' ? 'right' : 'left' }}>
            <span style={{
              background: m.role === 'user' ? '#0070f3' : '#f0f0f0',
              color: m.role === 'user' ? 'white' : 'black',
              padding: '0.5rem 1rem',
              borderRadius: '8px',
              display: 'inline-block',
              maxWidth: '80%',
              whiteSpace: 'pre-wrap',
            }}>
              {m.content}
            </span>
          </div>
        ))}
        {isLoading && <p>生成中...</p>}
        {error && <p style={{ color: 'red' }}>エラー: {error.message}</p>}
      </div>

      <form onSubmit={handleSubmit} style={{ display: 'flex', gap: '0.5rem' }}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="質問を入力してください..."
          style={{ flex: 1, padding: '0.5rem', borderRadius: '4px', border: '1px solid #ccc' }}
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading}>送信</button>
      </form>
    </main>
  );
}

エラーハンドリングとレート制限への対応

本番環境では、APIエラーやレート制限への対応が必須です。

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

try {
  const { text } = await generateText({
    model: anthropic('claude-sonnet-4-6'),
    prompt: '...',
    maxRetries: 3,  // 自動リトライ(デフォルト2回)
  });
} catch (error) {
  if (error instanceof RetryError) {
    console.error('リトライ上限に達しました:', error.message);
  }
  throw error;
}

また、streamTextでネットワークエラーが発生した場合は、onErrorコールバックでハンドリングできます。

コスト最適化のコツ

個人開発でAPIコストを抑えるポイントをまとめます。

1. キャッシュを活用する

Anthropic・OpenAIはプロンプトキャッシュ機能を提供しています。Vercel AI SDKではプロバイダー設定でキャッシュを有効化できます。

const { text } = await generateText({
  model: anthropic('claude-sonnet-4-6', {
    cacheControl: { type: 'ephemeral' },  // プロンプトキャッシュ有効
  }),
  system: '非常に長いシステムプロンプト...',  // キャッシュされる
  prompt: '各リクエストで変わる部分',
});

2. モデルを用途別に使い分ける

// 簡単なタスクは軽量モデル
const classify = await generateText({
  model: anthropic('claude-haiku-4-5-20251001'),  // 安価
  prompt: `以下のテキストをpositive/negativeに分類: "${text}"`,
});

// 複雑なタスクは高性能モデル
const analysis = await generateText({
  model: anthropic('claude-sonnet-4-6'),  // 高精度
  prompt: '複雑なコードレビューをお願いします...',
});

3. maxTokensで出力を制限する

const { text } = await generateText({
  model: anthropic('claude-sonnet-4-6'),
  prompt: '一言で答えてください: TypeScriptとは?',
  maxTokens: 100,  // 過剰な出力を防ぐ
});

Vercel AI SDKの主なアップデート(2026年)

2026年に入り、Vercel AI SDKには以下のような機能が追加されました。

  • Agentic ループの改善:maxStepsの上限が引き上げられ、長期タスクに対応
  • Computer Use対応:Claude 3.5以降のコンピュータ操作ツールをSDK経由で呼び出せる
  • 音声入出力:OpenAI Realtime APIとの統合でリアルタイム音声会話が可能
  • メモリ管理ヘルパー:長期会話のコンテキスト管理を自動化するユーティリティが追加
  • Cloudflare Workers対応強化:エッジランタイムでの動作が安定

他のAI SDKとの比較

SDK 特徴 向いているケース
Vercel AI SDK マルチプロバイダー・React統合・型安全 Next.js/Reactアプリ、AIチャット
LangChain.js チェーン・エージェント・RAG特化 複雑なエージェント、RAGシステム
Anthropic SDK Claude専用・公式・低レベルAPI Claude限定・最新機能を即使いたい
OpenAI SDK OpenAI専用・Assistants API対応 Assistants・File Search・Code Interpreter

シンプルなチャットやコンテンツ生成ならVercel AI SDKが最もコスパが高い選択です。複数プロバイダーを切り替えたい・Next.jsと連携したいなら特に有力です。一方、RAGやLangGraphのような複雑なエージェントグラフが必要な場合はLangChain.jsも検討しましょう。

まとめ:Vercel AI SDKを選ぶ理由

Vercel AI SDKは、AIアプリ開発の摩擦を極限まで下げるライブラリです。

  • 統一API:プロバイダー変更が1行で完了
  • 型安全:Zodとの組み合わせで構造化データを安全に扱える
  • React統合:useChat1つでチャットUIの大半が完成
  • ストリーミング:複雑なSSE実装が不要
  • エージェント対応:maxStepsで多段階ツール呼び出しが簡単

「どのAIを使おうか迷っている」「まずAIアプリを1本作ってみたい」という方には、Vercel AI SDK + Claude Sonnet + Next.jsの組み合わせが2026年現在の最良スタートだと言えます。公式ドキュメント(sdk.vercel.ai)にも豊富なサンプルが揃っているので、ぜひ手を動かしてみてください。