Перейти к содержанию
Innovialabs

Как получать от LLM стабильный JSON-ответ

Практика3 мин

Коротко

Самый надёжный способ — ответ, ограниченный JSON-схемой (structured outputs), если модель и API его поддерживают; JSON mode гарантирует только валидный синтаксис, а одна инструкция в промпте — ничего. В любом случае проверяйте ответ по схеме в коде и повторяйте запрос при ошибке.

Три способа получить JSON

Когда ответ LLM читает не человек, а код, нужен предсказуемый JSON. Есть три уровня надёжности:

СпособЧто гарантируетРиски
Только промптНичего: модель старается следовать инструкцииЛишний текст, markdown-обёртка, пропущенные поля
JSON modeСинтаксически валидный JSONПоля и типы могут не совпасть с ожидаемыми
Ответ по схеме (structured outputs)JSON соответствует переданной схемеПоддерживается не всеми моделями и не всеми конструкциями схем

Выбор простой: если API поддерживает ответ по схеме — используйте его. Если нет — JSON mode плюс строгая валидация. Промпт без всего этого годится только для прототипа.

Ещё один вариант — tool calling (function calling): вы описываете «инструмент» со схемой параметров, и модель возвращает аргументы в виде структуры. Многие используют его именно как способ получить JSON.

Как писать промпт для JSON

Даже с JSON mode промпт важен — модель должна понимать смысл полей.

  • Покажите точную схему или пример объекта.
  • Опишите, что значит каждое поле и какие значения допустимы.
  • Скажите, что делать при отсутствии данных: null, пустой массив или специальное значение.
  • Попросите вернуть только JSON, без пояснений и без markdown.
Извлеки данные из заявки. Верни только JSON без пояснений:
{
  "name": string,
  "phone": string | null,
  "service": "web" | "mobile" | "bot" | "other",
  "budget_mentioned": boolean
}
Если поле не указано в тексте — ставь null.

Валидация: всегда проверяйте ответ

Валидный синтаксис ещё не значит правильные данные. Проверяйте ответ по схеме в коде — например, с помощью Pydantic в Python или Zod в TypeScript.

from typing import Literal, Optional
from pydantic import BaseModel, ValidationError

class Lead(BaseModel):
    name: str
    phone: Optional[str]
    service: Literal["web", "mobile", "bot", "other"]
    budget_mentioned: bool

def parse_lead(raw: str) -> Lead | None:
    try:
        return Lead.model_validate_json(raw)
    except ValidationError:
        return None

Схема в коде работает как единый источник правды: из неё же можно сгенерировать JSON Schema для запроса к API.

Повторный запрос при ошибке

Даже при хорошей настройке ответы иногда не проходят проверку. Рабочий паттерн:

  1. Отправить запрос, получить ответ.
  2. Провалидировать.
  3. При ошибке — повторить запрос, добавив текст ошибки валидации: «Ответ не прошёл проверку: поле service имеет недопустимое значение. Исправь и верни только JSON».
  4. Ограничить число попыток (обычно хватает одной-двух).
  5. Если всё равно не вышло — записать в лог и вернуть понятную ошибку или отправить на ручную обработку.

Не повторяйте бесконечно и не «чините» JSON регулярными выражениями — это скрывает проблему.

Частые ошибки парсинга

  • Markdown-обёртка. Модель возвращает JSON внутри блока кода с тройными кавычками. Решение: ответ по схеме или JSON mode; на крайний случай — аккуратно убрать обёртку перед парсингом.
  • Текст до или после JSON. «Вот результат:» перед объектом. Решение: явный запрет в промпте и валидация.
  • Обрезанный ответ. Лимит токенов закончился посреди объекта. Решение: увеличить лимит, проверять причину остановки генерации в ответе API.
  • Неверные типы. "true" вместо true, число строкой. Решение: схема и валидация, при необходимости — приведение типов на стороне кода.
  • Выдуманные значения. Модель заполняет поле, которого нет в тексте. Решение: разрешить null и прямо сказать, что угадывать нельзя.
  • Слишком сложная схема. Глубокая вложенность и десятки полей повышают риск ошибок. Решение: упростить или разбить на несколько запросов.

Частые вопросы

Да, хотя бы минимальная. Гарантия касается структуры, но не смысла: значение может быть формально допустимым и всё равно неверным. Кроме того, проверка защищает от изменений на стороне API и от обрезанных ответов.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.