Інтеграція OpenAI Structured Outputs для парсингу відповідей
Structured Outputs гарантує, що відповідь моделі точно відповідає заданій JSON-схемі. На відміну від response_format: json_object (що просто просить повернути JSON), Structured Outputs забезпечує відповідність конкретній схемі через constrained decoding — модель фізично не може повернути невалідний JSON.
Базова інтеграція з Pydantic
from openai import OpenAI
from pydantic import BaseModel
from typing import Literal, Optional
client = OpenAI()
# Схема для добування даних
class Invoice(BaseModel):
vendor_name: str
invoice_number: str
date: str
total_amount: float
currency: str
line_items: list["InvoiceItem"]
vat_amount: Optional[float] = None
class InvoiceItem(BaseModel):
description: str
quantity: float
unit_price: float
total: float
Invoice.model_rebuild() # Необхідно для forward references
# Парсинг — гарантована відповідність схемі
def extract_invoice(text: str) -> Invoice:
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[
{"role": "system", "content": "Добути дані рахунку з тексту"},
{"role": "user", "content": text}
],
response_format=Invoice,
)
return response.choices[0].message.parsed # Відразу об'єкт Pydantic
Класифікація з Enum
from enum import Enum
class TicketCategory(str, Enum):
technical = "technical"
billing = "billing"
feature_request = "feature_request"
complaint = "complaint"
general = "general"
class TicketClassification(BaseModel):
category: TicketCategory
priority: Literal["low", "medium", "high", "critical"]
sentiment: Literal["positive", "neutral", "negative", "angry"]
requires_human: bool
summary: str
tags: list[str]
def classify_ticket(text: str) -> TicketClassification:
response = client.beta.chat.completions.parse(
model="gpt-4o-mini", # Structured Outputs доступні і в mini
messages=[{"role": "user", "content": f"Класифікуй тікет: {text}"}],
response_format=TicketClassification,
temperature=0,
)
return response.choices[0].message.parsed
Structured Outputs через JSON Schema (без Pydantic)
# Для мов без Pydantic або складних схем
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Дані продукту"}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "product_data",
"strict": True,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"in_stock": {"type": "boolean"},
"categories": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["name", "price", "in_stock", "categories"],
"additionalProperties": False,
}
}
}
)
import json
data = json.loads(response.choices[0].message.content)
Обмеження Structured Outputs
-
strict: TrueвимагаєadditionalProperties: Falseна всіх рівнях - Не підтримуються: nullable поля через
"type": ["string", "null"](використовуйтеanyOf) - Максимальна вкладеність: 5 рівнів
- Для рекурсивних схем — використовувати
$ref
Коли використовувати
| Сценарій | Метод |
|---|---|
| Добування даних з документів | Structured Outputs |
| Класифікація | Structured Outputs |
| Відповіді з передбачуваною структурою | Structured Outputs |
| Вільний JSON (невідома структура) | json_object mode |
| Прості відповіді | Звичайний текст |
Строки реалізації
- Базове добування з Pydantic: 0.5–1 день
- Комплексні вкладені схеми: 1–2 дні







