Все статьи
Статья
29 июля 2026 г.7 мин

Классификация и извлечение полей: JSON-режим

response_format и JSON Schema заставляют модель отвечать в заданной структуре. Как получать структурированные данные без регулярок.

Сергей Панов


Классификация и извлечение полей: JSON-режим

Извлечь из письма сумму, дату и контрагента; разложить тикеты по категориям; вытащить поля из счёта — классические задачи, где модель заменяет хрупкие регулярки. Чтобы это работало надёжно, она должна отвечать строго структурированным JSON.

response_format вместо «верни JSON»

Просьба «ответь в JSON» в тексте промпта работает через раз: модель то обернёт в ```json, то добавит комментарий сверху. Используйте параметр:

resp = client.chat.completions.create(
model="qwen3.8-27b",
messages=[
{"role": "system", "content": "Извлеки поля из счёта. Верни JSON."},
{"role": "user", "content": invoice_text},
],
response_format={"type": "json_object"},
temperature=0,
)
data = json.loads(resp.choices[0].message.content)

С json_object модель возвращает JSON без обёрток. temperature=0 убирает вариативность — для извлечения это то, что нужно.

Строгая схема

Если модель и провайдер поддерживают JSON Schema — фиксируйте структуру полностью. Тогда не придётся проверять наличие каждого поля вручную:

schema = {
"type": "object",
"properties": {
"supplier": {"type": "string"},
"amount": {"type": "number"},
"currency": {"type": "string", "enum": ["RUB", "USD", "EUR"]},
"date": {"type": "string", "description": "ISO 8601"},
},
"required": ["supplier", "amount", "currency", "date"],
"additionalProperties": False,
}

enum для классификации особенно полезен: при строгой схеме модель не выдумает категорию вне списка.

Классификация: закройте варианты

Для разметки тикетов не оставляйте модели свободу — дайте закрытый список меток:

system = """Классифицируй обращение в одну из категорий:
billing | technical | account | other.
Если не уверен — other. Верни JSON: {"category": "...", "confidence": 0.0-1.0}."""

Поле confidence даёт порог для ручной проверки: всё, что ниже 0.7, отправляйте человеку.

Выбор модели

  • Простое извлечение и классификация — Flash-модели справляются и стоят копейки. Гоняйте батчами.
  • Сложные документы (многостраничные договоры, вложенная структура) — модель посильнее и с большим контекстом.
  • Vision нужен, когда данные в скане или картинке, а не в тексте — тогда модель, которая понимает текст и изображения (об этом отдельно).

Грабли

  • Числа как строки. Модель вернёт "amount": "1 000,50". Схема с "type": "number" заставит её нормализовать, но проверяйте: русский формат с пробелом и запятой она иногда путает. Просите точку и без разделителей разрядов.
  • Галлюцинация полей. Если поля нет в документе — модель может его выдумать. Инструктируйте: «отсутствующее поле — null, не угадывай».
  • null против пустой строки. Договоритесь заранее и пропишите в промпте, иначе получите вперемешку.
  • Повторы. Даже с json_object изредка прилетает битый JSON. Оберните json.loads в try и сделайте один повтор запроса — дешевле, чем усложнять парсер.

Соберите тестовый набор из 30–50 реальных документов с эталонными полями и гоняйте по нему при смене модели или промпта. Извлечение — это тот случай, где метрику точности легко посчитать и легко улучшать.