Vercel AI SDK — Xây Dựng Ứng Dụng AI Streaming Với Kiến Trúc Edge-First
Hướng dẫn toàn diện về Vercel AI SDK để xây dựng ứng dụng AI production. Stream response LLM, tích hợp nhiều provider và deploy đến edge với zero config. Hỗ trợ React, Next.js và mọi framework.
- Cập nhật 2026-07-15
TL;DR #
Vercel AI SDK là thư viện mã nguồn mở để xây dựng giao diện người dùng powered AI với streaming support across tất cả framework chính. Nó cung cấp API type-safe để tích hợp LLM provider(OpenAI, Anthropic, Google), automatic response streaming, built-in UI component cho React và seamless deployment đến edge runtime. Lợi thế chính: một SDK hoạt động ở mọi nơi — Next.js App Router, Remix, SvelteKit, Nuxt hoặc bất kỳ framework nào hỗ trợ fetch.
Vercel AI SDK Là Gì? #
Vercel AI SDK là thư viện mã nguồn mở abstract hóa complexity của việc xây dựng ứng dụng AI. Về cốt lõi, nó cung cấp ba capability chính:
- Provider-agnostic API: Viết code một lần, deploy đến bất kỳ LLM provider nào
- Streaming-first architecture: Response stream token-by-token đến frontend
- Framework integration: Native support cho React, Next.js, Vue, Svelte và SolidJS
Tại Sao Edge-First Quan Trọng Cho Ứng Dụng AI #
Ứng dụng AI truyền thống theo pattern này:
User → Web Server → API Route → LLM Provider → Response
Mỗi hop thêm latency. Edge-first approach của Vercel loại bỏ middleman:
User → Edge Function → LLM Provider → Streaming Response
Edge function chạy trên Cloudflare Worker, Fastly Compute@Edge hoặc Vercel Edge Function — node phân phối địa lý cách user 100-300ms. Cho chat application, điều này có nghĩa token đầu tiên đến trong dưới 500ms.
Core Architecture #
// Provider abstraction layer
import { createOpenAI } from "@ai-sdk/openai";
import { createAnthropic } from "@ai-sdk/anthropic";
import { createGoogleGenerativeAI } from "@ai-sdk/google";
const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
// Unified API call bất kể provider
const result = await streamText({
model: openai("gpt-4o"),
messages: [{ role: "user", content: "Xin chào!" }],
system: "Bạn là trợ lý hữu ích."
});
Hàm streamText same hoạt động identically dù bạn gọi GPT-4o, Claude 3.5 Sonnet hay Gemini 1.5 Pro. Swap provider bằng cách thay đổi một dòng.
Bắt Đầu #
Bước 1: Cài Đặt Dependency #
# Tạo new Next.js project với TypeScript
npx create-next-app@latest my-ai-app --typescript --tailwind --app
cd my-ai-app
# Cài đặt AI SDK và provider package
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google
# Optional: cho structured output
npm install zod
Bước 2: Cấu Hình Chat API Đầu Tiên #
Tạo app/api/chat/route.ts:
import { streamText } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL, // Optional: cho compatible API
});
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-4o"),
messages,
system: `Bạn là trợ lý lập trình hữu ích.
Cung cấp ví dụ code khi liên quan.`,
maxTokens: 2048,
temperature: 0.7,
});
return result.toDataStreamResponse();
}
Chỉ vậy đó. Một file, 20 dòng code và bạn có fully streaming chat API.
Bước 3: Xây Dựng Frontend #
Tạo app/page.tsx:
"use client";
import { useChat } from "ai/react";
export default function Chat() {
const { messages, input, handleSubmit, isLoading } = useChat();
return (
<div className="max-w-2xl mx-auto p-4">
{/* Message list */}
<div className="space-y-4 mb-4">
{messages.map((msg) => (
<div
key={msg.id}
className={`p-3 rounded-lg ${
msg.role === "user"
? "bg-blue-100 ml-8"
: "bg-gray-100 mr-8"
}`}
>
{msg.content}
</div>
))}
</div>
{/* Input form */}
<form onSubmit={handleSubmit} className="flex gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Nhập tin nhắn..."
className="flex-1 p-2 border rounded-lg"
/>
<button
type="submit"
disabled={isLoading}
className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"
>
{isLoading ? "Đang suy nghĩ..." : "Gửi"}
</button>
</form>
</div>
);
}
Hook useChat xử lý everything: state management, streaming update, error handling và loading state.
Mẫu Nâng Cao #
Mẫu 1: Multi-Provider Routing #
Route request đến model khác nhau dựa trên task type:
import { createOpenAI } from "@ai-sdk/openai";
import { createAnthropic } from "@ai-sdk/anthropic";
import { createGoogleGenerativeAI } from "@ai-sdk/google";
import { streamText } from "ai";
const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const google = createGoogleGenerativeAI({ apiKey: process.env.GOOGLE_API_KEY });
type TaskType = "creative" | "analytical" | "code" | "summary";
const modelRouter: Record<TaskType, any> = {
creative: anthropic("claude-sonnet-4-20260514"),
analytical: openai("o3-mini"),
code: anthropic("claude-sonnet-4-20260514"),
summary: google("gemini-2.0-flash"),
};
export async function POST(req: Request) {
const { messages, taskType }: { messages: any[]; taskType: TaskType } =
await req.json();
const model = modelRouter[taskType] || modelRouter.creative;
const result = streamText({
model,
messages,
maxTokens: taskType === "code" ? 4096 : 1024,
temperature: taskType === "creative" ? 0.9 : 0.3,
});
return result.toDataStreamResponse();
}
Mẫu 2: Structured Output Với Zod #
Validate và parse LLM response thành typed object:
import { z } from "zod";
import { generateObject } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
const ArticleSchema = z.object({
title: z.string().describe("Tiêu đề bài viết"),
summary: z.string().describe("Tóm tắt một đoạn"),
tags: z.array(z.string()).describe("Tag liên quan"),
readingTime: z.number().describe("Thời gian đọc ước tính phút"),
sentiment: z.enum(["positive", "neutral", "negative"]),
});
export async function POST(req: Request) {
const { text } = await req.json();
const { object } = await generateObject({
model: openai("gpt-4o"),
schema: ArticleSchema,
prompt: `Phân tích text này và trích xuất metadata bài viết: ${text}`,
temperature: 0,
});
return Response.json(object);
}
Response được guarantee match schema — TypeScript type flow end-to-end từ schema definition đến frontend component.
Mẫu 3: RAG Pipeline Với Embedding #
Xây dựng retrieval-augmented generation trong single route:
import { embed, embedMany, streamText } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
import { cosineSimilarity } from "ai/embeddings";
const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
let documentVectors: { embedding: number[]; content: string }[] = [];
async function addDocuments(documents: string[]) {
const { embeddings } = await embedMany({
model: openai.embedding("text-embedding-3-small"),
values: documents,
});
documentVectors = documents.map((content, i) => ({
embedding: embeddings[i],
content,
}));
}
async function searchDocuments(query: string, topK: number = 3) {
const { embedding } = await embed({
model: openai.embedding("text-embedding-3-small"),
value: query,
});
const scored = documentVectors
.map((doc) => ({
...doc,
similarity: cosineSimilarity(embedding, doc.embedding),
}))
.sort((a, b) => b.similarity - a.similarity)
.slice(0, topK);
return scored.map((s) => s.content);
}
export async function POST(req: Request) {
const { messages, documents } = await req.json();
if (documents?.length) {
await addDocuments(documents);
}
const lastMessage = messages[messages.length - 1];
const context = await searchDocuments(lastMessage.content);
const result = streamText({
model: openai("gpt-4o"),
messages,
system: `Chỉ trả lời dùng context sau.
Nếu context không chứa thông tin relevant, nói vậy.
Context:
${context.join("\n\n")}
`,
});
return result.toDataStreamResponse();
}
Mẫu 4: Agent Tool Calling #
Cho LLM access đến external tool:
import { streamText, tool } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
import { z } from "zod";
const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
const result = streamText({
model: openai("gpt-4o"),
messages,
tools: {
searchWeb: tool({
description: "Tìm kiếm web cho thông tin hiện tại",
parameters: z.object({
query: z.string().describe("Từ khóa tìm kiếm"),
maxResults: z.number().default(5),
}),
execute: async ({ query, maxResults }) => {
const response = await fetch(
`https://api.search.com/v1/search?q=${encodeURIComponent(query)}&limit=${maxResults}`
);
return response.json();
},
}),
calculate: tool({
description: "Thực hiện phép tính toán học",
parameters: z.object({
expression: z.string().describe("Biểu thức toán học"),
}),
execute: async ({ expression }) => {
try {
return { result: Function(`return ${expression}`)() };
} catch (e) {
return { error: "Biểu thức không hợp lệ" };
}
},
}),
},
maxSteps: 5, // Cho phép đến 5 rounds tool-calling
});
Mỗi tool execute server-side, giữ API key secure trong khi cho LLM khả năng real-world.
UI Component #
Dùng Built-In UI Component #
SDK đi kèm React component cho common AI pattern:
npm install @ai-sdk/react
import { useChat } from "@ai-sdk/react";
export function AIChat() {
const {
messages, input, setInput, handleSubmit,
isLoading, error, stop,
} = useChat({
api: "/api/chat",
onFinish: (message) => {
console.log("Response complete:", message.content);
},
onError: (error) => {
console.error("Chat error:", error);
},
});
return (
<div className="ai-chat">
{/* Message rendering */}
<div className="space-y-2">
{messages.map((m) => (
<div key={m.id} className={`p-2 rounded ${m.role === "user" ? "bg-blue-100" : "bg-gray-100"}`}>
{m.content}
</div>
))}
</div>
<form onSubmit={handleSubmit}>
<input value={input} onChange={(e) => setInput(e.target.value)} placeholder="Hỏi bất cứ gì..." />
{isLoading && <button onClick={stop}>Dừng</button>}
{error && <div className="error">{error.message}</div>}
</form>
</div>
);
}
Triển Khai #
Deploy Lên Vercel #
# Cài đặt Vercel CLI
npm i -g vercel
# Link project
vercel link
# Set environment variable
vercel env add OPENAI_API_KEY
# Deploy
vercel deploy --prod
API route của bạn tự động deploy đến edge network Vercel. Không Docker, không Kubernetes, không configuration.
Deploy Lên Cloudflare Worker #
// app/api/chat/route.ts — hoạt động trên Cloudflare Worker nữa!
import { toEdgeAPI } from "ai";
export const config = {
runtime: "edge",
};
export async function POST(req: Request) {
const result = streamText({
model: openai("gpt-4o"),
messages: (await req.json()).messages,
});
return toEdgeAPI(result.toDataStreamResponse());
}
Deploy với wrangler deploy. Mạng global Cloudflare đảm bảo sub-100ms cold start.
Self-Hosted Với Docker #
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["npm", "start"]
Performance Benchmark #
So Sánh Độ Trễ #
| Configuration | First Token(p50) | Full Response(p95) |
|---|---|---|
| Vercel Edge + GPT-4o | 320ms | 4.2s |
| AWS Lambda + GPT-4o | 580ms | 5.8s |
| EC2 t3.large + GPT-4o | 450ms | 4.5s |
| Bare Metal + Local vLLM | 85ms | 2.1s |
Edge deployment consistently wins cho interactive application nơi first-token latency quan trọng nhất.
Chi Phí Cho 1K Request #
| Provider | Chi phí cho 1K request(100 token avg) |
|---|---|
| GPT-4o | $1.20 |
| Claude Sonnet 4 | $0.80 |
| Gemini 2.0 Flash | $0.15 |
| Llama 3.2(local) | $0.03(chỉ compute) |
Dùng multi-provider routing pattern để tự động chọn model cheapest đáp ứng quality requirement.
Xử Lý Vấn Đề #
Vấn Đề 1: Lỗi CORS Trên Development #
Access to fetch at 'http://localhost:30000/api/chat' from origin 'http://localhost:5173' blocked by CORS policy
Fix: Đảm bảo API route trả về proper CORS header:
export async function POST(req: Request) {
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
}
Vấn Đề 2: Streaming Không Hoạt Động Trong Production #
Nếu frontend hiển thị full response cùng lúc thay vì streaming:
Check 1: Verify API route trả về ReadableStream
Check 2: Đảm bảo bạn dùng toDataStreamResponse() không phải toTextStreamResponse() cho full fidelity.
Vấn Đề 3: Model Timeout Trên Edge Function #
Edge function có 60-second timeout. Cho long-running model:
const result = streamText({
model: openai("o3-mini"),
messages,
maxTokens: 4096,
timeout: 55000, // 55 giây(dưới 60s edge limit)
});
Cho operation dài hơn, offload đến queue-based pattern: submit request, poll completion, rồi stream result.
Vấn Đề 4: Lỗi Type Với Provider Model #
Argument of type '"gpt-4-turbo"' is not assignable to parameter of type...
Fix: Đảm bảo bạn dùng đúng model identifier cho provider version:
# Update lên latest AI SDK
npm update ai @ai-sdk/openai
Hướng Phát Triển Tương Lai #
Điều Gì Sắp Đến Với AI SDK 2026 #
- Native multimodal streaming: Stream image, audio và video alongside text trong single response
- Built-in evaluation harness: A/B test prompt và model trực tiếp trong SDK với automated quality metric
- Agent framework: First-class multi-agent orchestration với shared memory, handoff protocol và conflict resolution
- Cost-aware routing: Automatic model selection dựa trên cost/quality tradeoff cấu hình bởi developer
- WebGPU inference: Chạy small model trực tiếp trong browser dùng WebGPU API cho zero-latency interaction
Khi Nào Chọn Vercel AI SDK #
Chọn AI SDK khi:
- Bạn muốn rapid prototyping với minimal boilerplate
- App bạn cần streaming response
- Bạn plan hỗ trợ multiple LLM provider
- Bạn đang dùng React, Next.js hoặc modern frontend framework khác
- Bạn muốn edge deployment với zero infrastructure management
Xem xét alternative khi:
- Bạn chỉ cần on-premises deployment — LangChain hoặc LlamaIndex offer more flexibility
- Bạn xây dựng non-React application không có TypeScript — SDK shines brightest trong TS/React
- Bạn cần custom inference serving — vLLM hoặc TGI cho self-hosted GPU cluster
Cập Nhật Cộng Đồng #
Ecosystem AI SDK đã mature significantly:
- Provider coverage: 15+ official provider integration bao gồm OpenAI, Anthropic, Google, AWS Bedrock, Cohere, Mistral, Groq và Ollama
- Community package: 200+ community-contributed tool, utility và integration
- Framework support: Official adapter cho Next.js, Remix, SvelteKit, Nuxt, Astro và Qwik
- Enterprise adoption: Dùng bởi company như Stripe, Shopify và Notion cho production AI feature
GitHub repository của SDK đã phát triển lên hơn 30,000 star và npm weekly download vượt 5 triệu — làm nó most popular AI development SDK trong JavaScript ecosystem.
FAQ #
Q: Tôi có thể dùng Vercel AI SDK không có Next.js không? #
Có. Mặc dù SDK tích hợp beautifully với Next.js, nó hoạt động với mọi framework hỗ trợ Fetch API. Remix, SvelteKit, Nuxt, Astro, Express, Fastify và thậm chí vanilla Node.js đều hoạt động. Package ai framework-agnostic — chỉ React hook(@ai-sdk/react) yêu cầu React.
Q: Streaming hoạt động thế nào bên dưới hood? #
SDK dùng Server-Sent Event(SSE) qua ReadableStream. Khi bạn gọi streamText(), nó tạo streaming connection đến LLM provider. Mỗi token được gửi sebagai SSE event đến client, nơi useChat hook parse nó và update UI incrementally. Đây là cái cho phép “typing” effect trong AI chat interface.
Q: Tôi có thể cache LLM response để giảm chi phí không? #
Có. Implement caching ở API route level:
const cachedChat = cache(async (messages: any[]) => {
const hash = JSON.stringify(messages);
const cached = await redis.get(hash);
if (cached) return JSON.parse(cached);
const result = await streamText({ model: openai("gpt-4o"), messages });
await redis.setex(hash, 3600, JSON.stringify(result));
return result;
});
Cache identical conversation cho hours hoặc days, tiết kiệm 50-80% API cost cho repetitive query.
Q: SDK có free và open source không? #
Có. AI SDK là MIT-licensed và hoàn toàn free. Bạn chỉ pay cho underlying LLM provider API call. Không có subscription fee, không usage cap và không hidden cost.
Q: Làm sao tôi xử lý authentication cho ứng dụng AI? #
Dùng middleware để protect API route:
export function middleware(request: NextRequest) {
const token = request.cookies.get("auth-token");
if (!token && request.nextUrl.pathname.startsWith("/api/chat")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
Cho production app, combine JWT authentication với rate limiting để prevent abuse.
Nguồn Tham Khảo #
- Tài Liệu Vercel AI SDK
- AI SDK GitHub Repository
- Xây Dựng Streaming AI App — Vercel Blog 2026
- Edge Computing Cho AI — Cloudflare Research 2026
- AI SDK Provider Comparison Matrix
Tham gia Telegram Group của chúng tôi để thảo luận AI tool real-time và tips deploy: t.me/dibi8
💬 Bình luận & Thảo luận