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

Почему тихие обновления замечают слишком поздно
Провайдер может поменять модель или правила ее работы без отдельного письма. Снаружи почти ничего не меняется: тот же endpoint, те же параметры, похожий стиль ответов. Команда смотрит на несколько удачных запросов и решает, что все в порядке.
Проблема в другом. Тихий сдвиг редко ломает систему сразу. Обычно он начинается с мелочей: модель хуже держит JSON, чаще пропускает поле, осторожнее отвечает на пограничные запросы или иначе режет длинный контекст. На глаз это легко пропустить, особенно если читать ответы как человек, а не проверять их по четким условиям.
Поэтому регрессии LLM живут дольше, чем хотелось бы. Внутри команды нет ощущения аварии, потому что средний ответ все еще выглядит "нормально". Но для продукта разница уже есть: парсер падает на 2% запросов, классификация путает соседние категории, а суммаризация теряет одну строку, без которой оператору сложнее принять решение.
Первые сигналы часто приходят не от инженеров. Их замечают пользователи, саппорт или бизнес-аналитики. Один клиент пишет, что бот стал отвечать расплывчато. Другой жалуется, что документ теперь разбирается через раз. Пока эти жалобы складываются в понятную картину, команда уже теряет несколько дней.
Разовый ручной просмотр тут почти бесполезен. Люди прощают модели ошибки, если ответ в целом звучит разумно. Еще хуже, когда проверку делает человек, который заранее знает "правильный" результат. Мозг достраивает недостающее и пропускает сбой.
Это особенно заметно в продакшене, где модель встроена в цепочку шагов. Если один ответ чуть меняет формат, следующая часть системы работает хуже, хотя сама модель по отдельности кажется приемлемой. Поэтому команды замечают проблему поздно по простой причине: они ищут большие поломки, а тихий сдвиг почти всегда начинается с маленьких отклонений.
Что считать регрессией
Регрессия - это не только грубая ошибка или явный сбой. Для продакшена это любое ухудшение по сравнению со вчерашним рабочим состоянием. Если модель решает ту же задачу хуже, дольше или дороже, это уже проблема.
У команд часто возникает ложное чувство безопасности: ответ выглядит "умно", значит все хорошо. Но пользователю нужен не умный текст сам по себе. Ему нужен точный результат в коротком сценарии: классифицировать обращение, заполнить поля, вернуть JSON, вызвать нужный инструмент без лишних слов.
Поэтому смотреть стоит не на абстрактное "качество", а на стабильность в повторяемых задачах. Если вчера модель в 95 случаях из 100 правильно выделяла номер договора, а сегодня в 88, это регрессия. Даже если ответы по-прежнему звучат уверенно.
Что ломается первым
Обычно сдвиг видно в нескольких местах:
- падает точность в коротких рабочих задачах, где раньше ошибок почти не было
- ответ чаще выходит не в том формате, который ждет система
- растет число лишних отказов, предупреждений и оговорок
- ломаются вызовы инструментов, аргументы функций или JSON
- увеличиваются задержка и расход токенов на тот же запрос
Это бьет не по "красоте" текста, а по бизнес-логике. Один лишний абзац может сломать парсер. Неверный тип поля в JSON может остановить цепочку обработки. Лишний отказ на безопасный запрос может снизить конверсию или добавить работы операторам.
Хороший пример - извлечение данных из заявки. Вчера модель возвращала короткий JSON без пояснений: имя, ИИН, сумма, срок. Сегодня она добавляет фразу вроде "я могу ошибаться" и иногда меняет формат даты. Для человека это мелочь. Для сервиса это уже поломка.
Когда это уже инцидент
Не ждите массовых жалоб. Если сдвиг повторяется на контрольном наборе и задевает сценарий с деньгами, документами, маршрутизацией заявок или ответом пользователю, это инцидент. То же касается роста задержки и токенов: смысл ответа может остаться тем же, но модель становится слишком медленной или дорогой.
Правило простое: если система стала хуже выполнять конкретную работу, которую вы уже считали надежной, у вас регрессия.
Как собрать контрольный набор
Начинайте не с придуманных примеров, а с логов. Возьмите 20-50 реальных запросов из продукта и очистите их от персональных данных. Такой набор почти всегда полезнее, чем красивые синтетические кейсы, потому что он отражает живую нагрузку, странные формулировки и привычки пользователей.
Для регрессий опасны не только сложные задачи. Модель часто ломается на простом: путает строгий JSON, перестает вызывать нужный инструмент или слишком рано обрывает длинный ответ. Поэтому набор должен быть неровным. Добавьте короткие запросы, длинные диалоги, двусмысленные формулировки и пограничные случаи, где модель уже ошибалась раньше.
Обычно хватает пяти типов кейсов: короткий вопрос с одним точным ответом, длинный контекст с важной деталью в середине, ответ в строгом формате, сценарий с вызовом инструмента и запрос с чувствительными данными, где вы проверяете маскирование PII или корректную метку контента.
Не стоит хранить по одному идеальному ответу на все случаи. Для части задач нужен эталонный ответ, а для части - простой критерий сбоя. Если модель должна вернуть JSON с полями status и amount, проверяйте наличие этих полей и валидность структуры. Если она должна выбрать один из трех классов, сравнивайте метку. Если она обязана использовать инструмент, фиксируйте сам факт вызова и его аргументы.
Для каждого кейса полезно записать четыре вещи: вход, ожидаемое поведение, способ проверки и причину, почему кейс вообще попал в набор. Через месяц это экономит много времени. Никто не будет гадать, зачем здесь старый диалог на 8 тысяч токенов или запрос с грубой опечаткой.
Если вы гоняете одни и те же кейсы через нескольких провайдеров, удобно держать это на одном совместимом слое. Например, через AI Router можно отправлять одинаковые запросы к разным моделям через один OpenAI-совместимый endpoint и быстрее видеть, где просела точность, формат или скорость, не меняя SDK, код и промпты.
И еще одно правило: если кейс нельзя проверить за секунды, он редко доживает до ежедневного прогона. Берите только то, что дает ясный ответ - прошло или нет.
Как проводить ежедневный прогон
Ежедневный прогон работает только тогда, когда в нем мало случайности. Зафиксируйте все, что влияет на ответ: системный промпт, шаблон пользовательского запроса, temperature, top_p, max tokens, seed, если он доступен, и точный маршрут до модели.
Если у вас есть слой маршрутизации, контролируйте не только имя модели, но и сам маршрут. Иначе вы сравните разные цепочки и получите шум вместо сигнала.
Запускайте один и тот же набор кейсов каждый день примерно в одно и то же время. Это не формальность. Нагрузка у провайдера, холодный кэш и фоновые работы часто меняют задержку и даже форму ответа. Когда запуск идет по расписанию, проще понять, где реальный сдвиг, а где обычный дневной разброс.
Хорошая схема сравнивает новый прогон сразу с двумя точками. Первая - вчерашний результат. Она ловит резкий скачок. Вторая - стабильная база, например лучший известный прогон за последние две недели. Она помогает заметить медленное сползание качества, когда модель день за днем теряет по 1-2%, а это долго выглядит как шум.
Сначала считайте все автоматически, а ручной просмотр оставляйте на потом. Обычно хватает четырех групп метрик: совпадение с эталоном для задач с точным ответом, доля отказов и пустых ответов, корректность формата и обязательных полей, а также задержка и стоимость на один кейс.
После этого инженеру не нужно читать весь прогон. Ему нужен список заметных отклонений: ответ стал длиннее на 40%, JSON перестал парситься, выросла доля отказов, классификация сменилась на соседний класс. Так команда тратит 15 минут, а не полдня на чтение почти одинаковых ответов.
Полезно задать разные пороги для разных задач. Для извлечения данных допуск обычно жесткий. Для суммаризации можно терпеть небольшие текстовые отличия, если смысл, структура и факты сохранились. Один порог на все сценарии почти всегда дает ложные тревоги.
Какие тревоги действительно помогают
Команда быстро тонет в шуме, если ставит тревогу на каждый странный ответ. Нужны сигналы, которые показывают сдвиг по одной понятной метрике и сразу ведут к проверке.
Первая тревога - прохождение формата. Если вчера модель возвращала валидный JSON в 98% контрольных кейсов, а сегодня упала до 93%, это уже заметная проблема. Пользователь увидит ее позже, когда формы, парсеры и цепочки вызовов начнут ломаться в разных местах.
Отдельно смотрите на долю отказов. Рост фраз вроде "не могу помочь", пустых безопасных ответов или ухода в слишком общий текст часто появляется после скрытого обновления у провайдера. Со стороны кажется, что модель просто стала осторожнее. Для продукта это потерянный сценарий.
Минимальный набор тревог обычно такой:
- падение прохождения формата ниже заданного порога
- рост доли отказов относительно своей обычной базы
- скачок медианной задержки и 95-го перцентиля
- рост стоимости ответа на том же наборе запросов
- ошибки вызова инструмента в отдельной категории
Задержку и цену часто недооценивают. Зря. Если тот же набор промптов вдруг стал отвечать на 800 мс дольше или тратить на 20% больше токенов, это уже сдвиг. Регрессии нередко сначала видны именно там, а не в явных жалобах на качество.
Ошибки вызова инструмента стоит считать отдельно от обычных текстовых сбоев. Модель может дать человеку вполне нормальный ответ и при этом сломать автоматический сценарий: не вызвать функцию, передать неверные аргументы или вернуть битый JSON. Это другой тип проблемы, и чинят его тоже по-другому.
Если вы сравниваете несколько моделей или провайдеров, полезно видеть эти сигналы в одной таблице. Тогда сразу понятно, сдвиг случился у одной модели, у конкретного провайдера или во всем потоке сразу.
Утром команде обычно хватает короткой сводки в рабочем канале: формат, отказы, задержка, цена и tool errors плюс разница со вчерашним днем. Пять строк читаются за минуту и часто спасают от неприятного сюрприза к обеду.
Пример из обычного продакшена
У команды есть бот поддержки. Он читает входящее обращение и возвращает JSON по шаблону: тип запроса, продукт, срочность, язык и тег очереди. Дальше этот JSON забирает CRM и раскладывает тикеты по нужным людям.
Несколько недель все идет ровно. Валидный JSON приходит почти всегда, ручная проверка нужна редко. Потом провайдер тихо меняет поведение модели, и бот начинает иногда пропускать поле priority.
Снаружи это почти не видно. Пользователь все еще получает ответ, тикет создается, но часть обращений уходит в общую очередь вместо срочной. Жалоб с утра нет, зато ежедневный прогон сразу показывает сдвиг: доля полных ответов падает с 99% до 93%, а на контрольных кейсах с короткими жалобами поле пропадает особенно часто.
Такой сбой легко пропустить, если смотреть только на то, "ответила модель или нет". Формально ответила. По делу - уже нет, потому что сломала контракт, на котором держится маршрут тикета.
Команда не ждет, пока накопятся живые инциденты. Она временно переводит поток на другой маршрут с той же схемой ответа и тем же промптом. Если у команды есть маршрутизация между моделями, это занимает минуты.
После этого инженеры спокойно разбирают причину. Они сравнивают вчерашние и сегодняшние ответы на одном наборе обращений и быстро видят разницу: новая версия модели чаще считает поле необязательным, если в тексте нет явного маркера срочности. Иногда она еще и пишет пояснение рядом с JSON, хотя раньше этого не делала.
Дальше уже без спешки решают, что менять первым: закрепить другой маршрут, ужесточить валидацию или переписать инструкцию так, чтобы модель не пропускала поле даже при слабом сигнале. Пользователи за это время могут вообще ничего не заметить.
Где команды ошибаются чаще всего
Самая частая ошибка - строить контрольный набор только из синтетических примеров и не смотреть на живые логи. На тестовом наборе все аккуратно: короткие запросы, ровный язык, понятный формат. В продакшене люди пишут с опечатками, смешивают русский и казахский, вставляют лишний контекст и ждут ответ в нужной форме.
Из-за этого утром команда видит "зеленый" отчет, а днем получает жалобы. Если чат помогает операторам банка, ритейла или колл-центра, десятки реальных обезличенных запросов из логов обычно полезнее, чем сотня вылизанных тестов.
Вторая ошибка - проверять один идеальный ответ вместо простого критерия. Для многих задач не нужен текст слово в слово. Нужен результат, который проходит проверку: модель верно выбрала категорию, не потеряла сумму, ответила на нужном языке, не придумала факт, вернула JSON без поломки.
Третья ошибка - сравнивать только со вчерашним днем. Это удобно, но мало. Если качество сползает две недели подряд, дневное сравнение может ничего не показать. Нужен более длинный ориентир: среднее или лучший результат за 7, 14 или 30 дней по тем же контрольным кейсам.
Еще один типичный промах - менять сразу все. В один день правят промпт, провайдера и параметры, а потом никто не понимает, что именно сломало ответ. Лучше держать простую дисциплину: один релиз - одна переменная.
Наконец, команды часто складывают все сбои в одну кучу. Из-за этого суммарная оценка может держаться, хотя формат ответа уже развалился, а извлечение фактов просело. Проще всего разносить ошибки хотя бы по пяти типам: фактическая ошибка, сломанный формат, лишний отказ, пропуск важной детали и ответ не на том языке. Такой разбор сразу показывает характер сдвига.
Ежедневный минимум, который реально работает
Регрессии часто видно уже в первые 15 минут рабочего дня. Для этого не нужен большой отчет. Нужен короткий ритуал, который команда делает каждый день до того, как пользователи заметят проблему.
Начните с небольшого smoke-набора. Обычно хватает 20-30 запросов: несколько простых вопросов, несколько задач на извлечение данных, один ответ в строгом JSON и пару кейсов с чувствительными правилами, где модель уже ошибалась раньше.
После прогона не читайте все подряд. Сразу отберите 10 самых заметных отличий по сравнению со вчерашним днем или последним стабильным запуском. Смотрите не только на смысл, но и на длину ответа, тон, лишние отказы, пропуск обязательных полей и странные добавления вроде новых дисклеймеров.
Отдельно проверьте два числа: долю отказов и долю сломанного формата. Если модель должна вернуть JSON, таблицу или набор полей, любая трещина видна быстро. Даже рост с 1% до 4% уже ощутимо бьет по продакшену.
Полезно вручную открыть два кейса с длинным контекстом. Короткие запросы часто проходят нормально, а проблемы всплывают там, где модель должна удержать несколько правил, длинную историю чата или большой фрагмент документа. Один кейс можно взять на суммаризацию, второй - на точное извлечение фактов.
Если у вас есть резервный маршрут, проверьте и его. Отправьте один и тот же запрос по основному и запасному пути и сравните ответы. В системах вроде AI Router это удобно делать через один и тот же endpoint: можно быстро прогнать одинаковые кейсы по нескольким провайдерам, а аудит-логи держать в одном месте. Когда провайдер тихо меняет поведение модели, такая проверка сильно экономит время.
Ежедневный минимум обычно выглядит так:
- короткий утренний прогон
- 10 заметных отличий на ручную проверку
- цифры по отказам и формату
- 2 длинных кейса
- 1 запрос через резервный маршрут
Если на любом шаге что-то поехало, не ждите вечернего отчета. Заморозьте выпуск, переключите часть трафика и разберите примеры, пока проблема еще маленькая.
Что сделать дальше
Начните не с полного покрытия, а с мест, где ошибка сразу бьет по пользователю. Обычно это 10-20 сценариев: извлечение данных из документа, ответ по базе знаний, классификация обращения, короткое резюме без выдумок. Если модель сдвинется именно там, команда увидит проблему до жалоб.
Эти сценарии и станут вашим первым набором на проверку. Не пытайтесь собрать идеальный комплект за один день. Для старта хватит кейсов, где у вас уже были спорные ответы, ручные правки или неожиданные скачки качества.
У набора должен быть владелец. Не "команда в целом", а конкретный человек, который каждое утро смотрит результаты, разбирает провалы и решает, что делать дальше: открыть инцидент, временно откатить маршрут, обновить порог тревоги или пометить кейс как шумный. Обычно на это хватает 15-20 минут.
И храните данные рядом. Когда тест падает, никто не должен собирать картину по кускам из чатов и логов. Для каждого падения достаточно одной карточки: исходный промпт, параметры вызова, ответ модели, метка проверки, дата, провайдер и результат прошлого прогона. Тогда видно не только сам сбой, но и его форму - длина ответа, формат JSON, лишний отказ или ошибка на пограничном кейсе.
На первой неделе хватит простого режима: утренний прогон, один владелец, понятный журнал падений и 10-20 рискованных кейсов. Через несколько дней станет ясно, какие контрольные кейсы ловят сдвиг рано, а какие только создают шум. Это уже хорошая база, чтобы замечать скрытые обновления раньше пользователей.
Часто задаваемые вопросы
Что считать регрессией у LLM?
Регрессия — это любое ухудшение по сравнению с вашим обычным рабочим состоянием. Если модель стала чаще ломать JSON, путать классы, отвечать дольше или тратить больше токенов на тот же запрос, у вас уже есть проблема, даже если текст выглядит "умно".
Почему ручной просмотр часто пропускает тихий сдвиг?
Потому что человек легко прощает модели мелкие ошибки. Ответ может звучать нормально, но продукт уже страдает: парсер падает, поле пропадает, инструмент не вызывается или дата приходит в другом формате.
Сколько кейсов нужно для первого контрольного набора?
Для старта обычно хватает 20–50 реальных запросов из логов после очистки персональных данных. Этого достаточно, чтобы поймать частые поломки и не превратить утренний прогон в долгую рутину.
Что лучше брать в набор: реальные логи или синтетические примеры?
Сначала берите живые логи, а синтетические примеры добавляйте потом. Реальные запросы лучше показывают опечатки, длинный контекст, смешение языков и странные формулировки, на которых модель чаще всего и сыплется.
Как проверять ответы, если идеальный текст может отличаться?
Не гонитесь за ответом слово в слово, если задача это не требует. Проверяйте то, что ломает продукт: метку класса, наличие обязательных полей, валидность JSON, вызов инструмента, язык ответа и отсутствие выдуманных фактов.
Какие метрики полезно смотреть каждый день?
Смотрите на четыре вещи: точность на простых задачах, долю отказов, корректность формата и задержку со стоимостью. Такой набор быстро показывает, стала ли модель хуже работать для системы, а не только для человека, который читает ответ.
Когда тихий сдвиг уже стоит считать инцидентом?
Не ждите массовых жалоб. Если контрольный набор стабильно показывает падение в сценарии с деньгами, документами, маршрутизацией заявок или ответом клиенту, сразу открывайте инцидент и ограничивайте риск.
Как проводить ежедневный прогон без лишнего шума?
Запускайте один и тот же набор каждый день примерно в одно время. Перед этим зафиксируйте системный промпт, шаблон запроса, temperature, top_p, max tokens, seed, если он есть, и сам маршрут до модели, иначе вы получите шум вместо сравнения.
Что делать, если модель внезапно начала работать хуже в продакшене?
Сначала переведите часть трафика на запасной маршрут, если он у вас есть. Потом сравните вчерашние и сегодняшние ответы на одном наборе кейсов и ищите конкретный сдвиг: пропавшее поле, лишний отказ, рост длины ответа или сломанный вызов инструмента.
Как не утонуть в ложных тревогах?
Не ставьте тревогу на каждый странный ответ. Лучше держать пороги по понятным метрикам, отдельно считать ошибки формата и tool calls, а утром смотреть короткую сводку по отклонениям от своей обычной базы.