Надёжность · Средний уровень
Сколько попыток давать LLM на исправление структурированного ответа
Бесконечные повторы невалидного JSON увеличивают задержку и стоимость, но не гарантируют успех. Практическая стратегия — ограничить бюджет исправлений, различать типы ошибок и заранее определить резервный сценарий.
Почему «повторять до успеха» — плохая политика
Большая языковая модель (LLM) может вернуть синтаксически некорректный JSON, нарушить схему или выдать формально допустимые, но непригодные данные. Если отправлять один и тот же запрос снова без ограничений, система получает непредсказуемую задержку и потенциально неограниченный расход.
Повтор полезен только тогда, когда следующая попытка получает новую информацию: конкретную ошибку валидатора, сокращённый контекст или более строгий формат ответа. Одинаковые запросы при одинаковых условиях могут воспроизводить одну и ту же проблему.
Сначала классифицируйте ошибку
Не каждая ошибка заслуживает повторной генерации. Разделите сбои минимум на четыре класса.
| Класс | Пример | Действие |
|---|---|---|
| Синтаксис | Лишняя запятая, незакрытая кавычка | Разрешить одно исправление с точным сообщением парсера |
| Схема | Нет обязательного поля, неверный тип | Разрешить исправление с перечнем нарушений |
| Семантика | Дата раньше допустимого порога, взаимоисключающие значения | Повторять только при наличии однозначного правила исправления |
| Невосстановимая | Во входе нет нужных данных, запрос запрещён политикой, превышен контекст | Не повторять; сразу переходить к резервному сценарию |
Отдельно отмечайте инфраструктурные ошибки: тайм-аут, ограничение частоты запросов или временную недоступность сервиса. Они не являются ошибками JSON и должны обрабатываться собственной политикой повторов с задержкой и джиттером.
Шаг 1. Задайте бюджет до первого вызова
Бюджет должен ограничивать не только число попыток, но также суммарное время и, если возможно, расход токенов. Завершайте процесс при достижении любого лимита.
{
"max_generation_attempts": 3,
"max_repairs": 2,
"max_elapsed_ms": 12000,
"retry_on": ["json_syntax", "schema_violation"],
"stop_on": ["missing_source_data", "policy_rejection", "context_overflow"]
}
Это пример конфигурации. Значения не являются результатом внешнего теста. Для интерактивного интерфейса временной бюджет обычно важнее дополнительной попытки; для фоновой обработки допустим больший бюджет, если операция идемпотентна и её стоимость контролируется.
Шаг 2. Проверяйте ответ по слоям
- Отделите ответ модели от служебного текста. Предпочтительнее использовать нативный режим структурированного вывода, если он доступен.
- Разберите JSON стандартным парсером. Не исправляйте строки регулярными выражениями без последующей полной проверки.
- Проверьте JSON Schema или эквивалентный контракт.
- Примените бизнес-правила: диапазоны, допустимые переходы состояний, ссылки между полями.
- Сохраните код ошибки и безопасное диагностическое описание для следующей попытки.
Безопасная локальная проверка файла стандартными средствами Python:
python -m json.tool response.json > /dev/null
Команда только читает response.json и проверяет синтаксис. Нулевой код завершения означает корректный JSON, но ничего не говорит о соответствии схеме или бизнес-правилам.
Шаг 3. Передавайте модели минимальную ошибку
Запрос на исправление должен содержать контракт, полученный объект и конкретные нарушения. Не просите модель заново решать всю исходную задачу, если достаточно восстановить структуру.
Исправь объект по указанным ошибкам.
Верни только один JSON-объект без пояснений.
Ошибки:
- /items/0/quantity: ожидалось целое число больше 0
- /currency: обязательное поле отсутствует
Правила:
- не добавляй сведения, которых нет во входных данных;
- если значение нельзя восстановить, верни null только там,
где это разрешено схемой;
- сохрани корректные поля без изменений.
Не включайте в диагностический запрос секреты, полные журналы или персональные данные. Если исходный ответ может содержать недоверенный текст, передавайте его как данные с чёткими границами, а не как продолжение инструкций.
Шаг 4. Останавливайтесь, если прогресса нет
Помимо абсолютного лимита используйте раннюю остановку. Переходите к резервному сценарию, если выполняется хотя бы одно условие:
- повторилась та же ошибка по тому же пути схемы;
- число нарушений не уменьшилось после исправления;
- исправление удалило обязательные данные или создало более серьёзную ошибку;
- для заполнения поля требуется выдумать отсутствующий факт;
- исчерпан лимит попыток, времени или стоимости;
- ответ нарушает правила безопасности или политики обработки данных.
Практическое правило: первая попытка исправляет формат, вторая — последняя возможность устранить конкретные нарушения схемы. Если после неё объект невалиден, ещё один сходный запрос обычно хуже предсказуемого fallback.
Шаг 5. Определите резервный сценарий
Fallback должен быть частью контракта, а не импровизацией после сбоя. Подходящий вариант зависит от критичности операции:
- вернуть типизированную ошибку и предложить повторить действие;
- сохранить задачу в очередь для ручной проверки;
- использовать детерминированный парсер или шаблон для ограниченного набора случаев;
- вернуть частичный результат только при явном разрешении контракта;
- запросить у пользователя недостающие данные вместо их генерации.
{
"status": "needs_review",
"reason": "structured_output_invalid",
"attempts": 3,
"retryable": false
}
Такой объект — пример стабильного ответа системы, а не ответ модели. Его формирует приложение после исчерпания бюджета.
Воспроизводимая схема обработки
result = null
previous_errors = null
for attempt in range(1, max_generation_attempts + 1):
response = generate_or_repair(previous_errors)
parsed = parse_json(response)
if parsed.failed:
errors = classify_parse_error(parsed.error)
else:
errors = validate_schema_and_business_rules(parsed.value)
if errors.is_empty:
result = parsed.value
break
if errors.contains_nonrecoverable:
break
if errors.same_as(previous_errors):
break
if time_budget_exhausted():
break
previous_errors = errors
if result is null:
result = fallback()
Псевдокод намеренно не привязан к SDK. В рабочей реализации счётчик должен охватывать весь жизненный цикл операции, чтобы вложенные функции не запускали собственные неограниченные повторы.
Как проверить результат
Подготовьте локальный набор известных сценариев. Не называйте его доказательством качества модели: это проверка поведения вашей системы.
- Корректный JSON проходит без исправления.
- Сломанный синтаксис вызывает не более разрешённого числа попыток.
- Неверный тип поля возвращает точный путь и ожидаемый тип.
- Повторяющаяся ошибка приводит к ранней остановке.
- Недостающие исходные данные сразу активируют fallback.
- После исчерпания времени новый вызов модели не начинается.
- В логах нет полного содержимого чувствительных полей.
Для каждой операции регистрируйте: число генераций, класс финальной ошибки, длительность, факт ранней остановки и выбранный fallback. Стоимость фиксируйте только по фактическим данным используемого API, а не по предположениям.
Типовые ошибки
- Один общий лимит для всех повторов
- Сетевые повторы и исправления содержимого имеют разные причины. Разведите их счётчики, но ограничьте также общий бюджет операции.
- Повтор исходного промпта без диагностики
- Модель не получает информации о нарушении и может воспроизвести тот же ответ.
- Проверка только синтаксиса
- Валидный JSON может нарушать схему и бизнес-инварианты.
- Автоматическое заполнение отсутствующих фактов
- Структура становится валидной ценой недостоверных данных. Лучше вернуть контролируемую ошибку или запросить ввод.
- Слепое извлечение фрагмента между фигурными скобками
- Такой метод ломается на вложенных объектах и строках со скобками. Используйте JSON-парсер и структурированный режим API.
- Отсутствие идемпотентности
- Если результат запускает оплату, отправку или запись, повторная генерация не должна повторно выполнять побочный эффект.
Ограничения подхода
Лимит «два исправления» — стартовая эвристика, а не гарантия. Оптимальное значение зависит от модели, сложности схемы, длины ответа, режима структурированного вывода и требований к задержке.
Повтор не компенсирует противоречивую схему, неоднозначные инструкции или отсутствие данных. Если один и тот же класс ошибки часто встречается на разных запросах, исправлять нужно контракт, промпт или этап подготовки данных, а не увеличивать число попыток.
Для критических решений валидная структура также не подтверждает истинность содержания. Такие результаты требуют отдельной проверки по доверенным данным и, где необходимо, участия человека.
Итоговое правило
Начните с трёх вызовов на операцию: одна генерация и максимум два адресных исправления. Повторяйте только синтаксические и однозначные ошибки схемы. Останавливайтесь раньше при отсутствии прогресса, нехватке исходных данных или исчерпании временного бюджета. После лимита возвращайте заранее определённый fallback, а не запускайте ещё одну надежду.
Другие практические материалы собраны в руководствах Agent Lab Journal, а определения терминов — в глоссарии.