AIチャットボット
ルール
- Vercel AI SDK(
ai パッケージ)をストリーミングに使用 — クライアントは useChat() フック、サーバーは streamText()
- レスポンスは
text/event-stream でストリーム — 送信前に完全なレスポンスをバッファリングしない
- メッセージ形式:
{ role: "user" | "assistant" | "system", content: string }
- コンテキストウィンドウ管理: トークン制限に近づいたら最も古いメッセージをトリミングし、常にシステムプロンプトを保持
- RAGパターン: ユーザークエリを埋め込み → ベクター検索 → 上位k件の結果をユーザーメッセージの前にコンテキストとして注入
- チャットUI: 自動スクロールで最下部へ、アニメーションするドットで読み込みインジケータ、アシスタントメッセージはマークダウンをレンダリング
- 会話履歴はサーバーサイドで永続化 —
chatId、role、content、createdAt を持つ messages テーブルを使用
- システムプロンプトはmessages配列の先頭 — ユーザーメッセージで上書きさせない
- YepAPIチャットエンドポイント:
POST /v1/ai/chat、{ messages, model?, stream? } を送信
- 生成停止ボタン —
AbortController を使用して進行中のストリームをキャンセル
パターン
const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat({
api: "/api/chat",
});
import { streamText } from "ai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({ model, messages });
return result.toDataStreamResponse();
}
避けるべきこと
- トリミングせずに会話履歴全体を送信 — コンテキストウィンドウを超過します
- 完全なレスポンスを待つ間UIをブロック — 常にストリーミング
- メッセージをクライアント状態のみに保存 — 履歴のためにサーバーサイドで永続化
- モデル名をハードコーディング — 環境変数または設定を使用