Vercel AI SDKとNext.jsでマルチモデル対応のAIチャットストリーミングを構築する

Development tutorial - IT technology blog
Development tutorial - IT technology blog

マルチモデルAI統合における課題

クライアントから「GPT-4からClaude 3.5に切り替えたい」と言われ、ストリーミングロジックを書き直すために徹夜した経験はありませんか?プロバイダーごとにデータ構造やストリーミングの処理方法が異なるため、手動で実装する場合、メッセージ配列の管理、ネットワークエラーの処理、UI状態の維持などは非常に複雑になります。

Vercel AI SDKはこの問題を解決するために誕生しました。これは抽象化レイヤー(abstraction layer)として機能し、単一のコードセットであらゆるAIモデルとの通信を可能にします。それでは、OpenAI、Anthropic、Googleの「3大巨頭」をサポートするチャットアプリを実際に構築してみましょう。

実装方法の比較

コードを書く前に、現在主流の選択肢を比較してみましょう:

  • 従来のFetch API: シンプルですが、ストリーミング処理においては悪夢です。ReadableStreamを手動で処理し、ステートを管理する必要があり、不適切な実装はメモリリークの原因となります。
  • LangChain: RAGやAgentのような複雑なタスクには非常に強力です。しかし、シンプルなチャットインターフェースを作成するだけなら、ライブラリが重く、学習コストも高くなります。
  • Vercel AI SDK: Next.jsエコシステムにおける最適解です。useChatフックを提供しており、UI処理のコードを80%削減し、サーバーからのスムーズなデータストリーミングを標準でサポートしています。

なぜVercel AI SDKを使うべきか?

最大の利点は統一性(Unified)です。ロジックを一度書くだけで済みます。GPT-4oからClaude 3.5 Sonnetへの切り替えも、変数を1つ変更するだけで、わずか5秒で完了することもあります。

ただし、このツールはJavaScript/TypeScriptに強く依存しています。バックエンドがPythonやGoで動作している場合、強力なReactフックの恩恵を十分に受けることはできません。しかし、Next.jsユーザーにとっては、これ以上ない強力な味方となります。

詳細な実装手順

1. Next.jsプロジェクトの初期化

まず、App Routerを使用した新しいNext.jsプロジェクトを作成します:

npx create-next-app@latest my-ai-chat
cd my-ai-chat

次に、コアライブラリと対応する各プロバイダーをインストールします:

npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google zod

2. 環境変数の設定

ルートディレクトリに.env.localファイルを作成します。OpenAI、Anthropic、Google AI Studioのダッシュボードから取得したAPIキーをここに入力してください。

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_GENERATIVE_AI_API_KEY=...

3. APIルート(バックエンド)の作成

app/api/chat/route.tsAI呼び出しのロジックを処理します。クライアントからのリクエストに基づいて、バックエンドが自動的にモデルを選択するように構成します。

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

export const maxDuration = 30;

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

  let selectedModel;
  if (modelType === 'claude') {
    selectedModel = anthropic('claude-3-5-sonnet-20240620');
  } else if (modelType === 'gemini') {
    selectedModel = google('models/gemini-1.5-pro-latest');
  } else {
    selectedModel = openai('gpt-4o');
  }

  const result = await streamText({
    model: selectedModel,
    messages,
  });

  return result.toDataStreamResponse();
}

複雑なJSONリクエストをデバッグする際、バラバラのテキストを目で追う代わりに、JSON Formatterを使用すると、データ構造をより素早く確認できます。

4. チャットインターフェース(フロントエンド)の作成

app/page.tsxuseChatフックを使用します。このフックは、メッセージリストと入力状態の管理を自動的に行います。

'use client';

import { useChat } from 'ai/react';
import { useState } from 'react';

export default function Chat() {
  const [modelType, setModelType] = useState('openai');
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    body: { modelType },
  });

  return (
    <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
      <select 
        value={modelType} 
        onChange={(e) => setModelType(e.target.value)}
        className="mb-4 p-2 border rounded text-black"
      >
        <option value="openai">GPT-4o</option>
        <option value="claude">Claude 3.5 Sonnet</option>
        <option value="gemini">Gemini 1.5 Pro</option>
      </select>

      {messages.map(m => (
        <div key={m.id} className="mb-4">
          <span className="font-bold">{m.role === 'user' ? 'あなた: ' : 'AI: '}</span>
          {m.content}
        </div>
      ))}

      <form onSubmit={handleSubmit}>
        <input
          className="fixed bottom-0 w-full max-w-md p-2 mb-8 border rounded shadow-xl text-black"
          value={input}
          placeholder="何か質問してください..."
          onChange={handleInputChange}
        />
      </form>
    </div>
  );
}

実践的なアドバイス:タイムアウトエラーの回避

ストリーミング実装における一般的なエラーはmaxDurationに関するものです。VercelのHobbyプラン(無料版)では、Serverless Functionは10秒後にタイムアウトします。GPT-4のような「低速な」モデルでは、レスポンスの完了までに15〜20秒かかることがあります。

これを解決するには、常にexport const maxDuration = 30;を宣言してください(Proプランの最大制限は300秒です)。また、useChatから提供されるisLoading変数を利用してローディング状態を表示し、ユーザーがアプリがフリーズしたと感じないように工夫しましょう。

おわりに

Vercel AI SDKは単なるライブラリではなく、Web上でAIアプリケーションを構築するための新しい標準です。何十ページもの異なるAPIドキュメントを読む時間を省き、ユーザーエクスペリエンスの向上に集中することができます。

次のステップとして、**Tool Calling**機能を試してみてください。これは、AIがJavaScript関数を自ら呼び出して、リアルタイムの天気データを取得したり、データベースをクエリしたりできるようにする技術です。

Share: