Чтобы получать от нейросети JSON без пояснений, Markdown и текста вокруг объекта, используйте три уровня контроля: задайте однозначный контракт ответа, включите структурированный режим API, если он доступен, и проверяйте результат JSON-парсером вместе с валидацией структуры. Один только промпт снижает вероятность ошибки, но не гарантирует пригодность ответа для автоматической обработки.
Как должен выглядеть результат
Если приложение ожидает один JSON-объект, весь ответ модели должен состоять только из этого объекта:
{
"title": "Пример",
"priority": 2,
"published": true
}
Текст до объекта, Markdown-ограждения и синтаксические ошибки делают весь ответ непригодным для прямой передачи парсеру:
Вот результат:
{
"title": "Пример"
}
```json
{
"title": "Пример"
}
```
{
"title": "Пример",
}
JSON также требует двойных кавычек для строк и имён полей. Запись {'title': 'Пример'} не является корректным JSON.
Задайте однозначный контракт ответа
Фразы вроде «ответь в JSON» недостаточно: модель сама решает, какие поля вернуть, какие типы использовать и можно ли добавить пояснение. Вместо этого укажите пример объекта отдельно от правил для его полей:
Определи категорию сообщения.
Верни ровно один JSON-объект такого вида:
{
"category": "bug",
"confidence": 0.8,
"summary": "Краткое описание"
}
Правила:
- не добавляй текст до или после JSON;
- не используй Markdown;
- возвращай только поля category, confidence и summary;
- category может быть только bug, question или feature;
- confidence должно быть числом от 0 до 1;
- summary должно быть строкой.
Здесь значение "bug" является обычным примером, а допустимое перечисление описано отдельным правилом. Не записывайте "bug | question | feature" непосредственно в образец JSON: модель может воспринять всю строку с символами | как допустимое значение.
Для необязательных или отсутствующих данных тоже задавайте одно конкретное поведение. Например, если список сущностей всегда должен существовать, закрепите пустой массив как единственный вариант отсутствия результатов:
Если сущности не найдены, верни:
"entities": []
Не пропускай поле entities и не заменяй пустой массив на null.
Если поле допускает null, это также нужно определить явно:
{
"email": null
}
Не используйте для одной ситуации одновременно null, пустую строку и строку "unknown". Чем меньше вариантов представления одного состояния, тем проще обработка результата.
Инструкция «верни только валидный JSON» не является проверкой формата. Ответ, который приложение будет обрабатывать автоматически, необходимо сначала разобрать JSON-парсером, а затем проверить его структуру и значения.
Используйте структурированный вывод API, если он доступен
Некоторые API языковых моделей поддерживают отдельный JSON-режим, structured output или ограничение ответа JSON Schema. Такой механизм предпочтительнее одной текстовой инструкции, поскольку часть требований к формату задаётся средствами самого API.
Названия параметров, поддерживаемая часть JSON Schema и ограничения зависят от конкретного провайдера и версии интерфейса. Поэтому универсального фрагмента конфигурации для всех сервисов нет. Для используемого API следует проверить его официальную документацию и задать там ожидаемые типы, обязательные поля и допустимые значения.
Даже при структурированном режиме сохраняйте серверную проверку. Схема контролирует представление данных, но приложение всё равно должно проверять результат перед использованием.
Проверяйте синтаксис настоящим JSON-парсером
Не определяйте корректность JSON регулярным выражением, поиском фигурных скобок или визуальной проверкой. Передавайте исходную строку штатному парсеру без предварительного удаления Markdown и других попыток «починить» ответ.
Python
import json
raw = model_response
try:
data = json.loads(raw)
except json.JSONDecodeError as exc:
print(f"Invalid JSON: {exc}")
data = None
У стандартного json.loads() Python есть важное ограничение для строгой проверки стандарта JSON: по умолчанию декодер принимает специальные значения NaN, Infinity и -Infinity. Они не являются допустимыми числовыми литералами JSON. Если требуется отклонять такие константы, задайте parse_constant:
import json
def reject_constant(value):
raise ValueError(f"Invalid JSON constant: {value}")
try:
data = json.loads(
model_response,
parse_constant=reject_constant,
)
except (json.JSONDecodeError, ValueError) as exc:
print(f"Invalid JSON: {exc}")
data = None
Такой вариант подходит, когда необходимо проверять именно строгий JSON, а не расширенное поведение стандартного декодера Python.
JavaScript
let data;
try {
data = JSON.parse(modelResponse);
} catch (error) {
console.error("Invalid JSON:", error);
data = null;
}
JSON.parse() ожидает, что вся переданная строка представляет JSON. Пояснение перед объектом или Markdown-ограждение приведут к ошибке разбора.
После парсинга проверяйте поля и типы
Синтаксически корректный JSON ещё не означает, что модель выполнила контракт. Например:
{
"category": "something_else",
"confidence": "high",
"summary": 15
}
Этот объект можно разобрать как JSON, но все три значения нарушают ожидаемую схему. Минимальная проверка в Python может выглядеть так:
allowed_categories = {"bug", "question", "feature"}
if not isinstance(data, dict):
raise ValueError("Expected JSON object")
if data.get("category") not in allowed_categories:
raise ValueError("Unexpected category")
confidence = data.get("confidence")
if not isinstance(confidence, (int, float)) or isinstance(confidence, bool):
raise ValueError("confidence must be a number")
if not 0 <= confidence <= 1:
raise ValueError("confidence is out of range")
if not isinstance(data.get("summary"), str):
raise ValueError("summary must be a string")
Для более крупных контрактов обычно удобнее использовать JSON Schema или уже принятую в приложении систему моделей данных. Проверяйте как минимум обязательные поля, их типы, перечисления, диапазоны и ограничения бизнес-логики.
Не исправляйте ответ заменами строк
Попытки автоматически преобразовать почти правильный ответ часто создают новые ошибки. Например:
raw = raw.replace("'", '"')
Такая операция меняет не только кавычки синтаксиса, но и содержимое строк. Аналогично опасно вырезать всё между первой { и последней }: в тексте могут находиться несколько объектов или фигурные скобки внутри строкового значения.
Безопаснее считать неразбираемый ответ нарушением контракта. Если архитектура допускает повторную генерацию, отправьте модели краткое описание конкретной ошибки и снова проверьте весь результат тем же парсером и валидатором.
Например:
Предыдущий ответ нарушил контракт:
поле confidence должно быть числом от 0 до 1.
Верни заново ровно один JSON-объект:
{
"category": "bug",
"confidence": 0.8,
"summary": "Краткое описание"
}
category может быть только bug, question или feature.
Не добавляй Markdown и пояснения.
Для повторной попытки обычно достаточно назвать нарушенное поле, ожидаемый тип или допустимый диапазон. Нет необходимости переносить в промпт большие диагностические сообщения парсера.
Не смешивайте машинный формат и пояснение пользователю
Если одному процессу нужен JSON, а другому — человекочитаемое объяснение, не выводите их последовательно в одной строке ответа, который затем поступает в JSON-парсер.
Пояснение можно сделать частью самого контракта:
{
"result": "approved",
"reason": "Запрос соответствует заданным условиям."
}
Другой вариант — получать пользовательский текст отдельным запросом. В обоих случаях машинный канал остаётся однозначным.
Проверяйте контракт на пограничных входах
До подключения генерации к рабочему процессу проверьте несколько типов данных: обычный запрос, пустой ввод, многострочный текст, кавычки внутри исходных данных, Unicode, отсутствие обязательной информации и вход, способный спровоцировать поясняющий ответ.
Для каждого случая последовательность должна быть одинаковой:
- Получить исходную строку модели без исправлений.
- Передать её JSON-парсеру.
- Проверить ожидаемый корневой тип: объект, массив или другое разрешённое значение.
- Проверить обязательные поля и типы.
- Проверить перечисления, диапазоны и бизнес-ограничения.
- Использовать данные только после успешной валидации.
Так проверяется реальный контракт интеграции. То, что ответ визуально похож на JSON в интерфейсе или журнале, не означает, что программный обработчик сможет безопасно его принять.
Копируемый шаблон промпта
Выполни задачу и верни ровно один JSON-объект.
Пример структуры:
{
"status": "success",
"items": [
{
"name": "Пример",
"score": 0.8
}
]
}
Правила:
- возвращай только JSON без Markdown и пояснений;
- status может быть только success или unknown;
- name должно быть строкой;
- score должно быть числом;
- если элементов нет, items должен быть пустым массивом [];
- если данных недостаточно, используй status unknown и пустой массив items;
- не добавляй поля, не предусмотренные контрактом.
Замените названия полей, допустимые значения и правила отсутствующих данных требованиями конкретного приложения. Если API поддерживает структурированный вывод, перенесите формальные ограничения в его схему, а в промпте оставьте описание смысла данных.
Итоговый чек-лист
- Определён ожидаемый корневой тип JSON.
- Для каждого поля заданы тип и допустимые значения.
- Для отсутствующих данных выбрано одно однозначное представление.
- Пример JSON не содержит псевдозначений вроде
"a | b | c". - В промпте запрещены Markdown и текст вокруг объекта.
- При наличии structured output или JSON Schema ограничения задаются также средствами API.
- Исходный ответ проверяется штатным JSON-парсером.
- При строгой проверке в Python отдельно запрещены
NaNи бесконечности. - После разбора проверяются поля, типы, перечисления и диапазоны.
- Невалидный ответ не исправляется ненадёжными заменами строк.
- Повторная генерация проходит ту же валидацию заново.
Практический принцип прост: промпт описывает контракт, структурированный режим API ограничивает форму ответа, а парсер и валидатор решают, можно ли использовать результат как машинные данные.