· ai-tools / vercel-ai-sdk / typescript
Cách dùng Vercel AI SDK — streaming, tool call, và agent
AI SDK 6 cung cấp một API thống nhất cho 20+ provider, typed streaming, và ToolLoopAgent cho các vòng lặp agent nhiều bước. Đây là cách dùng.
Bởi Ethan
1.416 từ · 8 phút đọc
Vercel AI SDK là con đường nhanh nhất để đưa một tính năng AI streaming vào TypeScript. SDK này thống nhất 20+ model provider sau một API duy nhất, thay thế việc tự xử lý SSE bằng một lệnh streamText, và mang lại type safety từ đầu đến cuối qua tool call và agent loop. Dùng nó trừ khi bạn chỉ deploy trên một provider duy nhất và muốn bundle nhỏ nhất có thể.
Dành cho ai
Các developer TypeScript đang thêm AI vào Node.js script hoặc Next.js app, và không muốn tự viết code xử lý streaming hay tool call. Nếu bạn cần tính năng mới nhất từ một provider cụ thể ngay khi họ vừa ra mắt, hãy dùng native SDK của provider đó.
Cài đặt Vercel AI SDK
Package cốt lõi là ai. Thêm provider riêng biệt.
Node.js:
mkdir my-ai-app && cd my-ai-app
pnpm init
pnpm add ai zod dotenv
pnpm add -D @types/node tsx typescript
Next.js App Router:
pnpm create next-app@latest my-ai-app
cd my-ai-app
pnpm add ai @ai-sdk/react zod
Package provider là các install riêng — ví dụ @ai-sdk/anthropic, @ai-sdk/openai, hoặc @ai-sdk/google. Cách này giúp bundle gọn nhẹ: bạn chỉ ship provider mà bạn thực sự dùng.
Đặt API key vào .env:
ANTHROPIC_API_KEY=sk-ant-...
Nếu bạn dùng Cursor làm editor, AI completions sẽ hoạt động ngay trong route handler và tool schema khi bạn gõ — khá tiện khi mới làm quen với type signature của AI SDK.
Streaming text
Node.js
import { streamText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
const result = streamText({
model: anthropic('claude-sonnet-4-5'),
prompt: 'Explain async/await in 3 sentences.',
});
for await (const textPart of result.textStream) {
process.stdout.write(textPart);
}
streamText trả về result object ngay lập tức. Text thực sự đến trên result.textStream dưới dạng async iterable. Không callback, không tự quản lý buffer.
Lỗi thường gặp: nếu ANTHROPIC_API_KEY chưa được set, lệnh gọi sẽ throw lúc runtime — không phải lúc import. Set env var trước khi chạy.
Next.js App Router route
// app/api/chat/route.ts
import { streamText, UIMessage, convertToModelMessages } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: anthropic('claude-sonnet-4-5'),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
UIMessage là type v5+ cho messages đến từ React hook. convertToModelMessages chuyển đổi chúng sang format mà model mong đợi. Nếu bạn thấy Message trong các ví dụ cũ, đó là shape đã deprecated từ v4.
React client với useChat
// app/page.tsx
'use client';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div>
{messages.map(message => (
<div key={message.id}>
{message.role === 'user' ? 'User: ' : 'AI: '}
{message.parts
.filter(part => part.type === 'text')
.map((part, i) => (
<span key={i}>{part.text}</span>
))}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit">Send</button>
</form>
</div>
);
}
useChat xử lý cả ba việc: message state, HTTP POST đến /api/chat, và streaming response. Bạn chỉ cần viết markup.
Lỗi thường gặp: useChat mặc định gọi POST /api/chat. Nếu route của bạn ở path khác, truyền api như một option: useChat({ api: '/api/my-chat' }).
Tool call
Tool cho phép model thực hiện hành động — lấy dữ liệu, tính toán, gọi external API — trước khi trả về kết quả cuối. Bạn định nghĩa schema; model tự quyết định khi nào gọi.
import { generateText, tool, stepCountIs } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
const { text, steps } = await generateText({
model: anthropic('claude-sonnet-4-5'),
tools: {
getWeather: tool({
description: 'Get current weather for a city.',
inputSchema: z.object({ location: z.string() }),
execute: async ({ location }) => ({
location,
temperature: 68,
condition: 'sunny',
}),
}),
},
stopWhen: stepCountIs(5),
prompt: 'What should I wear today in NYC? Check the weather first.',
});
console.log(text);
console.log(`Completed in ${steps.length} steps`);
Lưu ý API cho v5/v6 — những điểm này sẽ gây lỗi âm thầm nếu dùng sai version:
| Dùng cái này | Không phải cái này |
|---|---|
inputSchema: | parameters: |
stopWhen: stepCountIs(N) | maxSteps: N |
output: trên tool result | result: |
steps cung cấp toàn bộ trace: model đã gọi gì, kết quả trả về là gì, và theo thứ tự nào. Rất hữu ích để debug.
Lỗi thường gặp: nếu execute throw, SDK sẽ đưa lỗi lên dưới dạng tool-call failure message. Model thường tự khắc phục bằng cách thử cách khác, nhưng hãy bọc execute trong try/catch và trả về structured error object nếu bạn muốn fallback có thể đoán trước.
Agent nhiều bước
Với các task cần nhiều tool call lặp lại — nghiên cứu, sinh code, xử lý data pipeline — ToolLoopAgent cho bạn một agent có thể tái sử dụng, chỉ cần định nghĩa một lần.
import { ToolLoopAgent, tool, stepCountIs } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
const agent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4-5'),
instructions: 'You are a research assistant. Be concise.',
tools: {
search: tool({
description: 'Search for information on a topic.',
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => ({
results: [`Fact about "${query}"`],
}),
}),
},
stopWhen: stepCountIs(20),
});
// Gọi một lần
const result = await agent.generate({
prompt: 'Compare RSC vs Client Components in React.',
});
console.log(result.text);
// Streaming
const stream = agent.stream({
prompt: 'Explain the Node.js event loop.',
});
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
ToolLoopAgent là tính năng mới trong AI SDK 6. Vòng lặp chạy cho đến khi stopWhen kích hoạt hoặc model báo hiệu xong. .generate() cho một response duy nhất; .stream() khi bạn muốn pipe output ngay khi có.
Điều kiện dừng
Ba tùy chọn sẵn có:
| Điều kiện | Dùng khi |
|---|---|
stepCountIs(N) | Muốn giới hạn cứng số lần gọi LLM |
hasToolCall('toolName') | Dừng khi một hành động cụ thể được kích hoạt |
isLoopFinished() | Để model chạy đến khi tự kết thúc |
Mặc định là stepCountIs(20). Điều chỉnh nếu task đơn giản (đặt thấp hơn để tiết kiệm token) hoặc phức tạp (đặt cao hơn).
Human-in-the-loop
Đánh dấu bất kỳ tool nào với needsApproval: true để vòng lặp dừng lại trước khi thực thi:
import { ToolLoopAgent, tool, stepCountIs } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
const agent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4-5'),
instructions: 'You are a deployment assistant.',
tools: {
deploy: tool({
description: 'Deploy the app to production.',
inputSchema: z.object({ env: z.string() }),
needsApproval: true,
execute: async ({ env }) => ({ deployed: true, env }),
}),
},
stopWhen: stepCountIs(10),
});
Agent dừng tại gate xác nhận và đưa tool call đang chờ lên UI để xác nhận. Đây là tính năng mới trong AI SDK 6.
Để xem walkthrough đầy đủ về kiến trúc agent — memory, tool chaining, và observability — xem cách build AI agent bằng TypeScript.
Chọn provider
Chỉ cần thay đổi model string khi chuyển provider:
| Provider | Install | Model ví dụ |
|---|---|---|
| Anthropic | @ai-sdk/anthropic | anthropic('claude-sonnet-4-5') |
| OpenAI | @ai-sdk/openai | openai('gpt-4o') |
@ai-sdk/google | google('gemini-2.0-flash') | |
| Mistral | @ai-sdk/mistral | mistral('mistral-large-latest') |
| Groq | @ai-sdk/groq | groq('llama-3.3-70b-versatile') |
| Vercel AI Gateway | built-in | gateway('anthropic/claude-sonnet-4-5') |
Đổi provider chỉ cần thay một dòng. Nếu bạn deploy trên Vercel, AI Gateway bổ sung caching, quản lý rate limit, và một đầu mối billing thống nhất cho mọi provider. Để xem phân tích chi tiết về chi phí và hiệu suất theo quy mô, xem đánh giá nền tảng Vercel của chúng tôi.
Debug với DevTools
AI SDK 6 đi kèm @ai-sdk/devtools. Sau khi cài, một inspector local tại localhost:4983 hiển thị mọi LLM call trong phiên: prompt, token, tool invocation, latency. Chạy trong lúc dev để phát hiện vấn đề với prompt và tool loop chạy mãi trước khi tốn tiền.
pnpm add -D @ai-sdk/devtools
Import ở đầu entry point dev — nó tự đăng ký và không làm gì trong production build.