Nỗi ám ảnh mang tên “Invalid JSON”
Nếu bạn từng gọi API của OpenAI để lấy dữ liệu, kịch bản sau chắc chắn rất quen thuộc: Bạn yêu cầu AI trả về JSON, nhưng nó lại hào phóng tặng thêm câu dẫn: “Đây là kết quả của bạn:”. Hoặc tệ hơn, một dấu ngoặc nhọn bị rớt mất ở cuối chuỗi. Kết quả là hàm json.loads() văng lỗi JSONDecodeError ngay lập tức.
Trước đây, mình thường phải dùng Regex để “gọt giũa” kết quả hoặc viết System Prompt dài cả trang giấy chỉ để van nài AI đừng nói thừa. Tuy nhiên, sau 6 tháng đưa Instructor vào hệ thống production, mình đã bỏ hẳn cách làm khổ sở đó. Tỷ lệ lỗi parsing từ mức 10-15% đã giảm xuống còn gần như bằng 0.
Instructor không chỉ là một thư viện. Nó là một tư duy mới: Sử dụng Pydantic để định nghĩa Schema và ép LLM phải tuân thủ tuyệt đối. Nếu AI trả về sai? Instructor sẽ tự động cầm log lỗi ném ngược lại cho AI và bảo: “Sai rồi, sửa đi!”.
Cài đặt trong 30 giây
Instructor đóng vai trò như một lớp bọc (wrapper) thông minh quanh client gốc của OpenAI hoặc Anthropic. Bạn chỉ cần cài đặt gói chính cùng với Pydantic v2:
pip install -U instructor openai pydantic
Thư viện này hỗ trợ cực tốt cho cơ chế tool_use (function calling), giúp việc trích xuất dữ liệu trở nên ổn định hơn bao giờ hết.
Triển khai thực tế: Từ Schema đến dữ liệu sạch
Quy trình với Instructor gói gọn trong 3 bước: Định nghĩa Schema, Wrap Client và Gọi API. Hãy xem cách mình xử lý một đoạn chat lộn xộn dưới đây.
1. Định nghĩa “khuôn mẫu” dữ liệu
Thay vì mô tả bằng lời, bạn dùng code Python thuần túy. Điều này giúp hệ thống của bạn có Type Hint đầy đủ.
from pydantic import BaseModel, Field
from typing import List, Optional
class UserInfo(BaseModel):
name: str = Field(..., description="Tên đầy đủ")
age: int = Field(..., description="Tuổi")
email: Optional[str] = Field(None, description="Email nếu có")
skills: List[str] = Field(default_factory=list, description="Các kỹ năng")
2. “Độ” lại Client và trích xuất
Thay vì dùng hàm patch() cũ, phiên bản mới nhất của Instructor khuyến khích dùng from_openai(). Cách tiếp cận này minh bạch và dễ debug hơn.
import instructor
from openai import OpenAI
# Khởi tạo client thông minh
client = instructor.from_openai(OpenAI(api_key="YOUR_KEY"))
text_input = "Chào bạn, mình là Nguyễn Văn A, 28 tuổi. Mình biết Python và JS. Email: [email protected]"
# Trích xuất dữ liệu trực tiếp vào object
user = client.chat.completions.create(
model="gpt-4o-mini",
response_model=UserInfo,
messages=[{"role": "user", "content": text_input}],
max_retries=3 # Tự động bắt AI sửa lỗi tối đa 3 lần
)
print(f"{user.name} ({user.age} tuổi) thạo các kỹ năng: {', '.join(user.skills)}")
Lúc này, user là một instance của Pydantic. Bạn có thể dùng IntelliSense để gọi thuộc tính mà không lo gõ nhầm tên key như khi dùng Dictionary.
Tại sao cơ chế Auto-retry lại quan trọng?
Trong môi trường thực tế, LLM đôi khi vẫn nhầm lẫn kiểu dữ liệu, ví dụ trả về tuổi là chuỗi “hai mươi tám”. Với Instructor, bạn không cần lo lắng. Khi Pydantic báo lỗi validation, thư viện sẽ tự động gửi thông báo lỗi chi tiết cho AI. AI sẽ nhìn vào lỗi đó để tự điều chỉnh output trong lượt retry tiếp theo.
Kinh nghiệm thực chiến khi đưa vào Production
Sau một thời gian dài áp dụng, mình rút ra 3 quy tắc vàng để tối ưu hiệu năng và chi phí:
- Ưu tiên Model nhỏ: Bạn không cần GPT-4o cho các tác vụ trích xuất đơn giản.
gpt-4o-minihoặcclaude-3-haikukhi kết hợp với Instructor cho độ chính xác tương đương nhưng rẻ hơn tới 20 lần. - Validator là vũ khí tối thượng: Hãy dùng
field_validatorđể kiểm soát logic nghiệp vụ. Ví dụ: Nếu tuổi trích xuất ra là số âm, hãy bắt AI làm lại ngay lập tức. - Giám sát số lượt Retry: Nếu một task thường xuyên phải retry đến lần thứ 3, đó là dấu hiệu cho thấy Prompt hoặc Schema của bạn đang quá phức tạp.
Hãy xem cách mình chặn đứng dữ liệu rác bằng Validator:
from pydantic import field_validator
class UserInfo(BaseModel):
name: str
age: int
@field_validator('age')
@classmethod
def validate_age(cls, v):
if v < 0 or v > 120:
raise ValueError("Tuổi phải từ 0 đến 120")
return v
Khi LLM trả về age: -1, Instructor sẽ bảo nó: “Này, tuổi không thể là số âm, hãy kiểm tra lại”. Đây là khả năng tự phục hồi (self-healing) mà các phương pháp parse JSON truyền thống không thể có được.
Chuyển sang Instructor giống như việc bạn nâng cấp từ làm thủ công sang dây chuyền tự động. Nó giúp bạn tập trung vào logic ứng dụng thay vì đi dọn rác cho AI. Nếu dự án của bạn đang gặp vấn đề về dữ liệu LLM không đồng nhất, hãy thử tích hợp nó ngay.
