Разработчики теперь могут контролировать стоимость исправления некорректного JSON, генерируемого большими языковыми моделями (LLM), ограничив количество попыток исправления двумя, как показывает простой цикл на Python. Этот паттерн — генерация, парсинг, валидация, повторная попытка, а затем принятие или отказ — превращает «возможно валидный JSON» в измеримый показатель успеха и предотвращает неконтролируемый расход токенов.
Почему цикл исправления имеет значение
LLM часто просят «вернуть JSON», однако результат часто содержит синтаксические ошибки, отсутствующие ключи или значения, нарушающие бизнес-правила. Зависимая система, ожидающая строго определенную структуру данных, аварийно завершится или выдаст неверные результаты, если получит такой вывод. Без систематического способа обнаружения и исправления этих проблем команды либо мирятся с высоким процентом ошибок, либо тратят деньги, многократно отправляя промпты модели, пока она не сделает всё правильно.
Три уровня валидации
Надежный цикл разделяет валидацию на:
- Синтаксис — парсится ли строка как JSON вообще?
- Структура — содержит ли объект верхнего уровня именно ожидаемые ключи?
- Семантика — соответствуют ли значения ограничениям предметной области (например, «category» должен принадлежать к предопределенному набору)?
Останавливаясь на первом же уровне, где произошла ошибка, цикл может передать модели точное сообщение об ошибке, что значительно повышает шансы на правильное исправление при следующей попытке.
Минимальный пример на Python
Следующий код использует только стандартную библиотеку. Он определяет крошечную схему (словарь с ключами category и summary) и фиксированный список разрешенных категорий.
import json
CATEGORIES = {"bug", "feature", "question"}
def validate(raw: str):
try:
value = json.loads(raw)
except json.JSONDecodeError as exc:
return None, f"syntax: {exc.msg}"
if not isinstance(value, dict):
return None, "shape: root must be an object"
if set(value) != {"category", "summary"}:
return None, "shape: expected category and summary"
if value["category"] not in CATEGORIES:
return None, "semantic: invalid category"
if not isinstance(value["summary"], str) or not value["summary"].strip():
return None, "semantic: summary must be text"
return value, None
Сам цикл исправления устанавливает жесткий предел попыток:
MAX_ATTEMPTS = 2
raw = model_response # initial LLM output
for attempt in range(MAX_ATTEMPTS + 1):
value, error = validate(raw)
if error is None:
break
if attempt == MAX_ATTEMPTS:
raise RuntimeError(f"failed after {MAX_ATTEMPTS} retries: {error}")
# Send the error and schema back to the model for a fix
raw = ask_model_to_repair(raw, error)
Если JSON проходит валидацию с первого раза, цикл немедленно завершается. В противном случае выполняется повторная попытка с передачей модели краткого набора данных: исходного вывода, точной строки ошибки и ожидаемой схемы. После двух неудачных попыток процесс прерывается с четким исключением.
Два правила для экономически эффективного исправления
Делайте промпты для исправления лаконичными — включайте только «сырой» JSON, сообщение об ошибке и схему. Добавление длинной истории чата увеличивает расход токенов и может запутать модель, повышая стоимость каждой попытки без улучшения точности.
Отделяйте валидацию от проверки фактов — парсер может обнаружить структурные проблемы, но он не может проверить, является ли утверждение в «summary» правдивым. Проверка фактов должна происходить на более позднем этапе; попытка «исправить» ложное утверждение лишь сделает ложь более аккуратной.
Измерение успеха
Логирование типа ошибки каждой попытки (синтаксис, структура, семантика) и того, завершился ли цикл успешно, дает конкретную метрику: долю ответов LLM, которые становятся пригодными для использования в рамках ограниченного количества повторных попыток. Команды могут отслеживать этот показатель со временем, сравнивать стили промптов или экспериментировать с различными определениями схем.
Потенциальные недостатки
Ограничение цикла означает, что некоторые некорректные выводы будут отброшены после достижения лимита, что может увеличить общий процент ошибок, если исходное качество модели низкое. В средах, где важен каждый ответ, разработчики могут предпочесть более высокий предел повторных попыток ценой дополнительных токенов. Компромисс очевиден: больше затрат ради более высокого охвата или более строгий бюджет с предсказуемым пределом.
На что обратить внимание в дальнейшем
- Промпт-инжиниринг для исправления — уточнение формата сообщения об ошибке может уменьшить количество необходимых повторных попыток.
- Альтернативные парсеры — некоторые библиотеки обеспечивают толерантный парсинг, который может автоматически исправлять мелкие ошибки; сравнение их стоимости с ограниченным циклом может быть полезным.
- Обновления моделей — новые версии LLM могут выдавать более чистый JSON «из коробки», что потенциально позволит еще больше снизить лимит повторных попыток.
Ограниченный цикл исправления JSON дает разработчикам практический инструмент для превращения нечетких выводов LLM в надежные данные без бесконтрольного роста затрат. Относясь к валидации как к полноценному этапу и ограничивая количество попыток, команды могут поддерживать в порядке как бюджеты, так и работу зависимых систем.
