Lỗi 400 gây khó chịu
Bạn đã bật chế độ JSON (JSON mode) bằng cách sử dụng response_format={"type": "json_object"}, với kỳ vọng nhận được một phản hồi có cấu trúc sạch sẽ. Thay vào đó, API trả về lỗi 400 Bad Request. Đây là một trở ngại phổ biến khiến nhiều nhà phát triển lúng túng. Lỗi trông như thế này:
openai.BadRequestError: Error code: 400 - {'error': {'message': "'messages' must contain the word 'json' in some form..."}}
Tại sao điều này xảy ra
Hãy coi chế độ JSON như một rào chắn nghiêm ngặt hơn là một tính năng thông minh. Khi bạn bật nó, API buộc đầu ra của mô hình phải là mã JSON đúng cú pháp. Tuy nhiên, mô hình không phải là người đọc được suy nghĩ. Nếu prompt của bạn yêu cầu một cuộc trò chuyện thông thường nhưng cài đặt API lại bắt buộc cấu trúc JSON, cả hai sẽ xung đột.
Để ngăn chặn sự xung đột này, OpenAI áp dụng một bước kiểm tra an toàn đơn giản: ít nhất một tin nhắn trong yêu cầu của bạn phải chứa chuỗi "json". Nếu bạn quên điều này, API sẽ giả định rằng mô hình có thể cố gắng xuất ra văn bản thuần túy, điều này sẽ vi phạm ràng buộc JSON, vì vậy nó sẽ từ chối toàn bộ yêu cầu trước khi tiêu tốn bất kỳ token nào.
Cách khắc phục Prompt của bạn
Cách khắc phục rất đơn giản. Bạn cần yêu cầu mô hình sử dụng JSON một cách rõ ràng ở đâu đó trong lịch sử tin nhắn. Mặc dù bạn có thể đặt yêu cầu này ở bất kỳ đâu, nhưng việc thêm nó vào tin nhắn hệ thống (system message) là cách đáng tin cậy nhất để thiết lập kỳ vọng đúng ngay từ đầu.
Phương pháp 1: Tin nhắn hệ thống (Cách tốt nhất)
Xác định định dạng đầu ra trong hướng dẫn hệ thống của bạn. Điều này đảm bảo mô hình hiểu rằng mục tiêu chính của nó là tạo dữ liệu, không phải tán gẫu.
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "Bạn là một bot trích xuất dữ liệu. Luôn trả về kết quả ở định dạng JSON."},
{"role": "user", "content": "3 thành phố lớn nhất Nhật Bản theo dân số là gì?"}
],
response_format={"type": "json_object"}
)
Phương pháp 2: Tin nhắn người dùng
Nếu bạn không sử dụng tin nhắn hệ thống, chỉ cần đề cập đến định dạng trong yêu cầu trực tiếp của bạn. Việc kiểm tra của API không phân biệt chữ hoa chữ thường; "JSON" hoặc "json" đều hoạt động hoàn hảo.
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "Cho tôi danh sách 5 món ăn nhẹ lành mạnh. Định dạng: JSON."}
],
response_format={"type": "json_object"}
)
Triển khai đầy đủ bằng Python
Dưới đây là một đoạn mã xử lý yêu cầu về prompt và phân tích đầu ra một cách an toàn. Lưu ý cách chúng ta bao bọc lệnh gọi json.loads() để ngăn lỗi crash nếu đầu ra của mô hình bị cắt ngắn đột ngột.
import json
from openai import OpenAI
client = OpenAI(api_key="your_api_key")
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": "Trích xuất chi tiết người dùng vào một đối tượng JSON với các khóa: 'name', 'age', 'city'."
},
{
"role": "user",
"content": "Tôi là Sarah, một kỹ sư 32 tuổi đến từ Seattle."
}
],
response_format={"type": "json_object"}
)
# Chuyển đổi đầu ra dạng chuỗi thành một từ điển thực sự
raw_content = response.choices[0].message.content
data = json.loads(raw_content)
print(f"Dữ liệu đã phân tích: {data}")
except Exception as e:
print(f"Không thể xử lý yêu cầu: {e}")
Danh sách kiểm tra xác minh cần thiết
Trước khi đưa vào vận hành (production), hãy xác minh việc triển khai của bạn với ba bước kiểm tra sau:
- **HTTP 200 OK:** Nếu bạn thấy lỗi 400, hãy kiểm tra kỹ xem từ "json" có xuất hiện trong mảng `messages` của bạn hay không.
- **Finish Reason:** Hãy xem `response.choices[0].finish_reason`. Nếu nó là `length`, mô hình đã hết token và mã JSON có thể bị hỏng. Lý tưởng nhất nó nên là `stop`.
- **Giải pháp thay thế tốt hơn:** Để đạt được độ tin cậy 100% về schema, hãy cân nhắc sử dụng **Structured Outputs** (`response_format: { type: "json_schema", ... }`). Tính năng mới này không yêu cầu bạn phải đề cập đến "json" trong prompt và đảm bảo đầu ra khớp chính xác với các khóa và kiểu dữ liệu của bạn.
Mẹo phát triển
Việc xử lý JSON đúng cách có thể khá khó khăn. Ngay cả với chế độ JSON, mô hình đôi khi có thể thêm các dấu phẩy dư thừa hoặc thiếu dấu ngoặc đóng nếu nó đạt đến giới hạn. Tôi luôn sử dụng một công cụ như JSON Formatter & Validator tại ToolCraft trong giai đoạn gỡ lỗi. Nó giúp trực quan hóa các cấu trúc lồng nhau và phát hiện các lỗi cú pháp khó nhận ra trong nhật ký terminal lộn xộn.
Hãy nhớ rằng: Chế độ JSON khả dụng trên gpt-4o, gpt-4-turbo, và gpt-3.5-turbo-1106 (hoặc mới hơn). Nếu bạn cố gắng sử dụng nó với gpt-4 (bản gốc) hoặc các mô hình cũ hơn, API sẽ bỏ qua tham số hoặc báo lỗi.

