会員限定
Next.jsでAIチャットボットを作る|Vercel AI SDK×Claude完全実装ガイド
Next.jsでAIチャットボットを作る|Vercel AI SDK×Claude完全実装ガイドこんにちは、橋本裕也です。近年、生成AIをWebアプリケーションに統合することは珍しくなくなりました。し
2026年3月27日
Next.jsでAIチャットボットを作る|Vercel AI SDK×Claude完全実装ガイド
こんにちは、西岡章です。
生成AIをWebアプリケーションに組み込むことは、もう珍しくない時代になりました。ただ、実際に作ろうとするとリアルタイムレスポンス、ストリーミング対応、エラーハンドリングなど、細かいところで苦労することが多いというのが正直なところです。今回は、Vercel AI SDKとClaude APIを使ってNext.jsで本格的なAIチャットボットを構築する方法をお伝えします。
環境構築と初期設定
結論から言うと、まずはプロジェクトを初期化するところから始まります。
npx create-next-app@latest ai-chatbot --typescript --tailwind
cd ai-chatbot
npm install ai @anthropic-ai/sdk
次にAnthropicのAPIキーを環境変数に設定します。.env.localというファイルを作成して、そこにキーを入れておきましょう。
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxx
API ルートの実装
Next.jsのApp Routerを使ったAPI実装です。app/api/chat/route.tsを新規作成します。
import { Anthropic } from "@anthropic-ai/sdk";
import { NextRequest, NextResponse } from "next/server";
const client = new Anthropic();
export const runtime = "nodejs";
export async function POST(request: NextRequest) {
try {
const { messages } = await request.json();
// バリデーション
if (!Array.isArray(messages) || messages.length === 0) {
return NextResponse.json(
{ error: "メッセージが必要です" },
{ status: 400 }
);
}
// Claudeにリクエスト
const response = await client.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1024,
system:
"あなたは親切で正確なAIアシスタントです。ユーザーの質問に丁寧に答えてください。",
messages: messages.map((msg: any) => ({
role: msg.role,
content: msg.content,
})),
});
const assistantMessage =
response.content[0].type === "text" ? response.content[0].text : "";
return NextResponse.json({
message: assistantMessage,
});
} catch (error) {
console.error("API Error:", error);
return NextResponse.json(
{ error: "チャット処理に失敗しました" },
{ status: 500 }
);
}
}
ストリーミング対応版の実装
より快適なユーザー体験を実現するには、ストリーミングレスポンスに対応させるのが効果的です。テキストがリアルタイムで流れてくるので、ユーザーの満足度がかなり変わります。
import { Anthropic } from "@anthropic-ai/sdk";
import { NextRequest } from "next/server";
const client = new Anthropic();
export const runtime = "nodejs";
export async function POST(request: NextRequest) {
try {
const { messages } = await request.json();
const stream = await client.messages.stream({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1024,
system: "あなたは親切で正確なAIアシスタントです。",
messages: messages,
});
// ReadableStreamを生成
const encoder = new TextEncoder();
const readable = new ReadableStream({
async start(controller) {
for await (const event of stream) {
if (
event.type === "content_block_delta" &&
event.delta.type === "text_delta"
) {
controller.enqueue(encoder.encode(event.delta.text));
}
}
controller.close();
},
});
return new Response(readable, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
} catch (error) {
console.error("Stream Error:", error);
return new Response("エラーが発生しました", { status: 500 });
}
}