useChat フックは、チャットボットアプリケーション用の会話型ユーザーインターフェイスの作成を簡単にします。AI プロバイダーからのチャットメッセージのストリーミングを可能にし、チャット状態を管理し、新しいメッセージを受け取ると同時に UI を自動的に更新します。
Vercel AI SDK 6 : AI SDK UI – チャットボット
作成 : Masashi Okumura (@classcat.com)
作成日時 : 02/09/2026
バージョン : ai@6.0.77
* 本記事は ai-sdk.dev/docs の以下のページを参考にしています :
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

Vercel AI SDK 6.x : AI SDK UI – チャットボット
useChat フックは、チャットボットアプリケーション用の会話型ユーザーインターフェイスの作成を簡単にします。AI プロバイダーからのチャットメッセージのストリーミングを可能にし、チャット状態を管理し、新しいメッセージを受け取ると同時に UI を自動的に更新します。
要約すると、useChat フックは以下の機能を提供します :
- メッセージ・ストリーミング : AI プロバイダーからのすべてのメッセージはチャット UI にリアルタイムでストリーミングされます。
- 状態管理 : フックは、入力、メッセージ、ステータス、エラー等の状態を管理します。
- シームレスな統合 : チャット AI を任意のデザインやレイアウトに、最小限の労力で簡単に統合できます。
このガイドでは、useChat フックを使用して、リアルタイムのメッセージストリーミングを備えたチャットアプリケーションを作成する方法を学習します。チャットボットでツールを使用する方法を学習するには chatbot with tools ガイドを確認してください。まずは次のサンプルから始めましょう。
サンプル
app/page.tsx
'use client';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import { useState } from 'react';
export default function Page() {
const { messages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({
api: '/api/chat',
}),
});
const [input, setInput] = useState('');
return (
<>
{messages.map(message => (
<div key={message.id}>
{message.role === 'user' ? 'User: ' : 'AI: '}
{message.parts.map((part, index) =>
part.type === 'text' ? <span key={index}>{part.text}</span> : null,
)}
</div>
))}
<form
onSubmit={e => {
e.preventDefault();
if (input.trim()) {
sendMessage({ text: input });
setInput('');
}
}}
>
<input
value={input}
onChange={e => setInput(e.target.value)}
disabled={status !== 'ready'}
placeholder="Say something..."
/>
<button type="submit" disabled={status !== 'ready'}>
Submit
</button>
</form>
</>
);
}
Provider app/api/chat/route.ts
import { convertToModelMessages, streamText, UIMessage } from 'ai';
import { openai } from "@ai-sdk/openai";
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: openai("gpt-4o-mini"),
system: 'You are a helpful assistant.',
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
ℹ️ UI メッセージは、メッセージ部分を含む新しい parts プロパティを持ちます。contents プロパティではなく、parts プロパティを使用してメッセージをレンダリングすることを勧めます。parts プロパティは、テキスト、ツール呼び出し、ツールの結果を含む、様々なメッセージ型をサポートし、より柔軟で複雑なチャット UI を可能にします。
Page コンポーネントでは、ユーザが sendMessage を使用してメッセージを送信するたびに、useChat フックは AI プロバイダーのエンドポイントにリクエストします。メッセージはリアルタイムにストリーミングとして返され、チャット UI に表示されます。
これは、ユーザは AI レスポンス全体が受信されるのを待つ必要なく、利用可能になり次第、確認できるようなシームレスなチャットエクスペリエンスを可能にします。
カスタマイズされた UI
useChat はまた、コードを通してチャットメッセージの状態を管理し、ステータスを表示し、ユーザインタラクションによるトリガーなしにメッセージを更新する方法も提供します。
ステータス
useChat フックは status を返します。以下の可能な値があります :
- submitted: メッセージは API に送信され、応答ストリームの開始を待機しています。
- streaming: レスポンスは API からアクティブにストリーミングされていて、データのチャンクを受信しています。
- ready: 完全なレスポンスが受信され、処理されました; 新しいユーザメッセージを送信できます。
- error: API リクエスト中にエラーが発生し、正常な補完を妨げました。
status を例えば、以下の目的で使用できます :
- チャットボットがユーザのメッセージを処理している間、ローディングスピナーを表示する。
- 現在のメッセージを中止するための “Stop” ボタンを表示する。
- 送信 (submit) ボタンを無効にする。
app/page.tsx
'use client';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import { useState } from 'react';
export default function Page() {
const { messages, sendMessage, status, stop } = useChat({
transport: new DefaultChatTransport({
api: '/api/chat',
}),
});
const [input, setInput] = useState('');
return (
<>
{messages.map(message => (
<div key={message.id}>
{message.role === 'user' ? 'User: ' : 'AI: '}
{message.parts.map((part, index) =>
part.type === 'text' ? {part.text} : null,
)}
</div>
))}
{(status === 'submitted' || status === 'streaming') && (
<div>
{status === 'submitted' && }
<button type="button" onClick={() => stop()}>
Stop
</button>
</div>
)}
<form
onSubmit={e => {
e.preventDefault();
if (input.trim()) {
sendMessage({ text: input });
setInput('');
}
}}
>
<input
value={input}
onChange={e => setInput(e.target.value)}
disabled={status !== 'ready'}
placeholder="Say something..."
/>
<button type="submit" disabled={status !== 'ready'}>
Submit
</button>
</form>
</>
);
}
メッセージの変更
幾つかの既存のメッセージを直接変更したい場合があります。例えば、各メッセージに削除ボタンを追加して、ユーザがチャット履歴からそれらを削除することを可能にします。
setMessages 関数はこれらのタスクを実現するのに役立ちます :
const { messages, setMessages } = useChat()
const handleDelete = (id) => {
setMessages(messages.filter(message => message.id !== id))
}
return <>
{messages.map(message => (
<div key={message.id}>
{message.role === 'user' ? 'User: ' : 'AI: '}
{message.parts.map((part, index) => (
part.type === 'text' ? (
<span key={index}>{part.text}</span>
) : null
))}
<button onClick={() => handleDelete(message.id)}>Delete</button>
</div>
))}
...
You can think of messages and setMessages as a pair of state and setState in React.
キャンセルと再生成
AI プロバイダーから応答メッセージがストリーミングされている最中に、それを中止することも一般的なユースケースです。useChat フックから返される stop 関数を呼び出すことでこれを実現できます。
const { stop, status } = useChat()
return <>
<button onClick={stop} disabled={!(status === 'streaming' || status === 'submitted')}>Stop</button>
...
ユーザが “Stop” ボタンをクリックすると、fetch (取得) リクエストが中止されます。これにより不要なリソースの消費を回避し、チャットボット・アプリケーションの UX を改良できます。
同様に、useChat フックにより返される regenerate 関数を呼び出して、AI プロバイダーに最後のメッセージの再処理をリクエストすることもできます :
const { regenerate, status } = useChat();
return (
<>
<button
onClick={regenerate}
disabled={!(status === 'ready' || status === 'error')}
>
Regenerate
</button>
...
</>
);
ユーザが “Regenerate” ボタンをクリックすると、AI プロバイダーは最後のメッセージを再生成して、それに応じて現在のものを置き換えます。
UI 更新のスロットル
ℹ️ This feature is currently only available for React.
デフォルトでは、useChat フックは、新しいチャンクを受信するたびにレンダリングをトリガーします。experimental_throttle オプションを使用して、UI の更新を調整 (throttle) できます。
page.tsx
const { messages, ... } = useChat({
// Throttle the messages and data updates to 50ms:
experimental_throttle: 50
})
イベント・コールバック
useChat は、チャットボットのライフサイクルの様々なステージを処理するために使用できる、オプションのイベントコールバックを提供しています :
- onFinish: アシスタントのレスポンスが完了したときに呼び出されます。このイベントは、応答メッセージ、すべてのメッセージ、そして中止 (abort)、切断 (disconnect) とエラーのフラグも含みます。
- onError: 取得リクエスト中にエラーが発生したときに呼び出されます。
- onData: データ部 (data part) が受信されるたびに呼び出されます。
これらのコールバックは、ログ記録、分析、カスタム UI の更新のような追加のアクションをトリガーするために使用できます。
import { UIMessage } from 'ai';
const {
/* ... */
} = useChat({
onFinish: ({ message, messages, isAbort, isDisconnect, isError }) => {
// use information to e.g. update other UI states
},
onError: error => {
console.error('An error occurred:', error);
},
onData: data => {
console.log('Received data part from server:', data);
},
});
onData コールバックでエラーを投げることで、処理を中止できることに注目してください。これは onError コールバックのトリガーとなり、メッセージがチャット UI に追加されることを停止します。これは、AI プロバイダーからの予期せぬレスポンスを処理する際に役立ちます。
以上