AI活用

Vercel AI SDKの使い方|Next.jsでマルチモデル対応AIアプリを作る

Vercel AI SDKをNext.jsで使い、OpenAI・Claude・Geminiをprovider設定で切り替える最小構成、generateText、streamText、本番確認を解説します。

この記事の目次
  1. 結論:AI SDK Coreでprovider切替を分離する
  2. Next.jsプロジェクトへ導入する
  3. 3つのproviderを切り替える
  4. generateTextで応答を得る
  5. streamTextで逐次表示する
  6. provider差を吸収しすぎない
  7. fallbackを設計する
  8. 本番前チェックリスト
  9. まとめ

Vercel AI SDKは、OpenAI、Anthropic、Googleなどのモデルを共通に近いAPIで呼ぶTypeScript向けSDKです。Next.jsでは、server routeでproviderを選び、generateTextstreamTextへ渡せます。

共通APIにしても、全モデルの機能が同じになるわけではありません。Tool Calling、画像入力、構造化出力、usage、finish reasonの対応差を確認し、providerごとのテストを残します。

この記事では、AI SDK CoreとUIの違い、3provider切替、テキスト生成、ストリーミング、本番のfallback・ログ・費用管理を解説します。

情報確認日:2026年7月17日(日本時間)

結論:AI SDK Coreでprovider切替を分離する

Browser
  ↓ POST /api/generate
Next.js Route Handler
  ↓ getModel(provider)
AI SDK Core
  ├─ @ai-sdk/openai
  ├─ @ai-sdk/anthropic
  └─ @ai-sdk/google
      ↓
各provider API
領域 役割
AI SDK Core generateText、streamText、tool、structured outputなど
AI SDK UI React・Next.js等のchat・streaming UI hook
Provider package 各事業者の認証・model・固有機能を接続
スポンサーリンク

Next.jsプロジェクトへ導入する

npx create-next-app@latest ai-sdk-demo --ts --app
cd ai-sdk-demo
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google

APIキーとmodel IDはserverの環境変数へ設定します。実際の値は公開repositoryへ保存しません。

OPENAI_API_KEY=...
OPENAI_MODEL=...
ANTHROPIC_API_KEY=...
ANTHROPIC_MODEL=...
GOOGLE_GENERATIVE_AI_API_KEY=...
GOOGLE_MODEL=...

AI SDKのpackage majorは更新されるため、導入時は現行Get startedとmigration guideを確認します。この記事は2026年7月17日時点のAI SDK 7を基準にしています。

3つのproviderを切り替える

lib/models.tsを作ります。

import { anthropic } from "@ai-sdk/anthropic";
import { google } from "@ai-sdk/google";
import { openai } from "@ai-sdk/openai";
import type { LanguageModel } from "ai";

export type ProviderName = "openai" | "anthropic" | "google";

const required = (name: string): string => {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is not set`);
  return value;
};

export function getModel(provider: ProviderName): LanguageModel {
  switch (provider) {
    case "openai":
      return openai(required("OPENAI_MODEL"));
    case "anthropic":
      return anthropic(required("ANTHROPIC_MODEL"));
    case "google":
      return google(required("GOOGLE_MODEL"));
  }
}

model IDをcodeへ固定せず、環境ごとに設定します。providerを利用者が自由入力するのではなく、許可した値のenumとして検証します。

generateTextで応答を得る

app/api/generate/route.tsを作ります。

import { generateText } from "ai";
import { getModel, type ProviderName } from "@/lib/models";

const providers = new Set<ProviderName>([
  "openai",
  "anthropic",
  "google",
]);

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

  if (
    !body ||
    typeof body !== "object" ||
    !("provider" in body) ||
    !("prompt" in body) ||
    typeof body.provider !== "string" ||
    !providers.has(body.provider as ProviderName) ||
    typeof body.prompt !== "string" ||
    body.prompt.length < 1 ||
    body.prompt.length > 2000
  ) {
    return Response.json({ error: "Invalid input" }, { status: 400 });
  }

  const result = await generateText({
    model: getModel(body.provider as ProviderName),
    system: "簡潔な日本語で回答してください。",
    prompt: body.prompt,
  });

  return Response.json({
    text: result.text,
    finishReason: result.finishReason,
    usage: result.usage,
  });
}

generateTextは応答完了後に結果を返すため、短い分類、下書き、server-side batchに向きます。finishReasonusageも保存すると、途中終了と費用を確認できます。

streamTextで逐次表示する

import { streamText } from "ai";
import { getModel } from "@/lib/models";

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

  if (typeof prompt !== "string" || prompt.length > 2000) {
    return Response.json({ error: "Invalid input" }, { status: 400 });
  }

  const result = streamText({
    model: getModel("openai"),
    prompt,
    onFinish({ finishReason, usage }) {
      console.info({ finishReason, usage });
    },
  });

  return result.toTextStreamResponse();
}

chat UIではAI SDK UIのhookを組み合わせられます。本文生成だけならtext stream、message・tool・metadataを扱うchatならUI message streamを選びます。

provider差を吸収しすぎない

機能 共通化 確認
基本text しやすい system、停止理由、token
画像入力 一部可能 形式、size、model対応
Tool Calling API形状は共通化可能 parallel、strict、streaming差
構造化出力 schema共通化可能 対応model、制限、失敗処理
reasoning 固有差が大きい providerOptionsと課金
usage 共通fieldあり providerの課金項目との差

Provider support表で対応機能を確認し、アプリが必須とする機能ごとに3providerで同じintegration testを実行します。

fallbackを設計する

失敗したら無条件に別providerへ送る設計は、データ処理地域、契約、費用、品質を変える可能性があります。fallback可能なデータと用途を明示します。

  1. timeout、429、5xxなど再試行可能な失敗を分類する
  2. 同じproviderで回数を制限して再試行する
  3. 別providerへ送ってよいデータか確認する
  4. 必須機能と出力schemaを満たすmodelだけを候補にする
  5. 切替をログと画面へ記録する

本番前チェックリスト

  • APIキーをserver-side secretへ置いた
  • providerとmodelをallowlistで制限した
  • 入力長、出力上限、timeoutを設定した
  • usage、finish reason、処理時間、providerを記録した
  • 429・5xxの再試行に上限がある
  • providerごとの評価とintegration testがある
  • fallback時のデータ送信規程を確認した
  • 利用者ごとの認証、rate limit、予算上限がある
  • package・provider・model変更を回帰評価する

JSON出力をアプリで使う場合はAIにJSONを出力させる方法、Tool Callingの基本はTool Callingとはも参考になります。

まとめ

Vercel AI SDKでは、AI SDK Coreとprovider packageを分け、Next.jsのserver routeでmodelを選びます。generateTextは完了後の応答、streamTextは逐次表示に使います。

共通APIは便利ですが、modelの能力差は残ります。providerごとの対応機能、評価、ログ、費用、fallbackのデータ条件を確認して本番へ進めてください。

スポンサーリンク