Классификация и извлечение полей: JSON-режим
response_format и JSON Schema превращают модель в надёжный парсер. Как получать структурированные данные без регулярок и без сюрпризов.
Сергей Панов
Классификация и извлечение полей: JSON-режим
Извлечь из письма сумму, дату и контрагента; разложить тикеты по категориям; вытащить поля из счёта — классические задачи, где модель заменяет хрупкие регулярки. Ключ к надёжности — заставить её отвечать строго структурированным JSON.
response_format вместо «верни JSON»
Просьба «ответь в JSON» в тексте промпта работает через раз: модель то обернёт в ```json, то добавит комментарий сверху. Используйте параметр:
resp = client.chat.completions.create( model="qwen-pro", 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 реальных документов с эталонными полями и гоняйте по нему при смене модели или промпта. Извлечение — это тот случай, где метрику точности легко посчитать и легко улучшать.