Перейти к содержимому
12 окт. 2024 г.·6 мин чтения

Теневой трафик для проверки модели перед выпуском

Разберем, как запустить теневой трафик для проверки модели, собрать честные метрики и сравнить новую LLM с текущей без риска для пользователей.

Теневой трафик для проверки модели перед выпуском

Зачем нужна теневая проверка

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

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

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

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

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

  • длинные диалоги с историей на 20-30 сообщений
  • запросы со смешением русского и английского
  • вопросы с персональными данными, которые нужно маскировать
  • редкие, но дорогие ошибки в чувствительных темах

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

Когда ее запускать

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

После смены провайдера такая проверка почти обязательна. API может остаться OpenAI-совместимым, а поведение - нет. Одна и та же модель у двух провайдеров по-разному режет контекст, считает токены и реагирует на таймауты. Если команда переключает base_url, например через RU LLM на другого провайдера, стоит несколько дней гонять копии реальных запросов в фоне и смотреть, где ответы начинают расходиться.

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

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

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

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

Как пустить копию запроса в фоне

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

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

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

  • один и тот же system prompt и история диалога
  • одинаковые параметры генерации, например temperature и max tokens
  • те же вложения, найденные документы, tool calls и метаданные
  • один и тот же момент времени, если ответ зависит от внешних данных

Персональные данные лучше убирать до дублирования трафика, а не после. Замаскируйте ФИО, телефоны, почту, номера договоров и другие поля, по которым можно узнать человека. Для банков, телекома и госсистем это обычная гигиена. Если вы используете шлюз вроде RU LLM, маскирование PII и аудит-трейлы можно встроить прямо в маршрут обработки.

Логи держите раздельно. Не смешивайте боевой и теневой ответы в одном потоке событий, иначе аналитика быстро ломается. Удобная схема такая: обе записи получают общий request_id, но каждая ветка пишет свой model_id, задержку, число токенов, finish_reason, текст ответа и результат вызова инструментов. Тогда пары легко сопоставить и сразу видно, где новая модель лучше, а где хуже.

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

Как запустить проверку по шагам

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

Первый прогон разумно делать на малой доле трафика. Часто хватает 1-5% реальных запросов на 2-7 дней, чтобы увидеть картину по будням и в часы пик. Если модель дорогая или медленная, выборку можно сделать еще меньше. Смысл не в объеме, а в чистом сравнении.

Минимальная схема

  • Пользовательский запрос идет в текущую модель и обычным путем возвращается клиенту.
  • Та же копия запроса уходит в новую модель в фоне, без влияния на ответ пользователю.
  • Обе версии получают один и тот же промпт, историю диалога и внешние данные.
  • Для двух ответов вы сохраняете общий request_id, время, модель и версию промпта.
  • Спорные пары ответов попадают в отдельную очередь на ручной разбор.

Параметры генерации нужно зафиксировать до старта. Температура, лимит токенов, стоп-условия и системный промпт должны быть одинаковыми везде, где это возможно. Иначе вы будете сравнивать не модели, а разные условия вызова. Даже небольшая разница в лимите токенов иногда меняет итог сильнее, чем сама модель.

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

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

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

Какие метрики сравнивать

Погоняйте open-weight модели
Сравните текущий маршрут с моделями на российских GPU без новой интеграции.

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

Качество ответа

Главная метрика - доля полезных ответов по ручной разметке. Для каждого запроса разметчик ставит простой статус: "помог", "частично помог" или "не помог". Потом команда считает долю ответов из первой группы и отдельно разбирает спорные случаи.

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

Скорость и цена

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

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

Длину ответа и расход токенов тоже держите рядом. Слишком короткий ответ часто не решает задачу. Слишком длинный поднимает цену, задержку и риск лишних деталей. Чтобы сравнение было честным, фиксируйте одинаковые промпты, температуру и лимиты токенов. Иначе вы сравните не модели, а разные условия запуска.

Хорошая практика простая: смотреть метрики по одной и той же пачке реальных запросов и по одним и тем же правилам разметки. Тогда перед релизом видно, стала ли модель лучше для людей, а не только красивее в демо.

Пример на чате поддержки банка

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

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

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

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

Полезно смотреть и на долю диалогов, которые ушли бы на оператора. Например, текущая модель переводит на человека 18% случаев, а новая - 27%. Разница часто появляется из-за мелочей: новая модель хуже держит структуру, путает шаги по переводу и блокировке или слишком рано пишет "обратитесь в поддержку" вместо простого действия в приложении.

Где команды ошибаются

Оставьте один шлюз на весь тест
Ведите боевую и теневую ветки через общий OpenAI-совместимый эндпоинт.

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

Вторая ловушка - смотреть только на среднюю задержку. Пользователь не чувствует "среднее" значение, если каждый двадцатый ответ приходит слишком поздно. Для чата и поддержки p95 и p99 полезнее среднего, потому что именно хвост ломает диалог, вызывает повторы и добавляет работу операторам.

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

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

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

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

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

Считайте цену без сюрпризов
Мерьте стоимость теневых прогонов по ставкам провайдеров без наценки на API.

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

  • Один идентификатор запроса связывает основной и теневой ответ. Иначе вы не сопоставите качество, цену и задержку по одной пользовательской сессии.
  • Логи сохраняют текст запроса, время, версию промпта, версию модели и, если есть маршрутизация, провайдера.
  • Команда заранее фиксирует допустимые пороги: качество не ниже текущего уровня, p95 не растет выше согласованного уровня, стоимость на 1000 запросов укладывается в бюджет.
  • Спорные ответы не растворяются в общей статистике. Их сразу помечают для ручной оценки.
  • План отката лежит наготове до старта: кто переключает трафик, где меняется маршрут и как быстро возвращается старая модель.

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

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

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

Что делать после проверки

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

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

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

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

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

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

Если для основной и теневой ветки вы используете RU LLM, обе можно вести через один OpenAI-совместимый эндпоинт, не меняя SDK, код и промпты. Для команд, которым важны хранение логов в РФ и аудит по каждому запросу, это еще и упрощает проверку перед релизом.

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

Теневой трафик для проверки модели перед выпуском | RU LLM