AI-инжиниринг

Error Handling для LLM: hallucinations, timeouts, malformed output, fallbacks

Цели урока

  • Классифицировать типы отказов LLM: timeout, rate limit, malformed output, hallucination
  • Реализовать retry с exponential backoff, jitter и model fallback
  • Построить слой валидации output через Zod и JSON repair
  • Применять self-consistency и grounding check для обнаружения галлюцинаций
  • Спроектировать graceful degradation с иерархией fallback-ов

LLM API падает по-другому чем REST API. 429 - не ошибка, норма: подожди и повтори. 500 - часто временно: retry помогает. Но главная ошибка LLM невидима: модель вернула 200, JSON валидный - и при этом полностью солгала. Американский юрист в 2023 году подал иск с 6 несуществующими прецедентами, сгенерированными GPT. Судья заметил. Юрист получил штраф 5000 долларов. Модель не вернула ошибку. Она вычислила следующий токен.

  • Air Canada: чат-бот пообещал скидку на билет, которой не существовало - суд обязал компанию выполнить обещание бота
  • Chevrolet: бот-продавец согласился продать автомобиль за 1 доллар после prompt injection от покупателя
  • Samsung: сотрудники загрузили конфиденциальный исходный код в ChatGPT - утечка через training data
  • Stack Overflow: временно запретил GPT-ответы - 80% проверенных ответов содержали фактические ошибки

Почему «галлюцинация» стала инженерной проблемой

Термин **галлюцинация (hallucination)** пришёл из исследований natural language generation, где он описывал гладкий текст, который не соответствует источнику или попросту неверен. Когда LLM дошли до продакшена, это перестало быть академическим курьёзом: модель может вернуть 200 с валидным JSON и при этом выдумать факты, цитаты или API. Инженеры ответили, заимствуя паттерны надёжности из распределённых систем - **retries с backoff, fallbacks и circuit breakers** - и применяя их к вызовам LLM вместе с валидацией вывода, чтобы ловить уверенные, но ошибочные ответы. Error handling для LLM - это столько же про правдоподобный, но ложный вывод, сколько про таймауты и 429.

Предварительные знания

  • Structured Output: Getting LLMs to Return JSON, Schemas, and Typed Data

Режимы отказа LLM: timeout, rate limit, malformed output, hallucination

Обычные API возвращают ошибку или корректный ответ. Два исхода. LLM добавляет третий - **формально корректный, фактически ложный ответ**. Это не баг реализации. Это фундаментальное свойство вероятностной генерации.

429 при работе с OpenAI - не катастрофа. Это сигнал: притормози, подожди, повтори. 500 от API чаще всего исчезает через секунду. Но `finish_reason: 'length'` - это тихая бомба. Ответ выглядит нормально. JSON начался. Просто не закончился.

Тип отказаПримерОбнаружимость
TimeoutМодель генерирует длинный ответ, соединение обрывается через 30сЛегко - HTTP timeout
Rate limit (429)Превышен лимит запросов в минуту или токенов в минутуЛегко - HTTP status code
Malformed outputЗапрошен JSON, получен текст с markdown-обёрткой ```json...```Средне - нужен парсинг
HallucinationМодель уверенно называет несуществующую функцию APIСложно - нужна верификация
Partial responsefinish_reason: 'length' - ответ обрезан по max_tokensЛегко - проверка finish_reason

**finish_reason: 'length'** - одна из самых коварных ошибок. Ответ выглядит нормально, но обрезан на середине. JSON без закрывающей скобки, список без последних пунктов, код без return. Всегда проверяйте finish_reason перед парсингом.

Главный инсайт: error handling для LLM - это не только `catch`. Это **валидация каждого 200 OK**. Модель вернула успех - начинается настоящая работа. Является ли ответ полным? Соответствует ли формату? Не выдуман ли он?

Если API вернул 200 - всё хорошо

200 OK означает только то, что HTTP-запрос прошёл. Семантические ошибки - галлюцинации, truncated output, невалидный JSON внутри строки - в HTTP-статусе не отражаются

LLM генерирует вероятностный текст. Модель не 'знает', что солгала - она вычислила наиболее вероятный следующий токен. Валидный HTTP при этом гарантирован. Валидный смысл - нет никогда.

Почему error handling для LLM сложнее, чем для обычных REST API?

Retry-стратегии: exponential backoff, jitter, model fallback

429 от OpenAI - это не отказ. Это вежливая просьба подождать. Проблема в том, что 1000 параллельных запросов получили этот 429 одновременно. И если все они ретраят через ровно 2 секунды - сервер снова получает удар в 1000 запросов. Thundering herd. Сам себе создал DDoS.

Решение: **exponential backoff с jitter**. Задержка растёт экспоненциально (1с, 2с, 4с, 8с...), плюс случайный разброс. 1000 клиентов расползаются по времени. Нагрузка сглаживается. Именно так устроен retry в AWS SDK, в Google Cloud клиентах, в OpenAI SDK начиная с версии 4.

**Jitter** решает проблему thundering herd: если 100 клиентов получили 429 одновременно и все ретраят через ровно 2 секунды - они снова ударят сервер одновременно. Случайный разброс (jitter) распределяет ретраи во времени.

**Model fallback** - цепочка gpt-4o → gpt-4o-mini → claude-haiku - стандарт для production AI-бекенда. GPT-4o упал? Переключаемся автоматически. Claude дорого для простой задачи? gpt-4o-mini в 16 раз дешевле. Абстракция LLMProvider делает это переключение незаметным для бизнес-логики.

Для malformed output - отдельная стратегия: **retry с усилением промпта**. Первая попытка - обычный промпт. Ретрай - добавляется жёсткое требование: «Предыдущий ответ был невалидным JSON. Верни ТОЛЬКО JSON, без markdown-обёрток, без пояснений». Часто работает с первого ретрая.

Зачем добавлять jitter к exponential backoff?

Валидация output: Zod parsing, JSON repair, structured output

LLM генерирует текст. Бизнес-логика ожидает типизированные данные. Между ними - пропасть. Модель попросили вернуть JSON, она вернула что-то похожее на JSON, обёрнутое в ```json, с trailing comma перед `}`, и комментарием «Вот ваш результат:» в начале.

Слой валидации - это конвейер из трёх шагов. Сначала извлечь JSON из любой обёртки. Затем починить то, что можно починить. Затем прогнать через Zod-схему. Каждый шаг - отдельная линия защиты.

Для случаев, когда JSON «почти правильный» - пропущена запятая, лишняя запятая перед `}`, незакрытая кавычка - существует библиотека **jsonrepair**. Она покрывает 90% реальных случаев невалидного LLM output:

**Structured Output (strict: true)** решает проблему формата, но НЕ решает проблему содержания. Модель вернёт валидный JSON с sentiment: 'positive' - но sentiment может быть неправильным. Формат - это HTTP 200. Корректность - совсем другой вопрос.

Что делает Zod-валидация при обработке ответа LLM?

Детекция галлюцинаций: confidence scoring, self-consistency, grounding

В 2023 году американский юрист подал иск, в котором GPT сгенерировал 6 судебных прецедентов. Дела звучали убедительно, цитаты были оформлены правильно, номера дел - реалистичны. Ни одного из них не существовало. Модель не знала, что галлюцинирует. Она вычисляла вероятный следующий токен.

Галлюцинация - самый коварный тип ошибки. В production это не баг, а **системный риск**. Нет ни HTTP-статуса, ни exception, ни stack trace. Есть уверенный ответ с несуществующими фактами.

  • **Self-consistency** - задать один вопрос N раз с temperature > 0. Если ответы расходятся - модель не уверена
  • **Grounding check** - проверить, основан ли ответ на предоставленном контексте (RAG) или взят «из головы»
  • **Confidence scoring** - попросить модель оценить уверенность (0-1) и отклонить ответы ниже порога
  • **Cross-model verification** - запросить ответ у двух моделей и сравнить
  • **Fact extraction + lookup** - извлечь утверждения из ответа и проверить по базе данных

**Self-consistency с 3 запросами** стоит 3x. Для медицины, финансов, юридических документов - это оправдано: цена ошибки выше цены трёх вызовов API. Для менее критичных задач хватит grounding check - 1 дополнительный вызов за разумные деньги.

Как работает self-consistency check для обнаружения галлюцинаций?

Graceful degradation: fallback responses, cached answers, human handoff

Все ретраи провалились. Модель галлюцинирует. Timeout истёк. Что показывает система пользователю? Ошибку 500? Пустой экран? Или - честный, понятный ответ: «Не смогли обработать сейчас, передали специалисту».

**Graceful degradation** - это иерархия: от идеального к минимально приемлемому. GPT-4o с полным контекстом - идеал. Статичный заранее написанный ответ - минимум. Между ними - несколько ступеней, каждая из которых лучше ошибки.

**Пример для customer support бота:**

**Метрика source** - золото для мониторинга. 95% ответов из primary - всё в порядке. 20% из cache или fallback - что-то сломалось, нужно расследование. Это лучший ранний индикатор деградации качества AI-системы - задолго до жалоб пользователей.

Что является ПОСЛЕДНИМ fallback-ом в цепочке graceful degradation?

Если API вернул 200 - всё хорошо

200 OK означает только то, что HTTP-транспорт сработал. Галлюцинации, truncated output, семантически неверный JSON - всё это приходит с кодом 200

LLM - вероятностный генератор текста. Он не знает 'правды', он вычисляет наиболее вероятный токен. Формально успешный HTTP-ответ и семантически корректный контент - две независимые вещи. Поэтому каждый 200 нужно валидировать так же тщательно, как любую ошибку.

Итоги

  • LLM может вернуть 200 OK с галлюцинацией - проверка HTTP-статуса недостаточна
  • finish_reason: 'length' - обрезанный ответ, опасный для JSON-парсинга
  • Exponential backoff + jitter + model fallback (gpt-4o → gpt-4o-mini → claude-haiku) - защита от всех retryable-ошибок
  • Zod + jsonrepair - надёжный парсинг невалидного LLM output
  • Self-consistency (N запросов) и grounding check - обнаружение галлюцинаций
  • Graceful degradation: primary → secondary → cache → fallback → human handoff

Что дальше

Error handling защищает от технических сбоев. Но LLM может генерировать токсичный, небезопасный или манипулятивный контент - и это уже задача guardrails.

  • Guardrails: безопасность LLM — Input/output фильтрация, NeMo Guardrails, defense-in-depth
  • Observability AI pipeline — Мониторинг ошибок, quality drift, cost tracking в production
  • Стоимость и оптимизация — Self-consistency стоит 3x - когда оправдано, а когда избыточно

Связанные уроки

  • aie-07-structured-output — Битый JSON - ключевой отказ для обработки
  • aie-33-guardrails — Обработка ошибок подпирает работу guardrails
  • aie-30-rate-limiting-ai — Retry с backoff на 429 и таймаутах
  • net-66-resilience — Применяем retry, таймауты и circuit breaker
  • aie-29-cost-management — Retry без лимитов умножают стоимость
  • sd-03-scalability
Error Handling для LLM: hallucinations, timeouts, malformed output, fallbacks

0

1

Войти