Перейти к содержимому
28 окт. 2025 г.·7 мин чтения

Postmortem LLM после сбоя: какие поля стоит фиксировать

Практичный разбор того, как оформить postmortem LLM после сбоя: какие поля записывать, кто их заполняет и как превратить выводы в задачи релиза.

Postmortem LLM после сбоя: какие поля стоит фиксировать

Почему после сбоя детали быстро теряются

Сразу после сбоя команда хорошо помнит самую громкую часть проблемы. Упал JSON-ответ, выросла задержка, пошли 429, пользователи начали получать странный текст. Но память плохо держит порядок событий. Уже через час люди спорят, что случилось раньше: релиз, смена маршрута на другую модель, рост таймаутов или откат.

В LLM-системах это заметнее, чем в обычном веб-сервисе. Один запрос часто проходит через несколько слоев: приложение, API-шлюз, прокси, провайдера модели, кеш, фильтры безопасности. У каждого слоя свои часы, свои request ID и свой формат логов. Если команда использует единый шлюз, например AI Router, а потом смотрит еще и логи приложения и провайдера, одна и та же ошибка легко превращается в три разные версии одной истории.

После отката картина портится еще сильнее. Инженер вернул старый промпт, выключил feature flag, сменил модель, поправил лимиты, и система снова ожила. Для продакшена это правильно. Для расследования - нет. Исходное состояние исчезает быстро. К вечеру уже трудно восстановить, какая версия схемы ожидала JSON, какой системный промпт был в момент сбоя и какой маршрут выбрали для этого трафика.

Чаще всего в первый час теряются такие детали:

  • точное время первого симптома и момент, когда его заметили
  • номер релиза, версия промпта и активные флаги
  • request ID, по которым можно связать логи между системами
  • что именно сделал откат и что он изменил

Когда фактов мало, команда почти всегда уходит в спор о причине. Один человек винит модель, другой - новый парсер, третий - сеть или rate limit. Разговор тянется, а исправления откладываются. Разбор инцидента LLM ломается именно здесь: не на шаблоне, а на потере опоры под ногами.

Поэтому детали нужно фиксировать в первые минуты, пока у команды еще есть живая хронология. Иначе следующий релиз снова пройдет по той же цепочке, и спор начнется заново.

Что считать инцидентом в LLM-системе

Инцидентом стоит считать любой сбой, который меняет поведение продукта и бьет по пользователю, бизнесу или рискам. Это не только 500, таймауты и падение API. Если модель вдруг начала отвечать не в том формате, выросла доля выдуманных фактов или наружу ушли персональные данные, это тоже инцидент.

Для postmortem LLM лучше брать широкое правило: если система стала дороже, медленнее, опаснее или заметно хуже по качеству, случай нужно зафиксировать. Иначе команда помнит только "сервис не отвечал", а реальная причина уходит из памяти уже через день.

Частая ошибка - смотреть только на техническую доступность. LLM-система может вернуть 200 OK и при этом сломать продукт. Простой пример: чат успешно отдал ответ, но JSON не прошел парсинг, потому что модель добавила лишний текст. Формально запрос завершился, а по факту сценарий после релиза перестал работать.

Тихие сбои особенно опасны. Они редко шумят в мониторинге, но быстро портят метрики. Обычно это сломанный JSON или другой формат, которого приложение не ждало, рост галлюцинаций на типовых задачах, утечка PII или пропуск маскирования, скачок цены на запрос без пользы для качества и рост задержки, после которого пользователь просто бросает сценарий.

Сразу полезно отмечать, на каком слое началась проблема. Это экономит часы споров после релиза. В записи об инциденте лучше прямо указать, где случился сбой: в модели, в маршрутизации между моделями, в системном промпте, в tool calling, в постобработке ответа или в политике ретраев.

Иногда ломается не один слой, а связка из двух. Например, роутер перевел трафик на другую модель, новая модель стала хуже держать JSON-схему, а приложение не проверило ответ перед вызовом инструмента. Пользователь видит один сбой, но команда должна записать всю цепочку.

Зрелость тут видна по простому признаку: инцидентом считают не только отказ сервиса, но и любое отклонение, которое меняет результат для пользователя. Тогда следующий релиз проверяют не по одному статус-коду, а по реальному поведению системы.

Какие поля записывать сразу после сбоя

Первые 15-30 минут после сбоя решают, будет ли postmortem LLM полезным или превратится в набор догадок. Пока логи еще под рукой, а участники помнят детали, зафиксируйте сухие факты, без объяснений и выводов.

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

Потом опишите симптом глазами пользователя. Не "LLM работала некорректно", а конкретно: пустой ответ, JSON сломан, появились лишние поля, модель выдала текст не на том языке, таймаут вырос с 4 до 40 секунд. Один точный пример полезнее пяти общих фраз.

Дальше сохраните идентификаторы, по которым можно собрать трассу целиком: request_id или другой ID запроса, ID трассировки, затронутый API-ключ, имя сервиса или клиента, откуда пришел запрос, и 1-2 примера входа и ответа без чувствительных данных.

Этого уже хватает, чтобы не искать инцидент вслепую. Если трафик идет через шлюз вроде AI Router, полезно сохранить ID запроса на уровне шлюза и у провайдера, если он тоже его отдает.

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

Без контекста релиза картина тоже неполная. Укажите версию релиза, активные флаги, лимиты, недавние изменения в маршрутизации, схеме JSON, кешировании, модерации или маскировании PII. Даже маленькое изменение, сделанное за час до сбоя, потом часто оказывается причиной.

В конце оцените масштаб: сколько запросов задело, какие сервисы пострадали, какой регион или пул клиентов попал под сбой, была ли проблема только у одного провайдера или по всей цепочке. Если сразу видно, что инцидент затронул только один API-ключ или один маршрут, команда сэкономит часы на поиске.

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

Как собрать postmortem по шагам

Первые 30-60 минут после сбоя решают, получит ли команда ясную картину или набор догадок. В этот момент лучше не спорить о том, кто ошибся. Намного полезнее быстро зафиксировать факты, пока логи не ушли в ротацию, а память у людей еще свежая.

Рабочий шаблон postmortem обычно собирают так:

  1. Сначала фиксируют сухие факты: что сломалось, когда это началось, кто заметил первым, какой путь затронуло сильнее всего - чат, классификацию, JSON-ответы, retrieval или billing.
  2. Сразу выгружают следы инцидента: логи приложения, метрики по ошибкам и задержке, трассировки, несколько сырых запросов и ответов, версию промпта, модели и релиза.
  3. Потом сводят таймлайн по минутам. В него обычно попадают релиз, первый алерт, ручная проверка, рост 4xx или 5xx, переключение модели, откат и момент, когда сервис снова начал отвечать нормально.
  4. После этого проверяют объяснение на полноту. Причина должна объяснять не один симптом, а всю картину. Если теория объясняет только сломанный JSON, но не рост таймаутов и не скачок стоимости, значит, копать нужно дальше.
  5. В конце выводы превращают в работу. У каждого действия должен быть владелец, срок и понятный результат: добавить контрактный тест, заморозить схему ответа, ввести canary-релиз, обновить алерты.

Таймлайн лучше собирать из системных данных, а не по памяти. Люди часто путают порядок событий, особенно если ночью команда параллельно проверяла промпты, rate limits и fallback. Если трафик идет через один шлюз, удобно сверять время по audit-логам, модели, провайдеру и ключу. Это помогает быстрее понять, где начался сбой: в приложении, в маршрутизации или уже после смены модели.

Еще один прием - держать рядом 2-3 сырых примера. Один успешный запрос до релиза, один неуспешный во время инцидента и один после исправления. На такой тройке проще увидеть, что именно изменилось: формат system prompt, температура, схема JSON, длина контекста или маскирование PII.

Если после разбора у вас остался только вывод "надо быть внимательнее", шаблон не сработал. Результат должен быть конкретным: "до пятницы добавляем тест на валидный JSON для трех моделей, владелец - backend lead".

Кто заполняет шаблон и кто проверяет факты

Проверьте лимиты по ключу
Разберите 429 и всплески задержки по rate-limits на уровне ключа.

Один человек редко пишет точный postmortem после сбоя. Через пару часов люди уже путают время, последовательность действий и даже саму причину. Поэтому шаблон лучше делить по ролям. Каждый заполняет тот блок, где у него есть проверяемые факты.

Обычно один владелец документа собирает все части в один текст, а остальные отвечают за свои записи. Так команда быстрее отделяет хронологию от гипотез и не спорит о том, кто "помнит лучше".

Менеджер инцидента собирает хронологию: первый алерт, время эскалации, действия команды, обходные меры и момент, когда сервис снова работал нормально. Разработчик релиза описывает все, что изменил перед сбоем: код, конфиг, версию SDK, новый парсер ответа или смену маршрута на другую модель. ML-инженер проверяет модель, версию промпта, параметры запроса и результаты eval, а еще смотрит, совпадали ли тесты с реальным трафиком и не сломался ли формат ответа. Инженер платформы сверяет логи, таймауты, лимиты запросов, ретраи и ошибки на уровне API-шлюза. Если команда использует AI Router, он может дополнительно проверить audit-логи, маршрут, маскирование PII и то, не ушел ли трафик к другому провайдеру после изменения маршрутизации. Руководитель команды фиксирует риск до следующего релиза: назначает владельцев действий, сроки и условия, без которых выпускать релиз нельзя.

Проверку фактов тоже лучше разделять. Хронологию сверяют по алертам и логам, а не по памяти. Изменения релиза - по коммитам, флагам и конфигам. Выводы по модели - по ID модели, версии промпта и результатам тестов, а не по фразе "раньше работало лучше".

Кто утверждает итог

Финальный документ обычно держит менеджер инцидента или тимлид. Но ему не стоит в одиночку решать, что считать корневой причиной. Если команда спорит о каком-то пункте, лучше прямо пометить его как неподтвержденный и записать, какой лог, тест или эксперимент снимет вопрос.

Хороший шаблон заканчивается не общими словами, а именами. У каждого исправления есть владелец, срок и способ проверки перед следующим релизом. Иначе postmortem останется аккуратным файлом, а тот же сбой вернется через неделю.

Пример с релизом, который сломал JSON-ответ

В пятницу вечером команда включила новую модель на 20% трафика. Переключение прошло тихо: HTTP-статусы были нормальными, задержка не выросла, явных сетевых ошибок не было. Поэтому первые 15 минут все думали, что релиз прошел нормально.

Проблема всплыла в клиентском сервисе, который ждал строгий JSON с фиксированными полями. Новая модель начала отвечать в другом формате tool calling, и парсер стал падать. Для пользователя это выглядело как обычный сбой: запрос отправлен, ответ вроде есть, а действие не выполняется.

Такой случай легко спутать с сетью или таймаутами. Команда тоже сначала пошла по ложному следу: посмотрела ретраи, балансировщик, логи API. Но быстро стало ясно, что транспорт работал нормально. Старый маршрут возвращал JSON в ожидаемом виде, а новый - структуру, где аргументы инструмента были упакованы иначе.

Что записали в postmortem

В такой разбор стоит занести не общие слова, а конкретные поля: model ID, который включили в релиз, провайдера, через которого шли ответы, версию промпта, долю трафика в момент сбоя и sample response, на котором сломался парсинг.

Этого набора хватило, чтобы спор закончился фактами. Когда команда сравнила sample response новой и старой модели, причина стала очевидной: дело не в сети и не в SDK. Сломался контракт между ответом модели и кодом, который ожидал другой формат вызова инструмента.

Если команда работает через OpenAI-совместимый шлюз, такой как AI Router, эти поля особенно важно сохранять. Один и тот же эндпоинт может скрывать смену модели или провайдера, а для расследования это уже прямой след к причине.

На следующий релиз команда не стала полагаться на ручную проверку. Она добавила контрактный тест, который валит сборку, если модель отдает JSON не по схеме, включила canary только на 5% трафика и поставила отдельный алерт на рост ошибок парсинга. Это дешевле, чем искать виноватого в понедельник утром.

Ошибки, которые портят postmortem

Проверьте PII до продакшена
Используйте маскирование PII и audit-логи, когда разбираете спорные ответы модели.

Худший postmortem выглядит аккуратно, но ничего не объясняет. После него команда помнит только общее чувство: "что-то пошло не так", а в следующем релизе ловит тот же сбой еще раз.

Первая ошибка - расплывчатые формулировки. Фраза вроде "модель повела себя странно" бесполезна. Нужны наблюдаемые факты: какой запрос пришел, какой ответ вернулся, что ожидал сервис, где именно сломался поток. Если JSON не распарсился, так и пишите. Если модель ушла в другой формат, фиксируйте это, а не впечатление от сбоя.

Вторая ошибка - смешивать факты и догадки в одном абзаце. Когда рядом стоят "в 14:03 выросли 5xx" и "вероятно, провайдер поменял поведение модели", документ быстро теряет точность. Лучше разделять подтвержденные факты из логов, трассировок и метрик, гипотезы, которые команда еще проверяет, и решения, принятые во время инцидента.

Что часто забывают записать

Очень часто команда не сохраняет примеры входа и выхода, а потом спорит по памяти. Нужны хотя бы 2-3 реальных примера с маскировкой PII: имен, номеров, адресов, аккаунтов. Без этого трудно понять, сбой вызвал конкретный тип запроса, новая версия промпта или редкий ответ модели.

Еще одна частая дыра - стоимость инцидента. Ее почему-то считают "делом менеджеров", хотя без нее картина неполная. Запишите, сколько токенов ушло впустую, сколько запросов попало под деградацию, были ли штрафы по SLA, сколько часов команда потратила на ручную проверку, откат и разбор. Иногда 40 минут сбоя дают не только просадку по метрикам, но и два дня ручной работы саппорта.

И последняя ошибка самая простая: документ закрыли, а задачи никуда не попали. Если после разбора нет тикетов в бэклоге, владельцев и срока проверки, postmortem превращается в архивную заметку. Нормальный финал здесь очень простой: что меняем в коде, что меняем в тестах, какой алерт добавляем и кто проверит это перед следующим релизом.

Быстрый чеклист перед следующим релизом

Хостите open-weight модели
Поднимите Llama, Qwen, Gemma, DeepSeek или Phi, если команде нужна низкая задержка.

Команда часто повторяет старую ошибку не потому, что забыла выводы, а потому, что не превратила их в проверяемые действия. После любого сбоя нужен короткий набор проверок, который живет рядом с релизом, а не в архиве заметок.

Если прошлый инцидент сломал JSON-ответ, новый релиз должен доказать одно: такой же сбой больше не пройдет незаметно. Зеленый smoke-тест тут не спасет. Нужен тест на тот самый сценарий, с тем же форматом ответа, теми же параметрами запроса и тем же клиентским кодом, который упал в продакшене.

Перед выкладкой полезно пройтись по таким пунктам:

  • у каждой задачи после инцидента есть ответственный, срок и статус
  • тесты воспроизводят найденную поломку, а не соседний случай
  • мониторинг замечает повтор того же сбоя за минуты
  • команда заранее проверила откат и запасной маршрут
  • по инциденту есть один документ, где совпадают таймлайн, причина, фикс и открытые задачи

Часто команды ошибаются именно на проверке отката. Они думают, что он "и так сработает", но не проверяют зависимости, лимиты, формат ответа и таймауты. Если вы работаете через единый LLM-шлюз, например AI Router, стоит заранее убедиться, что при смене модели или маршрута сохраняются нужные ID, audit-логи и поведение клиентской интеграции.

Разбор инцидента полезен только тогда, когда он меняет выпуск релиза. Если после него появились тест, алерт, владелец задачи и проверенный план отката, документ сработал. Если остался только текст, команда снова будет чинить тот же сбой ночью.

Что делать дальше с шаблоном

Шаблон не должен расти после каждого сбоя. Если команда после каждого инцидента добавляет еще три поля, через пару месяцев его перестают заполнять нормально. Лучше держать одну короткую форму на 8-12 пунктов, которой хватает для решения перед следующим релизом.

Держите форму короткой

Анкета на двадцать с лишним вопросов редко помогает. Люди пишут общие фразы, пропускают детали или откладывают заполнение до вечера, когда память уже подводит. Оставьте только то, что помогает понять причину, оценить влияние и поставить один конкретный барьер от повтора.

Раз в месяц полезно открыть последние postmortem LLM и посмотреть, какие строки пустуют. Если поле не заполняют в нескольких разборах подряд, причина обычно проста: оно не нужно или вопрос сформулирован слишком размыто. В обоих случаях форму стоит сократить.

Добавляйте поля только по делу

Для LLM-сбоев обычных полей из DevOps-формы часто мало. Если на инцидент влияют маршрут запроса, провайдер или правила обработки ответа, добавьте в шаблон еще несколько строк: route или имя маршрута модели, provider, который ответил на запрос, content label, если маркировка повлияла на результат, и audit log, по которому можно восстановить ход событий.

Не тяните эти поля в форму просто для порядка. Они нужны тогда, когда без них нельзя отделить баг в коде от ошибки маршрутизации, лимита или политики обработки.

Если трафик идет через AI Router, имеет смысл сверять инцидент не только с логами приложения. Проверьте audit-логи, лимиты по ключу, маршрут модели и метки контента. На практике сбой часто выглядит как ошибка релиза, хотя причина проще: запросы ушли не туда, один ключ уперся в rate limit, или ответ пришел с другой маркировкой и сломал сценарий.

Командам в Казахстане удобно хранить такие записи рядом с данными по инциденту и журналами релизов, в одном рабочем контуре. Тогда проще быстро поднять версию промпта, конфиг маршрута, лог ответа и решение, которое команда приняла после сбоя.

Хороший шаблон живет после встречи, а не заканчивается на ней. Если через месяц форма снова распухла, режьте ее без жалости.