Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn xây một chatbot tư vấn sản phẩm cho một sàn thương mại điện tử. Bạn hỏi AI: "Khách này muốn mua gì, ngân sách bao nhiêu?" và AI trả lời rất lịch sự: "Dạ, dựa trên tin nhắn thì khách hàng có vẻ đang tìm một chiếc điện thoại tầm trung, ngân sách khoảng 8 đến 10 triệu ạ." Nghe thì hay, nhưng đến lúc bạn viết code để lấy con số "8 triệu" ra và đẩy vào hệ thống lọc sản phẩm, bạn mới nhận ra: làm sao máy tính biết trích "8 triệu" từ một câu văn xuôi dài dòng như thế? Lần sau AI trả lời "tầm 8-10 củ", lần sau nữa "khoảng chục triệu đổ lại". Mỗi lần một kiểu. Hệ thống của bạn vỡ trận.
Đây chính là lý do structured output (đầu ra có cấu trúc) tồn tại. Khi bạn dùng AI trong sản phẩm thật — không phải chat cho vui — bạn gần như luôn cần AI trả về dữ liệu theo một định dạng máy đọc được: JSON, XML, hoặc bảng (table). Bài này dạy bạn cách "ép" mô hình trả lời đúng khuôn, ổn định, để bạn có thể parse (phân tích) và tự động hóa. Đây là kỹ năng ranh giới giữa "chơi với AI" và "đưa AI vào production". Nắm được nó, bạn mở ra cả một thế giới tích hợp: đẩy dữ liệu vào database, gọi API, điền form, xuất báo cáo — tất cả tự động.
Khái niệm cốt lõi
Structured output là gì và khác gì free-form
Mặc định, một mô hình ngôn ngữ (LLM) sinh ra free-form prose — văn xuôi tự do, giống như con người viết. Rất tuyệt để đọc, nhưng cực khó để máy xử lý. Structured output là khi bạn yêu cầu mô hình trả về dữ liệu theo một schema (lược đồ) cố định — một khuôn dạng có quy tắc rõ ràng về khóa (key), kiểu dữ liệu (số, chuỗi, boolean), và cấu trúc lồng nhau.
Ba định dạng phổ biến nhất:
- JSON (JavaScript Object Notation): Vua của structured output trong lập trình web và API. Dạng
{"ten": "Nam", "tuoi": 30}. Gần như mọi ngôn ngữ lập trình đều parse JSON trong một dòng code. Đây là lựa chọn mặc định 90% trường hợp. - XML: Dạng thẻ lồng nhau
<khach><ten>Nam</ten></khach>. Nặng nề hơn JSON nhưng có một ưu điểm lớn: mô hình rất giỏi giữ đúng cặp thẻ đóng/mở, nên với văn bản dài chứa ký tự đặc biệt (dấu ngoặc, xuống dòng), XML đôi khi ổn định hơn. Nhiều prompt engineer dùng thẻ XML để "đóng khung" từng phần trong prompt. - Table (bảng): Thường ở dạng Markdown table hoặc CSV. Lý tưởng khi kết quả là danh sách nhiều dòng đồng nhất — ví dụ danh sách 10 sản phẩm với cùng các cột. Người dùng cuối đọc bảng dễ, và bạn có thể copy thẳng vào Excel/Google Sheets.
Vì sao LLM hay "drift" format
Điểm đau lớn nhất: mô hình có xu hướng drift — trôi khỏi định dạng bạn yêu cầu. Bạn xin JSON thuần, nó lại "nhiệt tình" thêm câu mở đầu: "Chắc chắn rồi, đây là JSON bạn cần:" trước khối JSON, rồi thêm câu chốt "Hy vọng giúp được bạn!" ở cuối. Hoặc nó bọc JSON trong dấu `` (code fence). Hoặc tệ hơn, nó bịa thêm khóa bạn không hỏi, thiếu dấu phẩy, dùng dấu nháy đơn thay vì nháy kép (JSON chuẩn bắt buộc nháy kép). Chỉ cần một lỗi cú pháp nhỏ, hàm JSON.parse() của bạn ném lỗi và cả pipeline dừng lại.
Nguyên nhân: mô hình được huấn luyện để giao tiếp tự nhiên với con người, nên bản năng của nó là "nói cho lịch sự, đầy đủ". Nhiệm vụ của bạn là dùng prompt để ghi đè bản năng đó bằng những chỉ dẫn cực kỳ rõ ràng và ràng buộc chặt.
Ba tầng công cụ để ép format
Có ba mức độ, từ nhẹ đến mạnh:
- Chỉ dẫn trong prompt: Bạn mô tả schema bằng lời và ra lệnh "chỉ trả JSON, không thêm gì khác". Đơn giản, dùng được với mọi mô hình, nhưng độ tin cậy phụ thuộc kỹ năng viết prompt.
- Cung cấp ví dụ khuôn mẫu: Đưa 1-2 ví dụ output mẫu ngay trong prompt. Mô hình bắt chước rất tốt. (Kỹ thuật few-shot bạn sẽ học kỹ ở bài khác — ở đây ta chỉ dùng nó như công cụ ép format.)
- Structured output mode / JSON mode của API: Nhiều nhà cung cấp (như tính năng response_format của một số API, hay ràng buộc theo schema) cho phép bạn khai báo schema và hệ thống đảm bảo output hợp lệ ở tầng API, không phụ thuộc may rủi của prompt. Đây là cách chắc ăn nhất cho production. Khi có, hãy ưu tiên dùng.
Tình huống thực tế
Ví dụ 1 — Tiki và bài toán trích thông tin đơn hàng từ chat
Giả định một đội kỹ thuật ở một sàn TMĐT lớn tại Việt Nam (tạm gọi theo mô hình Tiki) xây tính năng: khách nhắn tin tự do mô tả nhu cầu, hệ thống dùng AI biến tin nhắn thành một "phiếu tìm kiếm" có cấu trúc để đẩy vào bộ lọc sản phẩm.
Ban đầu, đội để AI trả lời tự nhiên rồi viết regex (biểu thức chính quy) để bóc số liệu. Tỷ lệ bóc đúng chỉ khoảng 60%, vì khách viết "tám triệu", "8tr", "8 củ", "khoảng 8-10 triệu" — muôn hình vạn trạng. Mỗi tuần đội mất hàng chục giờ vá regex.
Họ chuyển sang bắt AI trả về JSON theo schema cố định:
{
"danh_muc": "dien_thoai",
"ngan_sach_min": 8000000,
"ngan_sach_max": 10000000,
"thuong_hieu": ["Samsung", "Xiaomi"],
"uu_tien": "pin_trau"
}
Prompt yêu cầu rõ: ngân sách phải quy về số nguyên đồng Việt Nam, danh mục phải chọn trong danh sách cho sẵn, nếu không rõ thì để null. Kết quả: tỷ lệ parse thành công vọt lên trên 95%, và quan trọng là dữ liệu đã "sạch" — luôn là số đồng, không còn "củ" hay "tr".
Bài học: Structured output không chỉ giúp máy đọc được, mà còn chuẩn hóa dữ liệu ngay tại nguồn. Bạn ép AI làm luôn việc quy đổi và làm sạch, thay vì để code phía sau vật lộn.
Ví dụ 2 — Startup fintech phân loại giao dịch
Một startup fintech ở TP.HCM làm app quản lý chi tiêu cá nhân. Họ cần AI đọc mô tả giao dịch ngân hàng (thường viết tắt kỳ quặc như "CHUYEN TIEN GRAB*ABC123") và phân loại vào các nhóm: ăn uống, di chuyển, mua sắm, hóa đơn...
Với hàng nghìn giao dịch mỗi ngày, họ không thể để AI trả lời từng câu văn xuôi. Họ dùng bảng: đưa vào một danh sách giao dịch, yêu cầu AI trả về Markdown table với đúng ba cột ma_giao_dich | nhom | do_tin_cay. Nhờ định dạng bảng, họ xử lý cả lô (batch) hàng trăm giao dịch trong một lần gọi, rồi convert bảng thành mảng để ghi vào database.
Điểm mấu chốt họ học được: cột do_tin_cay (0-1) cực kỳ giá trị. Với những dòng AI tự chấm điểm tin cậy dưới 0.7, hệ thống tự động chuyển sang cho nhân viên duyệt tay. Structured output cho phép bạn thiết kế "van an toàn" ngay trong dữ liệu.
Bài học: Bảng là bạn thân khi xử lý nhiều dòng đồng dạng. Và hãy chủ động thêm các trường meta như độ tin cậy để build cơ chế kiểm soát chất lượng.
Ví dụ 3 — Agency marketing xuất brief chiến dịch
Một agency ở Hà Nội dùng AI để biến buổi họp brainstorm (được ghi âm và chuyển thành văn bản) thành brief chiến dịch chuẩn. Họ dùng XML vì nội dung brief chứa nhiều đoạn văn dài, có dấu xuống dòng, dấu ngoặc kép — những thứ dễ làm hỏng JSON.
<brief>
<ten_chien_dich>Tết 2027 - Về Nhà</ten_chien_dich>
<doi_tuong>Người trẻ 22-30 xa quê</doi_tuong>
<thong_diep>Dù đi đâu, nhà vẫn là nơi để về</thong_diep>
<kenh>Facebook, TikTok, OOH</kenh>
</brief>
Với thẻ XML, mô hình giữ đúng cấu trúc kể cả khi trường thong_diep dài mấy đoạn. Họ chỉ cần một trình parse XML đơn giản là đổ thẳng vào template Google Docs.
Bài học: Chọn định dạng theo bản chất dữ liệu. Dữ liệu ngắn gọn, số nhiều: JSON. Nhiều dòng đồng dạng: table. Văn bản dài, nhiều ký tự đặc biệt: XML thường an toàn hơn.
Hướng dẫn từng bước
Bước 1 — Xác định schema trước khi viết prompt. Đừng viết prompt rồi mới nghĩ output. Ngược lại: vẽ ra chính xác cấu trúc bạn cần, tên từng khóa, kiểu dữ liệu, giá trị bắt buộc/tùy chọn. Schema là hợp đồng giữa AI và code của bạn.
Bước 2 — Mô tả schema thật rõ trong prompt. Nêu rõ từng khóa nghĩa là gì, kiểu gì. Ví dụ: "Trả về JSON với các khóa: ten (chuỗi), tuoi (số nguyên), da_ket_hon (boolean)."
Bước 3 — Đưa một ví dụ output mẫu. Dán một khối mẫu hoàn chỉnh. Đây là cách nhanh nhất để mô hình hiểu chính xác bạn muốn gì, kể cả cách đặt dấu, thụt lề.
Bước 4 — Ra lệnh ràng buộc nghiêm ngặt. Thêm những câu như: "CHỈ trả về JSON hợp lệ. KHÔNG thêm lời giải thích, không thêm câu mở đầu hay kết thúc, không bọc trong dấu `." Viết hoa những từ khóa quan trọng để nhấn mạnh.
Bước 5 — Xử lý trường hợp thiếu dữ liệu. Nói rõ AI phải làm gì khi không tìm được thông tin: dùng null, chuỗi rỗng "", hay bỏ khóa? Nếu không dặn, AI sẽ tự bịa (hallucinate) — cực nguy hiểm với dữ liệu tài chính.
Bước 6 — Dùng JSON mode / structured output của API nếu có. Nếu nền tảng hỗ trợ khai báo schema ở tầng API, hãy dùng. Nó đảm bảo output hợp lệ mà không phụ thuộc câu chữ của prompt.
Bước 7 — Luôn validate ở tầng code. Đừng bao giờ tin tuyệt đối. Bọc JSON.parse trong try-catch, kiểm tra các khóa bắt buộc có tồn tại không, kiểu dữ liệu đúng chưa. Nếu lỗi, có cơ chế thử lại (retry) hoặc fallback.
Lỗi thường gặp & mẹo
Lỗi 1 — Quên cấm phần văn xuôi thừa. Mô hình bọc JSON bằng "Đây là kết quả:" và code parse chết ngay. Mẹo: Ra lệnh rõ "output đầu tiên phải là ký tự {". Ở tầng code, có thể trích phần từ { đầu tiên đến } cuối để phòng hờ.
Lỗi 2 — Schema mơ hồ dẫn tới drift. Khóa đặt tên nhập nhằng khiến AI mỗi lần điền một kiểu. Mẹo: Tên khóa cụ thể, kèm ví dụ giá trị. gia mơ hồ; gia_ban_le_vnd` rõ ràng.
Lỗi 3 — Để AI tự bịa khi thiếu dữ liệu. Không dặn xử lý null, AI sẽ điền số ngẫu nhiên trông rất thật. Mẹo: Luôn có câu "nếu không chắc chắn, để null, TUYỆT ĐỐI không đoán".
Lỗi 4 — JSON quá phức tạp, lồng nhiều tầng. Cấu trúc lồng 4-5 tầng làm mô hình dễ sai cú pháp. Mẹo: Giữ schema càng phẳng càng tốt. Nếu quá phức tạp, chia thành nhiều lần gọi (prompt chaining — bạn sẽ học ở bài khác).
Lỗi 5 — Tin output mà không validate. Mẹo: Validate là bắt buộc trong production. Cân nhắc dùng schema validation như JSON Schema hay thư viện như Zod/Pydantic để kiểm tra tự động.
Mẹo vàng — Dùng thấp temperature. Với structured output, đặt temperature thấp (gần 0) để mô hình bám khuôn, ít sáng tạo lung tung. (Chi tiết về temperature ở bài riêng.)
Bài tập thực hành
- Thiết kế schema: Chọn một use case của bạn (ví dụ: trích thông tin từ CV ứng viên). Viết ra schema JSON đầy đủ: liệt kê khóa, kiểu dữ liệu, khóa nào bắt buộc, xử lý thiếu ra sao.
- Viết prompt ép JSON: Soạn một prompt hoàn chỉnh để AI đọc một đoạn CV mẫu và trả về đúng schema trên. Nhớ đủ 3 phần: mô tả schema, ví dụ output, câu ràng buộc nghiêm ngặt.
- So sánh ba định dạng: Lấy cùng một dữ liệu (danh sách 5 sản phẩm) và yêu cầu AI xuất ra lần lượt JSON, XML, và Markdown table. Nhận xét: định dạng nào dễ đọc nhất với con người? Dễ parse nhất với máy? Ổn định nhất qua nhiều lần chạy?
- Phá vỡ và sửa: Cố tình viết một prompt mơ hồ để AI drift format. Quan sát lỗi. Rồi sửa prompt từng bước cho đến khi output ổn định 5 lần chạy liên tiếp. Ghi lại câu chữ nào tạo khác biệt lớn nhất.
Tóm tắt
Structured output là cầu nối biến AI từ một "người trò chuyện" thành một "thành phần hệ thống" đáng tin. Cốt lõi bạn cần nhớ:
- Vì sao cần: Ứng dụng thật cần parse dữ liệu để tự động hóa; văn xuôi tự do không làm được điều đó; và mô hình hay drift format nếu không được ràng buộc chặt.
- Ba định dạng: JSON (mặc định, gọn, dễ parse), XML (an toàn cho văn bản dài, nhiều ký tự đặc biệt), table (lý tưởng cho nhiều dòng đồng dạng).
- Cách ép format: Xác định schema trước → mô tả rõ → cho ví dụ mẫu → ra lệnh nghiêm ngặt → dặn xử lý thiếu dữ liệu → dùng JSON mode của API khi có → validate ở tầng code.
- Nguyên tắc sống còn: Không bao giờ tin output một cách mù quáng. Luôn validate, luôn có phương án dự phòng.