Vercel AI SDK 触ってみた
はじめに
こんにちは。令和トラベルでフロントエンドエンジニアをしている @ippo_012 です。
最近、Vercel AI SDKを触る機会があったので、その内容をシェアしたいと思います。
本記事は、令和トラベルの社内Tech LT会で共有した内容をベースにしていますが、その後にリリースされたAI SDK 3.1での変更点も織り込んでアップデートしています。
※ この記事は令和トラベルのTech LT会で共有した内容を記事にしたものです。社外の方にもご参加いただけるTech LT会は connpass にて告知しています。
Vercel AI SDKとは
Vercel AI SDK は、AIを活用したユーザーインターフェイスの構築に役立つツールです。
Server-Sent Events (SSE)を使ってChatGPTのようにテキストをパラパラ表示するUIを簡単に実装できます。
Next.js、Nuxt.js、Svelteなどのフレームワークや、OpenAI、Anthropic、Googleなどの大規模言語モデル(LLM)をサポートしています。
Vercel AI SDKは以下の3つの主要な機能で構成されています。
- AI SDK Core: テキスト生成、構造化オブジェクト生成、ツール呼び出しのための統一されたAPI
- AI SDK UI: チャットインターフェースを素早く構築するためのフレームワークに依存しないフック
- AI SDK RSC: React Server Components (RSC)を使用して生成されたユーザーインターフェースをストリーミングするためのライブラリ
簡単な実装例
ここでは、Next.js App Routerを使って簡単なAIチャットボットを実装する例を紹介します。
まず、新しいNext.jsアプリケーションを作成します。
pnpm create next-app@latest my-ai-app
次に、ai
と@ai-sdk/openai
をインストールします。
pnpm install ai @ai-sdk/openai zod
.env.local
ファイルを作成し、OpenAI APIキーを設定します。
OPENAI_API_KEY=xxxxxxxxx
ルートハンドラ(app/api/chat/route.ts
)を作成し、以下のコードを追加します。
import { openai } from '@ai-sdk/openai';
import { StreamingTextResponse, streamText } from 'ai';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
});
return new StreamingTextResponse(result.toAIStream());
}
このコードでは、以下のことを行っています。
- リクエストのボディから
messages
を抽出します。 -
streamText
関数を呼び出し、モデルプロバイダ(openai
)とメッセージを渡します。 -
streamText
関数から返されたStreamTextResult
オブジェクトからtoAIStream
関数を使ってストリームを変換します。 -
StreamingTextResponse
を使って結果をクライアントに送信します。
次に、ルートページ(app/page.tsx
)を更新し、チャットメッセージのリストとユーザー入力を表示します。
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
{messages.map(m => (
<div key={m.id} className="whitespace-pre-wrap">
{m.role === 'user' ? 'User: ' : 'AI: '}
{m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
value={input}
placeholder="Say something..."
onChange={handleInputChange}
/>
</form>
</div>
);
}
このページでは、useChat
フックを利用しています。このフックは、デフォルトで先ほど作成した/api/chat
エンドポイントを使用します。
useChat
フックは、ユーザー入力とフォーム送信を処理するための関数と状態を提供します。
-
messages
- 現在のチャットメッセージ(idとrole、contentプロパティを持つオブジェクトの配列) -
input
- ユーザー入力フィールドの現在の値 -
handleInputChange
とhandleSubmit
- ユーザーの操作(入力フィールドへの入力とフォームの送信)を処理する関数 -
isLoading
- APIリクエストが進行中かどうかを示すブール値
これで、簡単なAIチャットボットが実装できました。
AI SDK RSC
AI SDK 3.1 では、これまでのGenerative UIがAI SDK RSCと命名されました。
AI SDK RSCを利用するとプレーンテキストだけでなくカスタマイズしたUIをレンダリングすることができます。React Server Components (RSC) を利用してLLMから直接カスタムUIをストリーミングしています。
現在はNext.js App Routerのみの対応ですが、他のフレームワークもRSC対応次第サポート予定だそうです。
ai/rscモジュールを利用して開発します。
AI SDK 3.1では、AI SDK Core Language Model Specificationと互換性のある新しい関数 streamUI
が追加されました。
これは render
の後継となるもので、次のマイナーリリースで render
は非推奨となる予定です。
以下は、ライブの天気情報を取得し、streamUI
でカスタムUIをレンダリングするReact Server Actionの例です。
import { streamUI } from 'ai/rsc'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
import { Spinner, Weather } from '@/components'
import { getWeather } from '@/utils'
async function submitMessage(userInput) { // 'What is the weather in SF?'
'use server'
const result = streamUI({
model: openai('gpt-4-turbo'),
messages: [
{ role: 'system', content: 'You are a helpful assistant' },
{ role: 'user', content: userInput }
],
text: ({ content }) => <p>{content}</p>,
tools: {
get_city_weather: {
description: 'Get the current weather for a city',
parameters: z.object({
city: z.string().describe('the city')
}).required(),
generate: async function* ({ city }) {
yield <Spinner/>
const weather = await getWeather(city)
return <Weather info={weather} />
}
}
}
})
return result.value
}
この例では、streamUI
関数を使用して、LLMの生成の一部としてReactコンポーネントをレンダリングしています。
tools
プロパティを使用して、get_city_weather
関数を定義し、getWeather
関数を呼び出して天気情報を取得しています。
その後、<Weather />
コンポーネントを使用して天気情報をレンダリングし、ストリーミングしています。
AI SDK RSCを使用すると、LLMの生成とUIのレンダリングをサーバー上で行い、クライアントにストリーミングすることができます。
これにより、クライアント側ではストリーミングされたUIをレンダリングするだけでよくなります。
AI SDK Core
AI SDK 3.1では、これまでexperimentalだったAI SDK Coreが正式リリースされました。
AI SDK Coreは、大規模言語モデル(LLMs)を簡単にアプリケーションに統合するための統一されたAPIを提供します。
これにより、開発者はモデルプロバイダーの違いを気にすることなく、一貫した方法でLLMを利用できるようになります。
具体的には、以下のようなAPIが用意されています。
-
generateText
: テキストを生成し、ツールを呼び出す。非インタラクティブなユースケース(メールの下書き、Webページの要約など)や、ツールを使用するエージェントに最適 -
streamText
: テキストをストリーミングし、ツールを呼び出す。チャットボットやコンテンツストリーミングなどのインタラクティブなユースケースに使用可能。ツールを使用してUIコンポーネントを生成することも可能(AI SDK RSC) -
generateObject
: Zodスキーマに一致する型付きの構造化オブジェクトを生成する。情報抽出、合成データ生成、分類タスクなどに使用可能 -
streamObject
: Zodスキーマに一致する構造化オブジェクトをストリーミングする。React Server Components (RSC)と組み合わせて生成されたUIをストリーミングするために使用可能(AI SDK RSC)
これらのAPIは、OpenAI、Anthropic、Google Geminiなどの主要なモデルプロバイダーをサポートしています。
さらに、AI SDK Language Model Specificationを実装する限り、他のプロバイダーとも互換性があります。
AI SDK Language Model Specificationは、言語モデルプロバイダーが実装すべきインターフェースを定義したものです。
これにより、開発者は統一された方法でさまざまな言語モデルを利用できるようになります。
カスタムプロバイダーを実装する方法については、Vercel AI SDKのドキュメントで詳しく説明されています。
generateObject
とstreamObject
はZodのスキーマに一致するオブジェクトを生成できます。Lang ChainでいうStructured output parserに似たものです。アプリケーションでLLMを扱うときに便利です。
import { generateObject } from 'ai';
import { z } from 'zod';
const { object } = await generateObject({
model,
schema: z.object({
recipe: z.object({
name: z.string(),
ingredients: z.array(
z.object({
name: z.string(),
amount: z.string(),
}),
),
steps: z.array(z.string()),
}),
}),
prompt: 'Generate a lasagna recipe.',
});
また、内部実装を見ると、generateObject
とstreamObject
では、ユーザーが入力したプロンプト、Zodのスキーマ、PREFIX、SUFFIXを結合し、OpenAIの場合はJSON Modeをラップしていることがわかります。
まとめ
Vercel AI SDKは以下のような特徴を持っています。
- AIを活用したユーザーインターフェイスの構築に役立つツール
- Server-Sent Events (SSE)を使ったUIを簡単に実装できる
また、AI SDK 3.1で新たに追加された機能は以下の通りです。
- Generative UIがAI SDK RSCと命名され、プレーンテキストだけでなくカスタマイズしたUIをレンダリングできるようになった
- AI SDK Coreが正式リリースされ、各種LLMを統一して呼び出すためのインターフェースが提供されるようになった
Vercel AI SDKは、AIを活用したアプリケーション開発のための包括的なフレームワークを提供しています。
特にAI SDK RSCとAI SDK Coreは、LLMを使ってインタラクティブなUIを構築する上で非常に強力なツールになりそうです。
弊社の機械学習チームでは、こうしたAI/MLの最新技術を活用して、お客様に最高の旅行体験を提供することを目指しています。
旅行 x MLにご興味のある方は、ぜひ一緒に働きませんか?
登壇スライド
参考資料
令和トラベルのTech Blogです。 「あたらしい旅行を、デザインする。」をミッションに、海外旅行におけるあたらしい体験や、あたらしい社会価値の提供を目指すデジタルトラベルエージェンシーです。海外ツアー・ホテル予約アプリ「NEWT(ニュート)」を提供しています。(NEWT:newt.net/)
Discussion