Mở đầu — vì sao bài này quan trọng
Trong các bài trước, chúng ta đã bàn nhiều về kiến trúc, mô hình nền tảng, RAG, đánh giá và guardrails — tức là "cái gì" và "tại sao". Bài này chuyển sang một câu hỏi rất thực dụng: làm sao để ship một tính năng AI ra production nhanh nhất, mà vẫn đủ tốt để người dùng thật sử dụng?
Tôi nhấn mạnh chữ "nhanh" vì trong thực tế xây dựng sản phẩm AI, tốc độ ra thị trường quyết định rất nhiều. Không phải vì bạn cần "chạy đua" một cách vô nghĩa, mà vì sản phẩm AI chỉ tốt lên khi có người dùng thật tạo ra dữ liệu thật (data flywheel — chúng ta sẽ đào sâu ở Bài 28). Bạn càng đưa tính năng đến tay người dùng sớm, vòng lặp học hỏi càng nhanh. Một prototype chatbot chạy được sau 2 ngày, có 50 người dùng phản hồi, giá trị hơn nhiều so với một kiến trúc "hoàn hảo" nằm trên slide suốt 2 tháng.
Vấn đề là: nếu bạn tự viết mọi thứ từ đầu — gọi API của từng nhà cung cấp, tự xử lý streaming token, tự quản lý state của cuộc hội thoại trên frontend, tự retry khi lỗi — bạn sẽ mất hàng tuần chỉ cho phần "hạ tầng ống nước" (plumbing) mà chẳng tạo ra khác biệt gì cho sản phẩm. Đây chính là chỗ Vercel AI SDK cùng Next.js tỏa sáng: chúng cho phép một kỹ sư (thậm chí một PM biết code) dựng được một tính năng AI có streaming, đa nhà cung cấp, UI mượt mà chỉ trong vài giờ.
Bài này không dạy bạn "framework nào tốt nhất" một cách trừu tượng (chuyện đó thuộc Bài 23). Bài này tập trung vào một bộ công cụ cụ thể để xây nhanh — và quan trọng hơn, dạy bạn cách nghĩ về việc chọn công cụ ưu tiên tốc độ giao hàng.
Khái niệm cốt lõi
Vercel AI SDK là gì và giải quyết vấn đề gì
Vercel AI SDK là một thư viện TypeScript mã nguồn mở, đóng vai trò lớp trừu tượng (abstraction layer) giữa ứng dụng của bạn và các mô hình ngôn ngữ lớn. Thay vì học cách gọi API riêng của OpenAI, Anthropic, Google, bạn học một API duy nhất của SDK, rồi chỉ đổi một dòng cấu hình để chuyển nhà cung cấp.
Nó gồm hai phần chính:
- Core (
ai): chạy ở phía server, cung cấp các hàm nhưgenerateText(sinh văn bản một lần),streamText(streaming từng token),generateObject(bắt mô hình trả về JSON có cấu trúc theo schema), vàtool(định nghĩa công cụ để mô hình gọi — tool calling). - UI (
@ai-sdk/react): các React hook nhưuseChat,useCompletion,useObjectgiúp bạn dựng giao diện chat/streaming mà không phải tự quản lý state, loading, lỗi hay cập nhật từng token.
Bốn lý do khiến nó phù hợp để xây nhanh
Một, TypeScript-first. Toàn bộ SDK được viết cho hệ sinh thái JavaScript/TypeScript. Nếu sản phẩm của bạn dùng Next.js, React, hay bất kỳ backend Node nào, bạn không phải chuyển ngữ cảnh sang Python. Type safety giúp bắt lỗi ngay khi gõ code, đặc biệt quý giá khi làm việc với structured output.
Hai, streaming được tích hợp sẵn. Trải nghiệm "chữ hiện ra từng dòng" (như ChatGPT) là kỳ vọng mặc định của người dùng AI ngày nay. Tự làm streaming đúng cách rất khó: bạn phải xử lý Server-Sent Events, quản lý backpressure, ghép các token, xử lý ngắt kết nối. SDK gói toàn bộ chuyện đó lại — bạn gọi streamText, trả về result.toDataStreamResponse(), và ở frontend useChat tự lo phần còn lại.
Ba, trừu tượng đa nhà cung cấp (multi-provider). Bạn viết import { openai } from '@ai-sdk/openai' hay import { anthropic } from '@ai-sdk/anthropic' — cùng một interface. Điều này cực kỳ quan trọng về mặt chiến lược: bạn tránh bị khóa vào một vendor, có thể A/B test giữa GPT và Claude, hoặc dùng model rẻ cho tác vụ đơn giản và model mạnh cho tác vụ khó, mà không viết lại code.
Bốn, React hooks cho UI. Một dòng const { messages, input, handleSubmit } = useChat() cho bạn toàn bộ vòng đời của một cuộc hội thoại. Đây là thứ tiết kiệm cho bạn nhiều ngày nhất.
Vì sao ghép với Next.js
Next.js bổ sung mảnh còn thiếu: một nơi để đặt cả frontend và backend trong cùng một dự án. Với Route Handlers (thư mục app/api/), bạn viết endpoint server gọi LLM ngay cạnh component React gọi nó. API key nằm an toàn ở server (không lộ ra client), còn deploy lên Vercel thì gần như tức thì. Cặp đôi Next.js + AI SDK vì thế trở thành con đường ngắn nhất từ ý tưởng đến URL production.
Một điểm cần khắc cốt ghi tâm: AI SDK là công cụ để đi nhanh ở giai đoạn đầu và tầm trung. Nó không thay thế các quyết định kiến trúc lớn (RAG, eval, MLOps). Hãy xem nó như bộ khung xe giúp bạn lắp ráp nhanh, còn động cơ và chiến lược vẫn là việc của bạn.
Tình huống thực tế
Ví dụ 1 — Tiki dựng trợ lý gợi ý quà tặng trong một tuần
Giả sử đội growth của một sàn thương mại điện tử lớn tại Việt Nam (tạm gọi theo mô hình Tiki) muốn thử nghiệm một tính năng "trợ lý chọn quà" trước dịp Tết: người dùng mô tả người nhận (tuổi, sở thích, ngân sách), AI gợi ý 3-5 sản phẩm có sẵn trên sàn.
Nếu làm theo cách truyền thống, riêng phần dựng pipeline gọi model, xử lý streaming, và nối với catalog đã ngốn 2-3 tuần. Nhóm thay vào đó dùng Vercel AI SDK: streamText để sinh lời gợi ý, kèm một tool tên searchProducts cho phép model gọi vào API tìm kiếm nội bộ của sàn. Frontend dùng useChat nhúng vào trang chủ. Kết quả: bản demo chạy được sau 4 ngày, đưa cho 500 người dùng thử trong tuần đầu.
Diễn giải: Điểm mấu chốt là họ không cố xây "chatbot vạn năng". Họ giới hạn phạm vi (chỉ gợi ý quà), dùng tool calling để nối AI với dữ liệu thật của sàn, và để SDK lo phần streaming/UI. Bài học: ưu tiên phạm vi hẹp + công cụ dựng nhanh sẽ cho bạn dữ liệu người dùng thật sớm nhất, và chính dữ liệu đó (chứ không phải code đẹp) mới quyết định tính năng có đáng đầu tư tiếp không.
Ví dụ 2 — Startup fintech VN chuyển nhà cung cấp trong một buổi chiều
Một startup fintech ở TP.HCM xây trợ lý giải thích sao kê giao dịch cho người dùng, ban đầu dùng GPT-4o-mini vì rẻ. Sau ba tuần, họ phát hiện với các câu hỏi phức tạp về phí và lãi suất, model hay trả lời sai lệch, gây rủi ro tuân thủ (compliance — xem Bài 31). Họ muốn thử Claude cho các câu khó.
Vì đã viết trên AI SDK, việc chuyển gần như chỉ là: thêm @ai-sdk/anthropic, và trong route handler viết logic đơn giản — câu hỏi phân loại "phức tạp" thì dùng anthropic('claude-...'), câu đơn giản vẫn dùng openai('gpt-4o-mini'). Toàn bộ frontend useChat không đổi một dòng. Họ triển khai định tuyến theo độ khó (model routing) chỉ trong một buổi chiều, và cắt được khoảng 40% chi phí so với dùng model mạnh cho mọi câu.
Diễn giải: Trừu tượng đa nhà cung cấp không chỉ là tiện lợi kỹ thuật — nó là đòn bẩy về chi phí và chất lượng (nhắc lại chủ đề Bài 12 latency & cost). Bài học: chọn công cụ giữ cho bạn tính linh hoạt về vendor ngay từ đầu, vì bạn gần như chắc chắn sẽ đổi model khi hiểu rõ hơn về nhu cầu thật.
Ví dụ 3 — Đội nội bộ dựng công cụ trích xuất dữ liệu hợp đồng
Một công ty logistics giả định muốn công cụ nội bộ để nhân viên dán nội dung hợp đồng vào, AI trích ra các trường: bên A, bên B, giá trị, thời hạn, điều khoản phạt. Đây không phải chatbot — đây là bài toán structured output.
Nhóm dùng generateObject với một Zod schema mô tả chính xác cấu trúc JSON cần trả về. SDK ép model tuân theo schema, và nếu thiếu trường, họ biết ngay nhờ type safety. Không cần parse chuỗi thủ công, không cần regex mong manh. Công cụ hoàn thiện trong 2 ngày, xử lý được ~200 hợp đồng/ngày, tiết kiệm mỗi nhân viên khoảng 15 phút mỗi hợp đồng.
Diễn giải: Nhiều người nghĩ AI SDK chỉ để làm chat, nhưng generateObject mới là "vũ khí bí mật" cho các tác vụ trích xuất/phân loại nội bộ. Bài học: không phải mọi tính năng AI đều là hội thoại — hãy nhận diện đúng dạng bài toán (chat, completion, hay structured extraction) để chọn đúng hàm của SDK.
Hướng dẫn từng bước
Dưới đây là quy trình dựng một tính năng chat streaming từ số 0 trên Next.js. Tôi mô tả theo bước để bạn hình dung, không sa đà vào từng dòng code.
Bước 1 — Khởi tạo dự án. Tạo app Next.js (App Router) và cài các gói: ai, @ai-sdk/react, và provider bạn muốn, ví dụ @ai-sdk/openai. Đặt OPENAI_API_KEY vào file .env.local — không bao giờ để key này lộ ra client.
Bước 2 — Viết Route Handler. Tạo file app/api/chat/route.ts. Ở đây bạn nhận messages từ request, gọi streamText({ model: openai('gpt-4o-mini'), messages }), rồi trả về result.toDataStreamResponse(). Đây là toàn bộ backend — chưa tới 15 dòng. Toàn bộ việc gọi model và streaming nằm gọn ở server.
Bước 3 — Dựng UI với useChat. Trong một client component, gọi const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat(). Render danh sách messages (mỗi tin có role và content), một ô input nối với input/handleInputChange, và một form gọi handleSubmit. Hook tự động gửi request tới /api/chat và stream kết quả về, cập nhật UI từng token.
Bước 4 — Thêm system prompt và giới hạn phạm vi. Trong route handler, thêm một message role: 'system' mô tả rõ vai trò và ranh giới của trợ lý (ví dụ: "Chỉ trả lời về sản phẩm của công ty, từ chối lịch sự các câu ngoài phạm vi"). Đây là guardrail nhẹ nhất, ghép với các biện pháp ở Bài 10.
Bước 5 — Nối dữ liệu thật bằng tool calling. Nếu cần AI truy cập dữ liệu (sản phẩm, đơn hàng, tài liệu), định nghĩa tools với tool({ description, parameters, execute }). Model sẽ tự quyết định khi nào gọi, SDK lo phần điều phối. Đây là cầu nối giữa AI và hệ thống của bạn — và là bước đầu tiên hướng tới agent (Bài 17).
Bước 6 — Xử lý lỗi và trạng thái tải. Dùng isLoading để hiện chỉ báo "đang gõ...", và bắt lỗi để hiện thông báo thân thiện khi API quá tải hoặc timeout. Đừng để người dùng nhìn màn hình đứng im.
Bước 7 — Deploy. Push lên Git, kết nối Vercel (hoặc bất kỳ nền tảng nào chạy Node). Đặt biến môi trường trên dashboard. Bạn có URL production ngay. Với dự án Việt Nam nhắm người dùng trong nước, hãy cân nhắc region gần (ví dụ Singapore) để giảm latency.
Bước 8 — Cắm eval và quan sát. Trước khi mở rộng, thêm logging cho input/output và một bộ eval tối thiểu (Bài 9). Đi nhanh không có nghĩa là đi mù.
Lỗi thường gặp & mẹo
Lỗi: để lộ API key ở client. Người mới hay gọi model trực tiếp từ component. Luôn gọi qua Route Handler ở server. Key rò rỉ có thể khiến bạn mất hàng chục triệu đồng chỉ sau một đêm.
Lỗi: dùng model đắt nhất cho mọi thứ. Mặc định chọn gpt-4o hay Claude Opus cho cả những câu chào hỏi đơn giản là cách nhanh nhất để đốt tiền. Hãy phân tầng: model rẻ cho tác vụ dễ, model mạnh cho tác vụ khó — SDK giúp bạn làm điều này gần như miễn phí về công sức.
Lỗi: quên giới hạn độ dài lịch sử hội thoại. useChat tích lũy toàn bộ messages và gửi lại mỗi lượt. Cuộc chat dài làm chi phí token và latency tăng vọt. Hãy cắt bớt (truncate) hoặc tóm tắt lịch sử khi vượt ngưỡng.
Lỗi: không xử lý trường hợp streaming bị ngắt. Người dùng đóng tab, mạng chập chờn — hãy đảm bảo request bị hủy đúng cách để không tính tiền cho token không ai đọc. useChat có cơ chế stop(), hãy dùng nó.
Mẹo: bắt đầu với generateText trước khi chuyển sang streamText. Khi prototype logic, generateText (không streaming) dễ debug hơn nhiều vì bạn thấy toàn bộ output một lần. Thêm streaming khi logic đã ổn.
Mẹo: dùng generateObject bất cứ khi nào bạn cần dữ liệu có cấu trúc. Đừng bao giờ tự parse JSON từ output văn bản của model — nó mong manh và hay hỏng. Định nghĩa schema, để SDK ép model tuân theo.
Mẹo: đừng nhầm "dựng nhanh" với "bỏ qua eval và guardrails". AI SDK giúp bạn ship khung sườn nhanh, nhưng chất lượng, an toàn và tuân thủ vẫn là trách nhiệm của bạn. Nhanh ở phần plumbing, kỹ ở phần quyết định.
Mẹo: khóa version của SDK. Hệ sinh thái AI SDK tiến hóa rất nhanh, API có thể đổi giữa các major version. Ghim version trong package.json và đọc changelog trước khi nâng cấp để tránh vỡ production.
Bài tập thực hành
- Dựng chatbot tối thiểu. Tạo một app Next.js với một Route Handler dùng
streamTextvà một trang dùnguseChat. Mục tiêu: có một chatbot streaming chạy trên máy bạn trong dưới 60 phút. Đo xem bạn mất bao lâu — con số này cho bạn cảm nhận thật về tốc độ.
- Thêm system prompt giới hạn phạm vi. Biến chatbot trên thành "trợ lý tư vấn sản phẩm" cho một cửa hàng giả định. Viết system prompt sao cho nó từ chối lịch sự các câu ngoài chủ đề. Thử nghiệm 5 câu hỏi "bẫy" để kiểm tra ranh giới.
- Chuyển nhà cung cấp. Cài thêm một provider thứ hai (ví dụ Anthropic hoặc Google) và viết logic định tuyến đơn giản: câu ngắn dùng model rẻ, câu dài dùng model mạnh. Ghi lại chênh lệch chi phí ước tính.
- Structured output. Dùng
generateObjectvới một Zod schema để trích xuất thông tin từ một đoạn mô tả sản phẩm tự do (tên, giá, danh mục, tính năng chính) thành JSON. So sánh độ tin cậy với cách bảo model "trả về JSON" trong prompt thông thường.
- Suy ngẫm chiến lược. Viết nửa trang: với sản phẩm bạn đang hình dung, phần nào nên dùng AI SDK để đi nhanh, và phần nào bạn không nên "đi tắt" (ví dụ eval, xử lý dữ liệu nhạy cảm, compliance)?
Tóm tắt
Bài 24 xoay quanh một mục tiêu duy nhất: rút ngắn khoảng cách từ ý tưởng đến tính năng AI chạy được trong tay người dùng thật. Vercel AI SDK cùng Next.js là con đường ngắn nhất cho hệ sinh thái TypeScript nhờ bốn thế mạnh — TypeScript-first, streaming tích hợp sẵn, trừu tượng đa nhà cung cấp, và React hooks cho UI. Ba trụ cột hàm bạn cần nắm là streamText (chat/streaming), generateObject (dữ liệu có cấu trúc), và tool (nối AI với hệ thống của bạn), tất cả đặt an toàn sau Route Handler của Next.js.
Qua ba tình huống — trợ lý gợi ý quà của một sàn TMĐT, việc chuyển vendor trong một buổi chiều của startup fintech, và công cụ trích xuất hợp đồng nội bộ — ta thấy một khuôn mẫu chung: giới hạn phạm vi hẹp, dùng công cụ dựng nhanh để lấy dữ liệu người dùng sớm, và giữ linh hoạt về mô hình để tối ưu chi phí lẫn chất lượng.
Nhưng hãy nhớ nguyên tắc cân bằng: đi nhanh ở phần "ống nước", đi kỹ ở phần quyết định. AI SDK giúp bạn ship khung sườn trong vài giờ, nhưng eval, guardrails, chi phí và tuân thủ vẫn là trách nhiệm không thể ủy thác. Ở các bài tiếp theo, chúng ta sẽ đào sâu backend (Bài 25), frontend streaming UX (Bài 26) và testing (Bài 27) — nhưng nền tảng "xây nhanh mà không xây ẩu" bạn đặt ở bài này sẽ theo bạn suốt hành trình làm sản phẩm AI.