このクイックスタート・チュートリアルでは、Expo を使用したストリーミング・チャットインターフェイスを備えた単純なエージェントを構築します。その過程で、独自プロジェクトで SDK を利用するための基礎となる主要コンセプトとテクニックを学習します。
Vercel AI SDK 6.x : Getting Started – Expo クイックスタート
作成 : Masashi Okumura (@classcat.com)
作成日時 : 01/12/2026
バージョン : ai@6.0.27
* 本記事は ai-sdk.dev/docs の以下のページを参考にしています :
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

Vercel AI SDK 6.x : Getting Started – Expo クイックスタート
このクイックスタート・チュートリアルでは、Expo を使用したストリーミング・チャットインターフェイスを備えた単純なエージェントを構築します。その過程で、独自プロジェクトで SDK を利用するための基礎となる主要コンセプトとテクニックを学習します。
前提条件
このクイックスタートに従うには、以下が必要です :
- Node.js 18+ と pnpm がローカル開発マシンにインストールされていること
- Vercel AI Gateway API キー
アプリケーションの作成
まず、新しい Expo アプリケーションを作成します。このコマンドは my-ai-app という名前の新しいディレクトリを作成し、その中に基本的な Expo アプリケーションをセットアップします。
pnpm create expo-app@latest my-ai-app
新たに作成されたディレクトリに移動します :
cd my-ai-app
ℹ️ This guide requires Expo 52 or higher.
依存関係のインストール
ai と @ai-sdk/react をインストールします、AI パッケージと AI SDK の React フックです。AI SDK の Vercel AI Gateway プロバイダーは ai パッケージでリリースされています。zod のインストールも必要です、ツール入力を定義するために使用されるスキーマ検証ライブラリです。
pnpm add ai @ai-sdk/react zod
Vercel AI Gateway API キーの設定
プロジェクトルートに .env.local ファイルを作成して Vercel AI Gateway API キーを追加します。このキーは、Vercel AI Gateway を使用するアプリケーションを認証します。
touch .env
Edit the .env.local file:
AI_GATEWAY_API_KEY=xxxxxxxxx
xxxxxxxxx を実際の Vercel AI Gateway API キーで置き換えます。
API Route の作成
route ハンドラ, app/api/chat+api.ts を作成して、以下のコードを追加します :
Gateway app/api/chat+api.ts
import { streamText, UIMessage, convertToModelMessages } from 'ai';
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: "openai/gpt-4o-mini",
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse({
headers: {
'Content-Type': 'application/octet-stream',
'Content-Encoding': 'none',
},
});
}
このコードで何が起きているか見てみましょう :
- 非同期 POST リクエストハンドラを定義してリクエストの body から messages を抽出します。messages 変数はユーザとチャットボット間の会話履歴を含み、チャットボットが次の生成を行うために必要なコンテキストを提供します。
- streamText を呼び出します、これは ai パッケージからインポートされています。この関数は、(ai からインポートされた) model プロバイダーと (ステップ 1 で定義された) messages を含む、configuration オブジェクトを受け取ります。モデルの動作を更にカスタマイズするために追加の 設定 を渡すこともできます。
- streamText 関数は StreamTextResult を返します。この結果オブジェクトは、結果をストリーミングされたレスポンス・オブジェクトに変換する toUIMessageStreamResponse 関数を含みます。
- 最後に、結果をクライアントに返してレスポンスをストリーミングします。
この API route は /api/chat に POST リクエスト・エンドポイントを作成します。
Wire up the UI
LLM にクエリーできる route を実装したので、次にフロントエンドをセットアップします。AI SDK の UI パッケージはチャットインターフェイスの複雑さを一つのフック、useChat に抽象化しています。
チャットメッセージのリストを表示してユーザメッセージの入力を提供するには、ルートページ (app/(tabs)/index.tsx) を以下のコードで更新します :
app/(tabs)/index.tsx
import { generateAPIUrl } from '@/utils';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import { fetch as expoFetch } from 'expo/fetch';
import { useState } from 'react';
import { View, TextInput, ScrollView, Text, SafeAreaView } from 'react-native';
export default function App() {
const [input, setInput] = useState('');
const { messages, error, sendMessage } = useChat({
transport: new DefaultChatTransport({
fetch: expoFetch as unknown as typeof globalThis.fetch,
api: generateAPIUrl('/api/chat'),
}),
onError: error => console.error(error, 'ERROR'),
});
if (error) return {error.message} ;
return (
<SafeAreaView style={{ height: '100%' }}>
<View
style={{
height: '95%',
display: 'flex',
flexDirection: 'column',
paddingHorizontal: 8,
}}
>
<ScrollView style={{ flex: 1 }}>
{messages.map(m => (
<View key={m.id} style={{ marginVertical: 8 }}>
<View>
<Text style={{ fontWeight: 700 }}>{m.role}</Text>
{m.parts.map((part, i) => {
switch (part.type) {
case 'text':
return <Text key={`${m.id}-${i}`}>{part.text}</Text>;
}
})}
</View>
</View>
))}
</ScrollView>
<View style={{ marginTop: 8 }}>
<TextInput
style={{ backgroundColor: 'white', padding: 8 }}
placeholder="Say something..."
value={input}
onChange={e => setInput(e.nativeEvent.text)}
onSubmitEditing={e => {
e.preventDefault();
sendMessage({ text: input });
setInput('');
}}
autoFocus={true}
/>
</View>
</View>
</SafeAreaView>
);
このページは useChat フックを利用します、これはデフォルトでは先に作成した POST API route (/api/chat) を使用します。このフックは、ユーザ入力とフォーム送信を処理する関数と状態を提供します。useChat フックは複数のユティリティ関数と状態変数を提供します :
- messages – 現在のチャットメッセージ (id, role と parts プロパティを持つオブジェクトの配列)。
- sendMessage – メッセージを chat API に送信する関数。
このコンポーネントはローカル状態 (useState) を使用して入力フィールド値を管理し、入力テキストを引数に sendMessage を呼び出し、入力フィールドをクリアすることでフォーム送信を処理します。
LLM のレスポンスはメッセージ parts 配列を通してアクセスできます。各メッセージは、モデルがレスポンスで生成したすべてを表す parts の順序付けられた配列を含みます。これらのパーツは、後でみるような plain テキスト、推論トークン等を含むことができます。parts 配列はモデルの出力のシークエンスを保持し、生成された順序で各コンポーネントを表示または処理することを可能にします。
API URL ジェネレータの作成
ストリーミング・レスポンスにネイティブの fetch 関数ではなく expo/fetch を使用していますので、クライアント環境 (e.g. web or モバイル) に応じて適切なベース url を使用することを確実にするため、API URL ジェネレータが必要です。プロジェクトのルートに utils.ts という新しいファイルを作成して以下のコードを追加します :
utils.ts
import Constants from 'expo-constants';
export const generateAPIUrl = (relativePath: string) => {
const origin = Constants.experienceUrl.replace('exp://', 'http://');
const path = relativePath.startsWith('/') ? relativePath : `/${relativePath}`;
if (process.env.NODE_ENV === 'development') {
return origin.concat(path);
}
if (!process.env.EXPO_PUBLIC_API_BASE_URL) {
throw new Error(
'EXPO_PUBLIC_API_BASE_URL environment variable is not defined',
);
}
return process.env.EXPO_PUBLIC_API_BASE_URL.concat(path);
};
このユティリティ関数は、開発環境と本番環境の両方の URL 生成を処理し、様々なデバイスと構成にわたり API 呼び出しが正しく機能することを保証します。
ℹ️ Before deploying to production, you must set the EXPO_PUBLIC_API_BASE_URL environment variable in your production environment. This variable should point to the base URL of your API server.
アプリケーションの実行
これで、チャットボットに必要なものすべてを構築しました!アプリケーションを起動するには、次のコマンドを使用します :
pnpm expo
ブラウザで http://localhost:8081 を開いてください。入力フィールドを見るはずです。メッセージを入力してテストすると、AI チャットボットがリアルタイムに応答するのを確認できます。AI SDK は、Expo で AI チャットインターフェイスを素早く簡単に構築できます。
以上