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

Почему один провайдер начинает мешать
Один провайдер удобен на старте. Подключение быстрое, настроек мало, биллинг понятный. Но в продакшене такая простота превращается в зависимость от чужих лимитов, очередей и правил.
Проблема обычно проявляется не в спокойный день, а на пике. Трафик растет, маркетинг запускает акцию, контакт-центр массово отправляет звонки на суммаризацию, и внешний API внезапно отвечает медленнее или начинает резать запросы по rate limit. Для пользователя все выглядит просто: сервис дольше "думает", выдает ошибку или возвращает пустой ответ. Для команды это уже удар по SLA.
Даже короткий сбой быстро тянет за собой другие проблемы. Если LLM участвует в онбординге, поиске, поддержке или проверке документов, задержка в 10-20 секунд копится в очередях. Пользователи повторяют запросы. Нагрузка растет еще сильнее. Расходы тоже.
Ручное переключение редко помогает. Когда команда в спешке меняет ключи, base_url, модель или провайдера прямо в коде, почти всегда всплывают мелочи: другой формат ошибок, иные таймауты, отличия в tool calling, неожиданный лимит на контекст. На бумаге сервис уже "переключили", а в реальности часть сценариев сломалась.
Второй провайдер обычно нужен уже тогда, когда появляется хотя бы один из этих признаков:
- ошибки rate limit стали обычной частью работы, а не редким исключением;
- задержка ответа заметно меняется в разное время суток;
- один вендор не закрывает требования по данным, аудиту или размещению;
- вы не можете спокойно тестировать более дешевую или более сильную модель без риска для продакшена.
Для компаний в Казахстане и Центральной Азии есть еще один фактор. Если данные должны храниться внутри страны или нужны аудит-логи и маскирование PII, один зарубежный API становится не только техническим, но и организационным узким местом. В такой ситуации переход на несколько AI-провайдеров - это не "улучшение на потом", а обычная защита сервиса.
Зрелая команда не ждет аварии. Она заранее готовит запасной маршрут, сравнивает ответы моделей и настраивает переключение так, чтобы пользователь этого не заметил.
Что проверить до первого шага
Переезд чаще ломается не на самих моделях, а на деталях, которые команда давно перестала замечать. До первого теста полезно собрать точную картину: какие запросы идут в продакшен, какие модели их обрабатывают и где ошибка уже сейчас стоит денег или времени.
Начните со списка задач. Не "чат" или "аналитика" в общем виде, а конкретные сценарии: поддержка клиентов, суммаризация звонков, поиск по базе знаний, проверка документов. Рядом укажите модель, средний размер запроса, ожидаемую длину ответа и допустимую задержку. Часто уже на этом этапе видно, что одна дорогая модель закрывает все подряд, хотя половине задач хватило бы более дешевого варианта.
Дальше проверьте, что ваш код реально отправляет в API. Многие команды уверены, что используют только model и temperature, а потом находят top_p, response_format, seed, tools, max_tokens и системные инструкции, которые накопились в проекте кусками. Если не зафиксировать эти параметры заранее, сравнение провайдеров будет нечестным.
Отдельно посмотрите на сетевое поведение. Для перехода на несколько провайдеров мало ответа на вопрос "работает или нет". Нужно понимать, как сервис ведет себя под нагрузкой. Обычно хватает четырех проверок:
- какой таймаут стоит на запрос и хватает ли его для длинных ответов;
- сколько ретраев делает клиент и не дублируют ли они ретраи на стороне шлюза;
- какие лимиты действуют по ключам, пользователям и очередям;
- что происходит при 429, 500 и обрыве стрима.
После этого зафиксируйте базовую линию. Смотрите не на средние цифры, а на p95 задержки, цену на 1000 запросов, долю ошибок, долю пустых или оборванных ответов и качество на контрольной выборке. Иначе команда увидит красивую экономию, а потом получит рост жалоб из-за более слабых ответов.
Еще один слой проверки связан с данными. Если в запросах есть персональные данные, медицинские записи или банковские сведения, заранее решите, что можно отправлять наружу, что нужно маскировать и где должны храниться логи. Для компаний в Казахстане это часто влияет на всю схему миграции с самого начала, а не решается в последний момент.
Хороший сигнал готовности простой: у вас есть таблица сценариев, список реальных параметров запроса и понятная базовая линия по цене, задержке и ошибкам. Без этого любой переезд быстро превращается в спор мнений.
Как сохранить совместимость SDK
Самый безопасный ход при переезде - не трогать клиентский код без необходимости. Если приложение уже работает через OpenAI-совместимый API, чаще всего можно оставить текущий SDK и поменять только точку подключения и параметры запроса.
Для этого вынесите base_url, имя модели и ключи из кода в конфиг или переменные окружения. Тогда один и тот же сервис сможет ходить к старому провайдеру, к новому шлюзу или к резервной модели без отдельной ветки и без срочных правок перед релизом. На практике это снижает риск сильнее, чем многие разовые оптимизации.
Если команда уже использует OpenAI SDK, переход на OpenAI-совместимый шлюз обычно выглядит просто: меняется base_url, а остальной код остается прежним. У AI Router это как раз базовый сценарий: запросы можно направить на api.airouter.kz и продолжить использовать те же SDK, код и промпты.
Что проверить до переключения
Одного успешного запроса мало. Ошибки прячутся в деталях, которые не видны на демо.
Проверьте streaming: как приходят чанки, когда приходит признак завершения, что делает ваш парсер при пустом фрагменте. Затем проверьте tool calling: одинаково ли клиент собирает аргументы, имена инструментов и JSON-схемы. После этого сведите ошибки к одному виду: таймаут, rate limit, 4xx, 5xx, пустой ответ. И сразу добавьте единый request_id, который попадет в логи, метрики и заголовки.
Дальше соберите тонкий слой совместимости внутри своего кода. Пусть приложение вызывает один внутренний метод, а он уже решает, какой base_url использовать, как назвать модель, сколько ждать ответ и как разобрать ошибку. Тогда отличия провайдеров останутся в одном месте, а не разойдутся по контроллерам, воркерам и ретраям.
request_id нужен не для порядка в логах. Когда вы запускаете старый и новый маршрут параллельно, он помогает быстро понять, почему у одного запроса выросла задержка, где сломался streaming и какой ответ пришел от какой модели.
Есть простое правило: если SDK прошел обычный текстовый запрос, это еще ничего не доказывает. Первые проверки нужно делать на streaming, вызове инструментов и реальных ошибках. Именно там совместимость ломается раньше всего.
Пошаговый план переезда
Переход на несколько AI-провайдеров проходит спокойнее, когда у команды есть одна точка входа для всего трафика. Тогда маршрут запросов меняется в одном месте, а не в каждом сервисе, воркере и cron-задаче отдельно.
Если у вас уже есть OpenAI-совместимый шлюз, переход заметно упрощается. В случае с AI Router команда может сменить base_url на api.airouter.kz и дальше работать через тот же SDK и тот же формат вызовов. Это убирает лишние изменения в клиентской части и позволяет сосредоточиться на маршрутизации.
Рабочий порядок обычно такой.
- Сначала поставьте единый слой маршрутизации перед всеми LLM-вызовами. Это может быть внутренний gateway или внешний OpenAI-совместимый шлюз. Задача простая: весь трафик проходит через одну точку, где вы видите провайдера, модель, ошибки, задержку и стоимость.
- Затем подключите второго провайдера так, чтобы продуктовая логика не менялась. Не трогайте бизнес-правила, интерфейс и цепочки обработки ответа. На этом шаге меняется только маршрут под капотом.
- После этого включите теневой запуск. Пользователь по-прежнему получает ответ от старого маршрута, а копия того же запроса уходит новому провайдеру. Так вы собираете реальные данные по задержке, отказам и качеству без риска для продакшена.
- Если тень показывает нормальный результат, переведите на новый маршрут маленькую долю боевого трафика. Обычно на старте хватает 1-5%, но только для понятных сценариев без жестких SLA. Рост доли должен идти по расписанию, а не по ощущению.
- Все это время держите быстрый откат. Самый удобный вариант - один флаг или правило маршрутизации, которое за минуту возвращает 100% запросов на старую схему.
Не стоит усложнять этот этап. Не меняйте одновременно провайдера, промпты и формат ответа. Если вы тронете все сразу, команда не поймет, что именно сломалось. Гораздо спокойнее делать один заметный шаг за раз: сначала маршрут, потом проверка, потом увеличение доли трафика.
Как сравнить ответы до переключения
До переключения трафика соберите контрольный набор запросов и прогоните его по двум маршрутам: через текущего провайдера и через нового. Иначе вы будете сравнивать не модели, а разные условия. В наборе должны быть обычные запросы, сложные случаи и те ошибки, которые случаются редко, но обходятся дорого.
Не смотрите только на текст ответа. Сохраняйте рядом четыре вещи: сам ответ, задержку, расход токенов и коды ошибок. Уже на этом этапе часто видно, что новая схема пишет не хуже, но отвечает на 700 мс дольше или чаще падает на длинных входах.
Если вы меняете только base_url и сохраняете тот же SDK, сравнение получается чище. Код и промпты остаются прежними, а разница видна именно в маршруте и модели, а не в клиентской части.
Что сравнивать в каждом тесте
Текст лучше сравнивать по смыслу, а не по буквам. Две модели могут ответить разными словами и обе быть правы. Но для структурированных сценариев правила жестче. Если сервис должен вернуть JSON, проверьте четыре вещи:
- совпадает ли схема и набор полей;
- не пропали ли обязательные значения;
- парсится ли ответ без ручных правок;
- не изменились ли типы данных.
Это частая ловушка. Текст выглядит нормальным, а интеграция падает, потому что вместо числа пришла строка или модель добавила пояснение вне JSON.
Длинные диалоги тестируйте отдельно. На коротком запросе разницы может не быть, а на двенадцатом сообщении одна модель теряет контекст, начинает повторяться или забывает формат ответа. Отдельный набор полезно держать для редких кейсов: смешанный язык, опечатки, пустые поля, длинные документы, резкая смена темы.
Заранее задайте порог допустимого расхождения. Для чата поддержки можно принять 90% смыслового совпадения и не более 2% ошибок по JSON. Для скоринга заявок планка обычно выше: там даже редкая ошибка обходится дорого.
Нормальный рабочий подход такой: все спорные ответы сначала отбирает автоматическая проверка, а потом команда смотрит только отклонения выше порога. Так сравнение не растягивается на недели и не превращается в чтение тысяч почти одинаковых ответов.
Простой сценарий из практики
Представим команду, у которой есть бот для операторов контакт-центра. Он подсказывает ответы на частые вопросы: статус заказа, возврат, смена тарифа, лимиты по карте. Сейчас все запросы идут к одному провайдеру, и любая просадка по скорости сразу бьет по очереди операторов.
Команда не переводит весь поток сразу. Сначала она делит запросы на две группы. Сложные диалоги с длинным контекстом, спорными формулировками и высоким риском ошибки остаются у текущего провайдера. Простые и повторяемые вопросы уходят во второй маршрут в тени. Оператор по-прежнему видит основной ответ, а новый маршрут работает рядом и не мешает смене.
Такой мягкий режим почти всегда безопаснее резкого переключения. Теневой запуск показывает разницу на живом трафике, а не на тестах, где все обычно выглядит лучше, чем в реальной работе.
Для первой проверки часто хватает 10-20 частых сценариев из логов за последнюю неделю. Лучше брать не "чистые" примеры, а те, где бот уже ошибался: короткие реплики, опечатки, смешанные языки, резкая смена темы. Именно на них новый маршрут либо проходит проверку, либо быстро проваливается.
Обычно команда смотрит на несколько простых вещей:
- попадает ли ответ в правила компании и не придумывает ли лишнего;
- держит ли нужный тон для оператора;
- не выросло ли время ответа;
- не стала ли цена выше на одном и том же типе запроса.
Если у команды один OpenAI-совместимый вход для основного и теневого трафика, сравнение вести проще. Например, в AI Router оба маршрута можно держать в одном слое, а аудит-логи помогают разбирать одинаковые запросы по request_id. Но даже без отдельного шлюза логика та же: сначала сравнение, потом решение.
Переключение начинают только после стабильной серии. Например, новый маршрут три дня подряд не хуже по качеству, укладывается в нужную задержку и не дает всплеска спорных ответов на частых сценариях. После этого можно перевести 5% реального трафика, потом 20%, и только затем основную долю.
Такой путь кажется медленным. На деле он часто экономит неделю разборов после неудачного релиза и не заставляет операторов вручную исправлять ошибки бота.
Где команды чаще ошибаются
Самая частая ошибка проста: команда пытается поменять все сразу. Тогда миграция быстро становится нервной и плохо управляемой. Гораздо надежнее перевести один поток запросов, например только внутренний поиск или только суммаризацию обращений, и посмотреть на задержку, цену и долю ошибок на живой нагрузке.
Вторая ошибка ломает проверку качества еще до запуска. Команды сравнивают ответы на разных промптах, с разными системными инструкциями или даже с разной температурой. После этого спорят о том, какая модель "лучше", хотя тест изначально нечестный. Для сравнения нужен один и тот же набор входных данных, одинаковые настройки и понятные метрики: точность по задаче, длина ответа, задержка, цена и число отказов.
Проблемы часто начинаются и на уровне трафика:
- один провайдер держит высокую нагрузку, другой режет запросы намного раньше;
- лимиты считаются по токенам, минутам или ключам по-разному;
- команда не закладывает ретраи и резервный маршрут;
- в логах нет кода ошибки и причины переключения.
Из-за этого теневой режим выглядит стабильным на тесте и сыпется в первый рабочий день. Если вы меняете только base_url и сохраняете совместимость SDK, это еще не значит, что поведение провайдеров совпадает. Нужны свои rate limits на уровне ключа, очереди и понятное правило, когда система повторяет запрос, а когда сразу уходит на запасной маршрут.
Еще один частый промах - слабый аудит. Команда хранит только итоговый ответ, но не сохраняет модель, провайдера, время, число токенов, причину ошибки и сам факт переключения. Потом невозможно понять, почему цена выросла на 18% или почему часть запросов ушла в таймаут. Без таких логов вы не сравните провайдеров честно и не найдете источник сбоев.
Отдельно стоит вопрос хранения данных. Для банков, телекома, медицины и госсектора это не формальность. Если запросы содержат персональные данные, их нельзя отправлять куда попало только ради более низкой цены. В Казахстане команды обычно сразу проверяют data residency, маскирование PII и аудит-логи. Если для этого нужен один вход к нескольким моделям, такие требования удобно закрывать на уровне шлюза. Например, у AI Router есть хранение данных внутри страны, аудит-логи, маскирование PII и ограничения на уровне ключа, но правила маршрутизации и состав данных все равно должна настроить сама команда.
Хороший признак зрелого переезда простой: сначала вы видите, куда уходит каждый запрос и почему, и только потом расширяете трафик.
Быстрые проверки перед переключением
За день до смены маршрута команда должна уметь перевести трафик одной настройкой, а не правкой кода в каждом сервисе. Если для смены провайдера вы все еще открываете репозиторий, собираете контейнер и ждете релиз, переключение без простоя под вопросом.
Надежная схема выглядит просто: приложение берет base_url, модель и правило маршрута из конфига, переменной среды или feature flag. Тогда меняется точка входа и логика выбора модели, а SDK, промпты и клиентский код остаются на месте.
Перед финальным шагом проверьте короткий список:
- мониторинг показывает не только среднюю задержку, но и p95, p99, долю ошибок, таймауты и обрывы потока по каждому маршруту;
- команда уже делала откат руками и знает, какой флаг вернуть, кто это делает и сколько минут занимает возврат;
- тестовый набор покрывает частые запросы, редкие сценарии, длинные диалоги, большие документы, пустые поля и пики нагрузки;
- финансы согласовали новую схему: лимиты, учет расхода по провайдерам, месячный инвойс и внутренние центры затрат;
- безопасность подтвердила правила по PII, логам, хранению данных и меткам контента, если они нужны по внутренним или местным требованиям.
Отдельно проверьте теневой запуск. Он часто выглядит "почти готовым", хотя сравнение шло только на удобных примерах. Нужны живые запросы из продакшена, пусть даже на малой доле трафика. Иначе новый маршрут пройдет демо, но начнет сыпаться на длинных промптах, нестабильных сетевых ответах или неожиданных форматах JSON.
Небольшой пример. Поддержка банка отправляет короткие вопросы, а внутренний поиск гоняет длинные документы с таблицами. Если вы тестировали только первый тип запросов, мониторинг покажет нормальную среднюю задержку. Но после переключения второй поток поднимет таймауты и ошибки парсинга. Такие вещи всплывают только тогда, когда тестовый набор похож на реальную нагрузку.
Если команда использует OpenAI-совместимый шлюз, перед запуском стоит один раз проверить SDK на боевом клиенте, а не в изолированном скрипте. Иногда мелкая разница сидит не в API, а в ретраях, таймаутах или разборе streaming-ответов.
Если хотя бы один пункт не закрыт, не переводите весь трафик сразу. Дайте сначала 5-10%, посмотрите на метрики 30-60 минут и только потом увеличивайте долю.
Что делать после запуска
Сразу после переключения не оставляйте систему "на автопилоте". В первые дни команда должна каждый день смотреть, куда ушли запросы, где сработал откат и почему он вообще понадобился: таймаут, рост цены, пустой ответ, сломанный формат или ухудшение качества.
Проблемы обычно видны не в общей сводке, а по маршрутам. Один провайдер может работать быстро на коротких запросах, но проседать на длинных. Другой держит качество, но дает слишком дорогой ответ на простых задачах. Если смотреть только на средние цифры, такие перекосы легко пропустить.
Настройте правила, а не ручное тушение
После запуска полезно закрепить понятные правила маршрутизации по цене, скорости и качеству. Не делайте их слишком сложными в первый день. Для старта хватает базовой логики: дешевый маршрут для простых задач, более сильная модель для сложных, запасной путь при ошибке или задержке.
Рабочий вариант обычно включает четыре вещи:
- лимит цены на тип запроса;
- порог по задержке, после которого запрос уходит на запасной маршрут;
- отдельный маршрут для задач, где качество важнее стоимости;
- логирование причины каждого переключения.
Если эти правила нигде не записаны, команда быстро скатывается к ручным исключениям. Через месяц уже никто не помнит, почему трафик идет именно так.
Зафиксируйте тестовый набор, на котором вы сравнивали ответы до релиза. Не меняйте его без причины. Этот набор пригодится для всех следующих изменений: новой модели, новой цены, нового провайдера или новых системных промптов. Иначе каждое следующее сравнение снова станет спором по впечатлениям.
Еще один практичный шаг - описать процедуру переключения для дежурной команды. Кто принимает решение, при каком проценте ошибок включают откат, где смотреть логи, как проверить деградацию качества, кто сообщает бизнесу. Лучше один короткий регламент на страницу, чем длинный документ, который никто не откроет ночью.
Если команде нужен один OpenAI-совместимый endpoint без переписывания SDK, такой слой лучше продумать заранее. Для команд в Казахстане это часто связано еще и с хранением данных внутри страны, аудит-логами, маскированием PII и требованиями местного законодательства. В такой схеме можно использовать AI Router: это единый OpenRouter-совместимый и OpenAI-совместимый API-шлюз, через который удобно маршрутизировать запросы между разными моделями и провайдерами, не меняя существующий клиентский код.
Часто задаваемые вопросы
Когда уже пора подключать второго AI-провайдера?
Второй провайдер нужен раньше, чем случится авария. Если 429 приходят регулярно, задержка гуляет по времени суток, а требования к логам, PII или хранению данных не закрывает один вендор, пора готовить запасной путь.
Обычно команда ждет слишком долго и начинает переезд уже под давлением SLA. Спокойнее подключить второй маршрут заранее и проверить его на живом трафике в тени.
Можно ли переехать без переписывания SDK?
Да, если вы уже работаете через OpenAI-совместимый API. Чаще всего хватает вынести base_url, модель и секреты в конфиг, а сам SDK, код вызовов и промпты оставить как есть.
Такой подход снижает риск: вы меняете точку входа, а не переписываете приложение перед релизом.
Что обычно ломается первым при смене провайдера?
Чаще всего первыми ломаются streaming, tool calling и обработка ошибок. Обычный текстовый запрос может пройти без проблем, а реальный сценарий упадет на пустом чанке, другом формате ошибки или неожиданном таймауте.
Сразу проверьте длинные ответы, обрыв стрима, 429, 5xx и разбор JSON. Именно там различия всплывают быстрее всего.
С чего начать миграцию, чтобы не запутаться?
Начните с карты реальных сценариев. Зафиксируйте, какие задачи вы гоняете в продакшене, какие модели их обрабатывают, сколько токенов уходит и какая задержка допустима для каждого случая.
Потом снимите базовую линию: p95, цену на один и тот же объем запросов, долю ошибок и качество на контрольной выборке. Без этого спор быстро уйдет в ощущения.
Как честно сравнить старый и новый маршрут?
Гоняйте один и тот же набор запросов через старый и новый путь при одинаковых настройках. Сохраняйте не только текст ответа, но и задержку, токены, коды ошибок и случаи, где ответ оборвался или не распарсился.
Для свободного текста смотрите на смысл, а не на буквальное совпадение. Для JSON проверяйте схему, обязательные поля и типы данных.
Нужен ли теневой запуск перед переключением?
Да, это самый спокойный способ. Пользователь продолжает получать ответ от текущего маршрута, а новый получает копию запроса и показывает, как он ведет себя на живой нагрузке.
Тень быстро вскрывает вещи, которых не видно на демо: длинные диалоги, редкие ошибки, скачки задержки и странности в форматах ответа.
Как подготовить быстрый откат?
Делайте откат через флаг или правило маршрутизации, а не через срочный релиз. Если для возврата на старую схему нужно лезть в код, вы уже проиграли время.
Перед запуском один раз отрепетируйте возврат руками. Команда должна знать, кто переключает трафик, где смотреть метрики и сколько минут занимает возврат.
Что делать с PII, логами и хранением данных?
Решите это до первой миграции, а не после тестов. Нужно заранее определить, что можно отправлять наружу, что надо маскировать, где лежат логи и кто имеет к ним доступ.
Для команд в Казахстане это часто влияет на всю схему с самого начала. Если нужен один вход с хранением данных внутри страны, аудит-логами и маскированием PII, такие правила удобнее держать на уровне шлюза.
Как безопасно увеличивать долю трафика после старта?
Не переводите весь поток сразу. Сначала дайте новому маршруту маленькую долю, например простые и повторяемые сценарии, и посмотрите на метрики хотя бы 30–60 минут.
Если задержка, цена и качество держатся ровно, увеличивайте долю по расписанию. Сложные кейсы с длинным контекстом лучше оставить на старом или более сильном маршруте до конца проверки.
Зачем вообще нужен единый шлюз вроде AI Router?
Единая точка входа убирает хаос. Команда видит, куда ушел каждый запрос, какая модель ответила, где сработал ретрай, почему система переключилась и сколько это стоило.
Если вам нужен OpenAI-совместимый шлюз без смены клиентского кода, AI Router закрывает такой сценарий. Он дает один endpoint для разных моделей и провайдеров, а для Казахстана полезны хранение данных внутри страны, аудит-логи, маскирование PII и биллинг в тенге.