Build AI Chatbot Với Next.js: Từ Hello World Đến Streaming Response Như ChatGPT
Chatbot AI không còn là magic. Tutorial này hướng dẫn build chatbot thực sự với streaming responses, conversation history, và system prompt tùy chỉnh — dùng Next.js và OpenAI SDK.
Build AI Chatbot Với Next.js: Từ Hello World Đến Streaming Response Như ChatGPT
Điều làm ChatGPT cảm giác "sống" là streaming — chữ xuất hiện dần dần thay vì chờ toàn bộ response rồi mới hiện. Tutorial này build chatbot với streaming hoàn chỉnh, conversation history, và system prompt tùy chỉnh.
📌 TL;DR: Kết Quả Cuối Bài
- Chatbot với giao diện chat đẹp (dark theme)
- Streaming response — chữ hiện dần như ChatGPT
- Conversation history — AI nhớ context trong session
- System prompt tùy chỉnh — định nghĩa tính cách AI
- Tech: Next.js 14 + Vercel AI SDK + OpenAI GPT-4o
Setup
npx create-next-app@latest ai-chatbot --typescript --tailwind --app
cd ai-chatbot
# Vercel AI SDK — wrapper tiện lợi cho streaming
npm install ai @ai-sdk/openai
File .env.local:
OPENAI_API_KEY=sk-proj-your-key-here
API Route Với Streaming
Tạo file app/api/chat/route.ts:
import { openai } from '@ai-sdk/openai'
import { streamText } from 'ai'
import { NextRequest } from 'next/server'
// System prompt định nghĩa tính cách chatbot
const SYSTEM_PROMPT = `Bạn là AI Builder Hub Assistant — trợ lý thông minh giúp người dùng học và ứng dụng AI.
Phong cách:
- Thân thiện, rõ ràng, thực tế
- Ưu tiên ví dụ cụ thể hơn lý thuyết dài dòng
- Khi không biết, nói thẳng "tôi không chắc về điều này"
- Ngôn ngữ: tiếng Việt là mặc định, trả lời cùng ngôn ngữ với user
Không được:
- Giả mạo thông tin
- Nói những câu generic như "AI đang thay đổi thế giới"
- Trả lời quá dài khi câu hỏi đơn giản`
export async function POST(request: NextRequest) {
const { messages } = await request.json()
// streamText từ Vercel AI SDK xử lý streaming tự động
const result = await streamText({
model: openai('gpt-4o'),
system: SYSTEM_PROMPT,
messages,
maxTokens: 1000
})
// Trả về streaming response
return result.toDataStreamResponse()
}
Giao Diện Chat
Tạo app/page.tsx:
'use client'
import { useChat } from 'ai/react'
import { useEffect, useRef } from 'react'
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
api: '/api/chat'
})
const messagesEndRef = useRef<HTMLDivElement>(null)
// Auto-scroll xuống cuối khi có message mới
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}, [messages])
return (
<div className="flex flex-col h-screen bg-gray-950 text-white">
{/* Header */}
<header className="border-b border-gray-800 px-6 py-4 flex items-center gap-3">
<div className="w-8 h-8 rounded-full bg-gradient-to-r from-blue-500 to-cyan-500 flex items-center justify-center">
🤖
</div>
<div>
<h1 className="font-semibold">AI Builder Hub Assistant</h1>
<p className="text-sm text-gray-400">GPT-4o · Streaming enabled</p>
</div>
</header>
{/* Messages */}
<div className="flex-1 overflow-y-auto px-4 py-6">
{messages.length === 0 && (
<div className="text-center text-gray-500 mt-20">
<p className="text-4xl mb-4">💬</p>
<p className="text-lg">Hỏi tôi bất cứ điều gì về AI...</p>
<div className="mt-6 flex flex-wrap gap-2 justify-center">
{['ChatGPT vs Claude', 'Bắt đầu với AI', 'Build AI App', 'Prompt hay'].map(s => (
<button
key={s}
onClick={() => {
handleInputChange({ target: { value: s } } as React.ChangeEvent<HTMLInputElement>)
}}
className="text-sm px-4 py-2 bg-gray-800 hover:bg-gray-700 rounded-full transition-colors"
>
{s}
</button>
))}
</div>
</div>
)}
<div className="max-w-3xl mx-auto space-y-6">
{messages.map((message) => (
<div
key={message.id}
className={`flex gap-4 ${message.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`}
>
{/* Avatar */}
<div className={`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 text-sm ${
message.role === 'user'
? 'bg-blue-600'
: 'bg-gradient-to-r from-blue-500 to-cyan-500'
}`}>
{message.role === 'user' ? '👤' : '🤖'}
</div>
{/* Bubble */}
<div className={`max-w-[80%] rounded-2xl px-4 py-3 ${
message.role === 'user'
? 'bg-blue-600 text-white'
: 'bg-gray-900 border border-gray-800 text-gray-100'
}`}>
<p className="whitespace-pre-wrap leading-relaxed">{message.content}</p>
</div>
</div>
))}
{/* Loading indicator */}
{isLoading && (
<div className="flex gap-4">
<div className="w-8 h-8 rounded-full bg-gradient-to-r from-blue-500 to-cyan-500 flex items-center justify-center text-sm">
🤖
</div>
<div className="bg-gray-900 border border-gray-800 rounded-2xl px-4 py-3">
<span className="text-gray-400 animate-pulse">Đang trả lời...</span>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
</div>
{/* Input */}
<div className="border-t border-gray-800 p-4">
<form onSubmit={handleSubmit} className="max-w-3xl mx-auto flex gap-3">
<input
value={input}
onChange={handleInputChange}
placeholder="Nhập câu hỏi... (Enter để gửi)"
className="flex-1 bg-gray-900 border border-gray-700 rounded-xl px-4 py-3 focus:outline-none focus:border-blue-500 transition-colors"
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading || !input.trim()}
className="px-6 py-3 bg-gradient-to-r from-blue-500 to-cyan-500 rounded-xl font-medium disabled:opacity-50 disabled:cursor-not-allowed hover:from-blue-600 hover:to-cyan-600 transition-all"
>
{isLoading ? '⟳' : '→'}
</button>
</form>
<p className="text-center text-xs text-gray-600 mt-2">
AI có thể mắc lỗi — luôn verify thông tin quan trọng
</p>
</div>
</div>
)
}
Chạy Và Test
npm run dev
Mở http://localhost:3000 và bắt đầu chat. Bạn sẽ thấy response streaming real-time.
Hiểu Cách Streaming Hoạt Động
User gửi message
↓
API Route: streamText() gọi OpenAI
↓
OpenAI trả về tokens TỪNG CÁI MỘT
↓
toDataStreamResponse() stream tokens về browser
↓
useChat() hook nhận từng token, update UI real-time
↓
User thấy chữ xuất hiện dần dần
Tại sao streaming quan trọng: Response thông thường chờ AI generate xong rồi mới show (5-15 giây). Streaming show từng từ ngay khi AI generate — cảm giác responsive hơn nhiều dù tổng thời gian như nhau.
Mở Rộng Tiếp
Lưu conversation history: Dùng localStorage hoặc database để giữ lịch sử giữa các sessions
Nhiều chatbot với system prompts khác nhau: Customer support bot, coding assistant, writing coach
Thêm file upload: Cho phép attach PDF để AI trả lời về file đó
Rate limiting: Tránh bị abuse nếu deploy public
Đọc thêm:
- Build AI app đầu tiên (simpler): Your First AI App
- AI API fundamentals: AI API Guide
- Scale với RAG knowledge base: RAG Guide
- Dùng Cursor AI để code nhanh hơn: Cursor AI Review