Các ứng dụng tương tác với mô hình ngôn ngữ lớn (LLM) như ChatGPT hay Claude đã định nghĩa lại kỳ vọng của người dùng về giao diện phần mềm. Người dùng không còn chấp nhận ngồi chờ 5-10 giây để nhận một khối văn bản tĩnh. Họ mong muốn thấy câu trả lời xuất hiện tức thì theo dạng **Streaming Token** và các thành phần giao diện tương tác động (**Generative UI**) xuất hiện ngay khi AI đưa ra đề xuất.
Với **Vercel AI SDK** và kiến trúc Next.js App Router, việc tích hợp các tính năng AI này trở nên vô cùng mạch lạc và dễ dàng.
1. Sự khác biệt giữa Plain Streaming và Generative UI
Có hai cấp độ khi tích hợp AI vào giao diện người dùng:
1. Streaming Text (Level 1): LLM gửi về từng ký tự/từ qua Server-Sent Events (SSE). UI hiển thị hiệu ứng gõ chữ mượt mà.
2. Generative UI & Tool Calling (Level 2): Khi AI nhận diện yêu cầu xem thời tiết, đặt vé hay so sánh sản phẩm, AI sẽ gọi hàm (Tool Calling) và server trả về trực tiếp một React Component tương tác (thẻ Card, Biểu đồ, Form chọn ngày) thay vì chỉ là văn bản thô.
2. Tạo API Endpoint Streaming với Vercel AI SDK
Tạo Route Handler tại app/api/chat/route.ts kết nối với OpenAI hoặc Anthropic Claude:
import { openai } from "@ai-sdk/openai";
import { streamText } from "ai";
export const runtime = "edge";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-4o-mini"),
system: "Bạn là trợ lý AI thông minh cho portfolio của Nguyễn Duy Noa.",
messages,
});
return result.toDataStreamResponse();
}3. Xây dựng giao diện Chat phía Client với hook useChat
Phía client sử dụng hook useChat để tự động xử lý kết nối stream, trạng thái loading và danh sách tin nhắn:
"use client";
import { useChat } from "ai/react";
import { PaperPlaneTilt } from "@phosphor-icons/react";
export function AIChatAssistant() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
return (
<div className="flex flex-col h-[500px] w-full max-w-lg bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden">
{/* Messages list */}
<div className="flex-1 overflow-y-auto p-4 space-y-3">
{messages.map((m) => (
<div
key={m.id}
className={`p-3 rounded-xl text-sm max-w-[85%] ${
m.role === "user"
? "ml-auto bg-emerald-500 text-black font-medium"
: "bg-zinc-800 text-zinc-200"
}`}
>
{m.content}
</div>
))}
{isLoading && <div className="text-xs text-zinc-500 italic">AI đang phản hồi...</div>}
</div>
{/* Input box */}
<form onSubmit={handleSubmit} className="p-3 border-t border-zinc-800 flex gap-2">
<input
value={input}
onChange={handleInputChange}
placeholder="Hỏi bất kỳ điều gì..."
className="flex-1 bg-zinc-950 border border-zinc-800 rounded-xl px-4 py-2 text-sm text-zinc-100 focus:outline-none focus:border-emerald-500"
/>
<button
type="submit"
className="p-2.5 bg-emerald-500 text-black rounded-xl hover:bg-emerald-400 transition-colors"
>
<PaperPlaneTilt size={18} weight="bold" />
</button>
</form>
</div>
);
}Facing similar challenges?
I can help you optimize your website — reach out for a free consultation.
Kết luận
Kỹ năng tích hợp AI vào giao diện người dùng đang nhanh chóng trở thành một năng lực phân hóa quan trọng giữa lập trình viên Frontend trung bình và lập trình viên cao cấp. Hãy bắt đầu đưa các yếu tố thông minh này vào sản phẩm của bạn ngay hôm nay.
Want to discuss further?
If you have specific questions about web performance, React, or want to collaborate on a project — reach out directly.