🤖

Vercel AI SDK 触ってみた

2024/05/29に公開

はじめに

こんにちは。令和トラベルでフロントエンドエンジニアをしている @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つの主要な機能で構成されています。

  1. AI SDK Core: テキスト生成、構造化オブジェクト生成、ツール呼び出しのための統一されたAPI
  2. AI SDK UI: チャットインターフェースを素早く構築するためのフレームワークに依存しないフック
  3. 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());
}

このコードでは、以下のことを行っています。

  1. リクエストのボディからmessagesを抽出します。
  2. streamText関数を呼び出し、モデルプロバイダ(openai)とメッセージを渡します。
  3. streamText関数から返されたStreamTextResultオブジェクトからtoAIStream関数を使ってストリームを変換します。
  4. 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 - ユーザー入力フィールドの現在の値
  • handleInputChangehandleSubmit - ユーザーの操作(入力フィールドへの入力とフォームの送信)を処理する関数
  • 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のドキュメントで詳しく説明されています。

generateObjectstreamObjectは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.',
});

また、内部実装を見ると、generateObjectstreamObjectでは、ユーザーが入力したプロンプト、Zodのスキーマ、PREFIX、SUFFIXを結合し、OpenAIの場合はJSON Modeをラップしていることがわかります。

https://github.com/vercel/ai/blob/40d8d753f724f141f51cb7f17b2ba0ff5b4600b4/packages/core/core/generate-object/generate-object.ts#L90-L110

https://github.com/vercel/ai/blob/40d8d753f724f141f51cb7f17b2ba0ff5b4600b4/packages/core/core/generate-object/inject-json-schema-into-system.ts

まとめ

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にご興味のある方は、ぜひ一緒に働きませんか?

登壇スライド

参考資料

https://sdk.vercel.ai/
https://vercel.com/blog/category/engineering

令和トラベル Tech Blog

Discussion