- Structured outputs ép mô hình sinh JSON khớp schema bạn đưa (kiểu dữ liệu, trường bắt buộc), nên không còn lỗi JSON hỏng hay thiếu trường.
- Hai trường hợp ngoại lệ phải tự xử lý: mô hình từ chối, hoặc câu trả lời bị cắt vì chạm giới hạn token.
- Schema không ép được mọi thứ: tài liệu ghi không hỗ trợ ràng buộc khoảng số, độ dài chuỗi; chữ hoa thường của giá trị enum cũng không được bảo đảm. Phần này tự soát sau khi nhận.
- JSON đúng định dạng chưa chắc đúng nội dung. Vẫn cần đối chiếu và đánh giá.
Bài này dựa trên trang Structured outputs trong tài liệu của Anthropic (đọc ngày 11/11/2026). OpenAI và các hãng khác có tính năng tương tự với tên tham số khác. Nếu chưa gọi API bao giờ, đọc trước bài gọi API AI bằng Python.
Vì sao dặn trong prompt chưa đủ
Cách đầu tiên ai cũng thử là viết trong prompt: "trả lời bằng JSON có các trường sau". Phần lớn lần sẽ được. Nhưng khi chạy hàng nghìn lần, sẽ có lúc mô hình thêm một câu dẫn trước JSON, quên một trường, đổi tên trường, viết số thành chuỗi, hoặc để JSON thiếu dấu ngoặc. Mỗi lỗi như vậy làm chương trình đọc JSON bị ngắt, và bạn phải viết thêm code thử lại.
Structured outputs giải quyết ở tầng sinh chữ. Theo tài liệu, API dùng giải mã có ràng buộc: tại mỗi bước, mô hình chỉ được chọn những ký tự giữ cho câu trả lời còn khớp schema. Kết quả là JSON luôn đọc được và đúng cấu trúc, trừ các ngoại lệ nói ở dưới.
Viết schema
Schema viết theo chuẩn JSON Schema: đối tượng có những thuộc tính nào, mỗi thuộc tính kiểu gì, thuộc tính nào bắt buộc. Với structured outputs, mỗi đối tượng cần đặt thêm thuộc tính bổ sung là không cho phép, để mô hình không tự thêm trường lạ.
Tài liệu liệt kê những gì hỗ trợ: các kiểu cơ bản (đối tượng, mảng, chuỗi, số nguyên, số thực, đúng sai, rỗng), enum, các định dạng chuỗi như ngày, ngày giờ, email, đường dẫn. Và những gì không hỗ trợ, gửi lên sẽ bị báo lỗi: schema đệ quy, ràng buộc số như nhỏ nhất, lớn nhất, ràng buộc độ dài chuỗi, ràng buộc mảng ngoài số phần tử tối thiểu là 0 hoặc 1. Nếu cần các ràng buộc đó, ghi chúng vào phần mô tả của trường để mô hình biết, rồi tự kiểm lại trong code.
Một mẹo nhỏ: giữ schema đơn giản và phẳng. Tài liệu có nêu giới hạn độ phức tạp, và lần đầu dùng một schema mới sẽ chậm hơn vì API phải biên dịch nó; bản biên dịch được giữ 24 giờ kể từ lần dùng cuối.
Ví dụ: trích lịch thi
Chương trình dưới đây nhận một thông báo lịch thi bằng tiếng Việt và trích ra danh sách môn thi, mỗi môn gồm tên môn, ngày, ca (sáng hoặc chiều), phòng, thời gian làm bài tính bằng phút, kèm một trường ghi chú. Schema được gửi trong tham số output_config. Chỉ dẫn hệ thống nhắc mô hình chỉ dùng thông tin có trong thông báo.
"""Bắt Claude trả về JSON đúng schema (structured outputs) để trích lịch thi từ một thông báo.
API bảo đảm JSON hợp lệ và đúng schema (output_config.format), trừ khi mô hình từ chối (stop_reason "refusal")
hoặc bị cắt vì max_tokens. Schema không hỗ trợ ràng buộc như minimum/maximum, nên phần đó tự kiểm sau khi nhận.
Cài: python -m pip install anthropic ; đặt biến môi trường ANTHROPIC_API_KEY.
"""
import json
import os
import sys
from datetime import date
SCHEMA = {
"type": "object",
"properties": {
"mon_thi": {
"type": "array",
"items": {
"type": "object",
"properties": {
"mon": {"type": "string"},
"ngay": {"type": "string", "format": "date"},
"ca": {"type": "string", "enum": ["sáng", "chiều"]},
"phong": {"type": "string"},
"thoi_gian_phut": {"type": "integer", "description": "Từ 15 đến 240"},
},
"required": ["mon", "ngay", "ca", "phong", "thoi_gian_phut"],
"additionalProperties": False,
},
},
"ghi_chu": {"type": "string"},
},
"required": ["mon_thi", "ghi_chu"],
"additionalProperties": False,
}
HE_THONG = "Trích lịch thi từ thông báo. Chỉ dùng thông tin có trong thông báo; không có thì ghi vào ghi_chu."
class KhongTrichDuoc(Exception):
pass
def trich(client, thong_bao, mo_hinh="claude-opus-5-5"):
tl = client.messages.create(
model=mo_hinh,
max_tokens=2000,
system=HE_THONG,
messages=[{"role": "user", "content": thong_bao}],
output_config={"format": {"type": "json_schema", "schema": SCHEMA}},
)
if tl.stop_reason == "refusal":
raise KhongTrichDuoc("Mô hình từ chối; kết quả có thể không đúng schema.")
if tl.stop_reason == "max_tokens":
raise KhongTrichDuoc("Bị cắt vì max_tokens; tăng giới hạn rồi thử lại.")
chu = next(k.text for k in tl.content if k.type == "text")
return json.loads(chu)
def soat(du_lieu):
"""Tự kiểm những điều schema không ép được: khoảng giá trị, ngày hợp lệ, chữ hoa thường của enum."""
loi = []
for i, m in enumerate(du_lieu["mon_thi"], 1):
m["ca"] = m["ca"].lower()
if m["ca"] not in ("sáng", "chiều"):
loi.append(f"môn {i}: ca '{m['ca']}' lạ")
if not 15 <= m["thoi_gian_phut"] <= 240:
loi.append(f"môn {i}: thời gian {m['thoi_gian_phut']} phút ngoài khoảng 15-240")
try:
date.fromisoformat(m["ngay"])
except ValueError:
loi.append(f"môn {i}: ngày '{m['ngay']}' không hợp lệ")
return loi
def main():
if not os.environ.get("ANTHROPIC_API_KEY"):
sys.exit("Chưa có ANTHROPIC_API_KEY. Đặt biến môi trường trước khi chạy.")
import anthropic
thong_bao = (sys.stdin.read() if not sys.stdin.isatty() else "").strip() or (
"Lịch thi học kỳ 1: Toán sáng 15/12/2026 phòng A101, 90 phút; Tin chiều 17/12/2026 phòng Lab2, 120 phút.")
try:
du_lieu = trich(anthropic.Anthropic(), thong_bao)
except anthropic.APIStatusError as e:
sys.exit(f"API báo lỗi {e.status_code}: {e.message}")
except anthropic.APIConnectionError:
sys.exit("Không kết nối được tới API. Kiểm tra mạng rồi thử lại.")
except KhongTrichDuoc as e:
sys.exit(str(e))
print(json.dumps(du_lieu, ensure_ascii=False, indent=2))
for l in soat(du_lieu):
print("Cần xem lại:", l)
if __name__ == "__main__":
main()
Hàm trich làm ba việc theo thứ tự. Gửi yêu cầu kèm schema. Xét lý do dừng: nếu là từ chối hoặc chạm giới hạn token thì báo lỗi riêng, không đọc tiếp. Còn lại thì lấy khối chữ và đọc JSON.
Hàm soat làm phần schema không ép được. Thời gian làm bài phải từ 15 đến 240 phút; schema không cho đặt khoảng số, nên điều kiện này chỉ ghi trong mô tả trường và được kiểm lại ở đây. Ngày phải là ngày có thật; định dạng ngày trong schema bảo đảm đúng mẫu năm-tháng-ngày, nhưng code vẫn đọc lại để bắt trường hợp như ngày 30 tháng 2. Ca thi được đưa về chữ thường trước khi so, vì tài liệu ghi rõ chữ hoa thường của giá trị enum không được bảo đảm.
Hai ngoại lệ phải xử lý
Mô hình từ chối. Khi lý do dừng là từ chối, API vẫn trả về thành công và vẫn tính tiền phần đã sinh, nhưng tài liệu ghi rõ nội dung có thể không khớp schema, vì việc từ chối được ưu tiên. Chương trình không được đọc kết quả như bình thường. Tài liệu còn lưu ý: trường yêu cầu mô hình viết lập luận từng bước có thể gây từ chối; muốn có lời giải thích thì xin một lời giải thích ngắn.
Bị cắt vì giới hạn token. Khi danh sách dài và giới hạn token thấp, JSON có thể dừng giữa chừng và không còn hợp lệ. Cách xử lý là tăng giới hạn rồi thử lại, hoặc chia đầu vào thành phần nhỏ hơn.
Một luồng xử lý đầy đủ
Ghép các phần trên lại, một chương trình trích dữ liệu bằng mô hình thường chạy theo luồng sau. Văn bản vào được làm sạch sơ bộ: bỏ phần chữ ký email, đầu trang, những đoạn không liên quan, để mô hình tập trung và đỡ tốn token. Gửi yêu cầu kèm schema. Nếu bị từ chối hay bị cắt, ghi lại và đưa vào hàng chờ cho người xem, không tự thử lại vô hạn. Nếu nhận được JSON, chạy hàm soát; mục nào vượt qua thì ghi thẳng vào hệ thống, mục nào có cảnh báo thì đánh dấu để người kiểm duyệt.
Luôn lưu kèm văn bản gốc và phiên bản schema cạnh mỗi kết quả. Khi phát hiện trích sai, bạn có đủ dữ liệu để tìm nguyên nhân: văn bản mơ hồ, mô tả trường chưa rõ, hay mô hình nhầm. Khi đổi schema, các kết quả cũ vẫn đọc được vì bạn biết chúng theo phiên bản nào.
Thư viện Python làm sẵn
Ví dụ trong bài viết schema bằng dictionary để thấy rõ cấu trúc. Thư viện anthropic còn có hàm parse nhận một lớp Pydantic: bạn khai báo lớp với các trường và kiểu, thư viện tự chuyển thành schema, gửi đi, kiểm kết quả và trả về một đối tượng đã kiểm. Theo tài liệu, khi dùng cách này, thư viện còn chuyển những ràng buộc API không hỗ trợ vào phần mô tả và tự kiểm chúng ở máy bạn. Với dự án thật, đây thường là cách gọn nhất.
JSON đúng chưa chắc nội dung đúng
Structured outputs bảo đảm hình thức. Nó không bảo đảm mô hình đọc đúng thông báo: có thể nhầm ngày, ghép sai phòng với môn, hoặc tự điền một giá trị không có trong văn bản khi trường là bắt buộc. Ba cách giảm rủi ro:
- Cho phép "không có thông tin": thêm trường ghi chú, hoặc cho phép giá trị rỗng, để mô hình không bị ép bịa.
- Đối chiếu ngược: kiểm tra mỗi giá trị trích ra có xuất hiện trong văn bản gốc không.
- Đánh giá trên một bộ thông báo mẫu có đáp án trước khi dùng thật, như cách trong bài đánh giá câu trả lời AI.
Structured outputs cũng dùng được cho công cụ: thêm chế độ nghiêm ngặt vào định nghĩa công cụ để tham số mô hình đưa luôn đúng schema, xem bài tool use.
- Chỉ dặn JSON trong prompt rồi đọc thẳng kết quả mà không bắt lỗi.
- Đọc kết quả khi lý do dừng là từ chối hoặc bị cắt.
- Dùng ràng buộc số hay độ dài chuỗi trong schema mà tài liệu ghi là không hỗ trợ.
- So giá trị enum phân biệt chữ hoa thường.
- Bắt buộc mọi trường mà không cho mô hình cách nói "không có thông tin".
Câu hỏi thường gặp
Structured outputs có làm chậm không?
Lần đầu dùng một schema mới chậm hơn vì phải biên dịch; các lần sau trong 24 giờ dùng bản đã lưu. API cũng thêm một đoạn chỉ dẫn hệ thống, tốn thêm ít token đầu vào.
Mô hình nào hỗ trợ?
Mọi mô hình. Bảng Availability trong tài liệu ghi thẳng ở dòng Models là "All models", nên không phải chọn mô hình theo tính năng này. Vẫn nên mở trang tài liệu xem lại trước khi làm, vì tính năng còn đang được bổ sung.
Nên dùng structured outputs hay tool use?
Muốn câu trả lời cuối là JSON thì dùng structured outputs. Muốn mô hình gọi hàm của bạn thì dùng tool use, có thể bật chế độ nghiêm ngặt. Hai cách dùng chung được.
Có cần thử lại khi lỗi không?
Với lỗi cú pháp thì hầu như không còn. Vẫn cần xử lý từ chối, bị cắt và lỗi mạng.
Học tiếp
- Gọi API lần đầu: gọi API AI bằng Python.
- Cho mô hình gọi hàm với tham số đúng schema: tool use.
- Dùng JSON có cấu trúc để phân loại văn bản: phân loại văn bản bằng mô hình ngôn ngữ.
Nếu bạn muốn học Python và AI bài bản cùng giảng viên, tham khảo khóa học AI của Big-O Coding.
Khóa AI – Introduction to Machine Learning: nền tảng Máy học từ thuật toán cơ bản đến Neural Networks và LLM, học bằng Python. Học thử buổi 1 miễn phí.


