Перейти к содержимому
7 мин чтения

Что даёт лучшую отказоустойчивость LLM?

Сравниваем отказоустойчивость LLM при переключении провайдеров и на выделенных GPU: время возврата, совместимость, мощность и регионы.

Что даёт лучшую отказоустойчивость LLM?

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

Надёжность надо измерять четырьмя отдельными обещаниями

Один процент доступности скрывает разные поломки, которые клиент ощущает по-разному. HTTP-ответ за две секунды с неправильным форматом не делает чат доступным, как и идеально совместимая модель, до которой запрос стоит в очереди минуту. Перед выбором инфраструктуры зафиксируйте четыре отдельных показателя.

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

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

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

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

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

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

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

Автопереход сокращает паузу, если отказ распознан верно

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

Сетевой тайм-аут, HTTP 429, HTTP 500 и поток, оборвавшийся после первых токенов, требуют разных действий. RFC 9110 определяет заголовок Retry-After для ответа 503 как время или задержку, после которой клиенту стоит повторить запрос. Это полезный сигнал, но я не отдаю ему весь бюджет ожидания: провайдер описывает своё состояние, а не терпение клиента. Если Retry-After длиннее остатка клиентского срока, маршрутизатор должен выбрать другой разрешённый путь или завершить запрос контролируемой ошибкой.

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

Практический бюджет выглядит так. Допустим, канал чата должен показать полезный ответ не позднее чем через 8 секунд. Основной попытке можно дать 2,5 секунды до первого токена, маршрутизации и новому соединению 0,5 секунды, запасной модели 4 секунды, а последнюю секунду оставить на передачу и контролируемую деградацию. Эти числа служат примером расчёта, а не универсальной нормой. Их надо получить из фактических задержек вашего промпта и канала.

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

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

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

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

Совместимый API ещё не означает совместимый ответ

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

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

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

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

  • JSON проходит ту же схему без исправления свободного текста.
  • Разрешённые инструменты и условия их вызова не меняются.
  • Ответ не раскрывает скрытые инструкции и персональные данные.
  • Эскалация человеку срабатывает на тех же классах риска.
  • Длина и язык подходят каналу обслуживания.

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

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

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

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

Резерв GPU меняет внешний дефицит на внутреннюю очередь

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

Мощность надо считать по пиковому потоку, а не по среднему за сутки. Упрощённая проверка использует закон Литтла: требуемая одновременность примерно равна частоте запросов, умноженной на среднее время обслуживания. Если в аварийном режиме приходит 12 запросов в секунду, а модель занимает GPU в среднем 3 секунды, системе нужно около 36 одновременных слотов до поправки на разброс и служебные операции. Это иллюстрация формулы, не характеристика конкретной модели.

Среднее значение всё равно недостаточно. Длинные истории диалогов увеличивают время prefill, длинные ответы удерживают слот, а пакетирование меняет задержку нелинейно. Нужны измерения p95 для длины входа, длины выхода, времени до первого токена и полного времени на вашем сервере вывода. Затем команда задаёт запас под отказ части узлов и под поток, который раньше обслуживал внешний провайдер.

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

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

Часть ёмкости полезно держать недоступной обычному планировщику. Такой запас кажется пустой тратой до первого сбоя узла, но без него любая аппаратная потеря сразу повышает очередь. Размер запаса зависит от минимального отказавшего блока: если планировщик теряет целый сервер с несколькими GPU, резерв в долю одного ускорителя ничего не исправит.

Есть и время возврата после аппаратного сбоя. Запасной процесс на уже работающем узле стартует быстро. Новый узел без загруженных весов должен получить образ, веса и занять память, поэтому его восстановление может измеряться минутами. Точное время зависит от размера модели, хранилища и сервера вывода. Его нельзя обещать по результату тёплого теста.

Резерв GPU надёжнее автоперехода по совместимости и доступу к закреплённой мощности. Он слабее, когда весь пул стоит в одном месте или рассчитан без аварийного запаса. Покупка ускорителей без политики очереди лишь переносит отказ из чужого API в ваш балансировщик.

Региональный сбой проверяет независимость, а не число копий

Автопереход через один эндпоинт
AI Router направляет запросы к 500+ моделям 68+ поставщиков через совместимый API.

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

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

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

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

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

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

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

AI Router сочетает маршрутизацию между поставщиками с собственными open-weight моделями на GPU в Казахстане, а также поддерживает маскирование PII и аудит-логи. Это позволяет собрать разные пути за одним OpenAI-совместимым эндпоинтом, но независимость конкретной схемы всё равно надо подтвердить испытанием её региональных зависимостей.

Клиентский RTO начинается раньше инфраструктурного

Два пути без смены SDK
Смените base_url и сохраните текущие SDK, код и промпты для резервной маршрутизации.

Для владельца сервиса восстановление наступает, когда клиент снова может завершить задачу, а не когда метрика GPU стала зелёной. Поэтому технический RTO нужно связать с состоянием разговора, повтором инструментов и поведением интерфейса.

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

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

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

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

Требование локального хранения ведёт к GPU в разрешённом регионе и второму разрешённому месту, если оно существует. Когда второго места нет, честным резервом остаётся передача оператору, а не внешний API, нарушающий политику данных. Для короткого RTO при отказе API подходят заранее проверенные поставщики и тёплый локальный пул.

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

Гибридная схема даёт два разных способа восстановиться

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

Маршрутизатору нужны группы совместимости, а не просто упорядоченный список моделей. Внутри группы модели прошли одинаковые проверки JSON, инструментов и политики. Между группами меняется разрешённый набор намерений: например, запасная группа отвечает на справочные вопросы, но передаёт изменение договора оператору.

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

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

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

route: support-chat
deadline_ms: 8000
attempts:
  - pool: local-reserved
    first_token_timeout_ms: 2500
    compatibility_group: support-v3
  - pool: external-multi-provider
    first_token_timeout_ms: 3500
    compatibility_group: support-v3
    pii: masked
after_stream_started: return_controlled_error
on_capacity_exhausted:
  disable_tasks: [conversation_summary, draft_variants]
  preserve_tasks: [customer_reply, human_handoff]

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

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

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

Учение должно ломать путь, а не подменять модель

Локальный резерв на GPU
Держите чувствительные обращения на open-weight моделях в собственной GPU-инфраструктуре платформы.

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

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

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

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

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

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

Часто задаваемые вопросы

Сколько времени занимает автоматическое переключение LLM-провайдера?

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

Гарантируют ли зарезервированные GPU отсутствие очереди?

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

Можно ли считать две OpenAI-совместимые модели взаимозаменяемыми?

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

Что делать, если поток ответа оборвался после первых токенов?

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

Защищает ли второй поставщик от регионального сбоя?

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

Какой запас GPU нужен для клиентского сервиса?

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

Безопасно ли повторять запрос к другой модели после тайм-аута?

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

Когда выделенный GPU-пул выгоднее нескольких внешних API?

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

Нужно ли запасной модели уметь обрабатывать все обращения?

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

Как часто проводить учения по отказу LLM?

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