В документации Google Gemini потоковые ошибки передаются как отдельные события SSE с полями code и message, а не как обычный финальный JSON-ответ. Это сразу определяет правильную архитектуру: чтобы единообразно управлять API OpenAI, Claude и Gemini, создайте внутренний LLM Gateway со стабильным контрактом, но не скрывайте различия в инструментах, потоковой передаче, ошибках и правилах обработки данных. Описание ошибок Gemini API подтверждает, что потоковый режим требует отдельной обработки событий.
Эта статья предназначена для:
- backend-разработчиков, поддерживающих приложения с несколькими моделями;
- платформенных команд, отвечающих за ключи, лимиты, аудит и бюджеты;
- DevOps- и архитектурных руководителей, которым нужен отказоустойчивый AI Gateway.
Шаг 1. Проведите инвентаризацию возможностей и данных
До выбора прокси, SDK или готового LLM Gateway зафиксируйте, что приложение действительно отправляет поставщикам. Разделите требования на технические и организационные.
Технический список должен включать:
- обычные текстовые сообщения и историю диалога;
- изображения, документы и другие мультимодальные входы;
- потоковую выдачу через SSE;
- вызов функций и внешних инструментов;
- структурированный ответ по JSON Schema;
- отмену запроса;
- повторную отправку;
- максимальный размер входа и ожидаемый размер ответа;
- требования к задержке до первого токена.
Отдельно опишите границы данных:
- Какие запросы можно направлять любому разрешённому поставщику.
- Какие данные должны оставаться в определённом регионе.
- Какие персональные или коммерческие сведения нужно маскировать.
- Какие данные запрещено передавать внешней модели без дополнительного согласия.
- Как долго разрешено хранить запросы, ответы и технические журналы.
Главная ошибка на этом этапе — принять похожие пользовательские сценарии за полностью совместимые API. Anthropic использует собственную структуру для tool_use, tool_result и причины завершения, а Google описывает вызов функций через отдельные этапы передачи декларации функции и результата. Поэтому внутренний слой должен унифицировать жизненный цикл операции, а не механически копировать поля одного поставщика в формат другого. Руководство Anthropic по tool use и документация Google по function calling показывают, почему адаптеры должны сохранять поставщицкую семантику.
Создайте рабочую матрицу до реализации:
| Возможность | OpenAI | Claude | Gemini | Что фиксировать в шлюзе |
|---|---|---|---|---|
| Текстовый запрос | Поддерживается | Поддерживается | Поддерживается | Единая внутренняя схема сообщений |
| Потоковый ответ | Событийная модель | События сообщения и причина остановки | SSE-события, включая ошибки | Адаптер событий и финальный статус |
| Инструменты | Функции и инструменты API | tool_use и tool_result |
Function calling | Общая модель инструмента и расширения |
| Структурированный ответ | Проверять для конкретной модели и API | Проверять для конкретного режима | Проверять для конкретного API | Валидация после ответа |
| Политика данных | Зависит от продукта и настроек | Зависит от API и условий аккаунта | Зависит от режима Gemini API | Реестр региона и ограничений |
Названия моделей, параметры, лимиты и правила хранения необходимо проверять перед каждым существенным изменением. В качестве исходных точек используйте официальный справочник OpenAI API, документацию Anthropic API и справочник Gemini API. Не переносите параметры между поставщиками только потому, что они называются одинаково.
Шаг 2. Зафиксируйте внутренний API-контракт
Приложение не должно напрямую зависеть от конкретного имени модели поставщика. Вместо этого используйте логические псевдонимы:
general-fast;reasoning-primary;vision-standard;structured-output;coding-fallback.
В конфигурации LLM Gateway каждый псевдоним связывается с поставщиком, моделью, версией API, разрешёнными параметрами и политикой резервного маршрута. Это позволяет менять модель через контролируемую конфигурацию, не исправляя каждый бизнес-сервис отдельно.
Минимальный внутренний запрос может выглядеть так:
{
"model_alias": "general-fast",
"messages": [],
"tools": [],
"response_format": null,
"stream": false,
"timeout_ms": 30000,
"trace_id": "req_7f3a_example",
"tenant_id": "tenant_example",
"extensions": {}
}
Все значения здесь являются безопасными заполнителями. Реальные ключи доступа нельзя помещать в этот объект, клиентское приложение или репозиторий.
Внутренний ответ должен включать:
- нормализованный текст;
- список вызовов инструментов;
- статус завершения;
- фактического поставщика и модель;
- сведения об использовании токенов, если они доступны;
trace_id;- внутренний код ошибки;
- необязательное поле
provider_details, доступное только защищённой диагностике.
Для специфических параметров используйте явный объект extensions. Если поставщик поддерживает особую настройку, отсутствующую у других API, шлюз должен либо передать её соответствующему адаптеру, либо вернуть понятную ошибку несовместимости. Молчаливое удаление параметра опасно: приложение будет считать, что запрос выполнен с нужными условиями, хотя фактически модель их проигнорировала.
Рекомендуемая внутренняя классификация ошибок:
invalid_request— запрос не прошёл валидацию;authentication_failed— неверный ключ или недостаточные права;rate_limited— превышен лимит частоты или квота;provider_unavailable— временно недоступен поставщик;model_unavailable— модель отключена или не найдена;policy_blocked— результат остановлен политикой безопасности;timeout— превышен внутренний предел ожидания;tool_execution_failed— сбой внешнего инструмента.
Оригинальный HTTP-статус, тело ответа и идентификатор поставщика сохраняйте в защищённом журнале, но не возвращайте их напрямую бизнес-приложению. Иначе унифицированный интерфейс снова станет зависимым от конкретного формата OpenAI, Claude или Gemini.
Шаг 3. Разделите ключи, идентичности и окружения
Ключи OpenAI, Anthropic и Google должны находиться только на стороне шлюза. Клиентское приложение использует внутренние учётные данные, которые можно ограничивать по проекту, окружению, пользователю или организации.
Минимальная схема изоляции включает:
- отдельные секреты для разработки, тестирования и продакшена;
- доступ к секретному хранилищу только для процесса шлюза;
- запрет вывода ключей в логи и диагностические дампы;
- ротацию ключей без длительного перерыва;
- аудит административных изменений;
- привязку внутреннего токена к tenant или сервисному аккаунту.
Не используйте один ключ во всех средах. Компрометация тестового окружения не должна открывать доступ к рабочим квотам и журналам.
Пошаговая процедура управления API Key:
- Создайте отдельный секрет для каждого поставщика и окружения.
- Разрешите его чтение только сервису LLM Gateway.
- Исключите секреты из трассировок, сообщений исключений и переменных, доступных клиенту.
- Выпустите новый ключ до отзыва старого.
- Переключите шлюз на новый секрет и проверьте обычный запрос.
- Отзовите старый ключ после подтверждения работоспособности.
- Проверьте, что ошибка авторизации преобразуется во внутренний
authentication_failed. - Зафиксируйте дату ротации и ответственного администратора.
Права администратора также нужно разделить. Оператор маршрутов не обязан видеть содержимое запросов, а специалист по бюджетам не должен автоматически иметь возможность менять секреты. Для крупных команд полезно разделять роли управления ключами, маршрутами, лимитами и аудитом.
Шаг 4. Настройте детерминированную маршрутизацию
На первом этапе не пытайтесь выбирать «лучшую» модель для каждого запроса в реальном времени. Задайте предсказуемый маршрут:
general-fast → основной поставщик → разрешённый резерв
structured-output → только проверенные модели
vision-standard → модели с подтверждённым мультимодальным входом
coding-fallback → модели, прошедшие тесты на код
Псевдоним должен описывать бизнес-возможность, а не рекламное название модели. В реестре маршрутов храните поставщика, модель, версию API, регион, поддерживаемые входы, инструменты и ограничения.
Сначала соберите фактические показатели:
- задержку до первого события;
- общее время ответа;
- долю ошибок;
- число повторов;
- процент успешной валидации схемы;
- долю переходов на резервный маршрут;
- качество ответа на фиксированном тестовом наборе.
Только после этого добавляйте распределение нагрузки, маршрутизацию по tenant или выбор по типу задачи.
Тайм-ауты задавайте на нескольких уровнях:
- установка соединения с поставщиком;
- ожидание первого события;
- общий срок выполнения;
- вызов внешнего инструмента;
- ожидание передачи результата обратно приложению.
Повторять запрос можно не всегда. Генерацию текста обычно можно повторить при временном сбое, но операцию, которая создаёт запись, отправляет письмо или меняет состояние, нельзя автоматически дублировать без идемпотентности. Введите внутренний ключ идемпотентности и храните его вместе с trace_id.
Стратегия повторов должна учитывать:
- тип ошибки;
- возможность безопасного повтора;
- экспоненциальную задержку;
- случайное расхождение времени;
- максимальное число попыток;
- общий бюджет задержки.
Ошибка ограничения скорости, отказ авторизации и временный сбой поставщика требуют разных действий. Нельзя отправлять все статусы в один универсальный цикл повторов: это создаёт повторный шторм и увеличивает нагрузку именно тогда, когда система уже нестабильна.
Шаг 5. Определите правила автоматического fallback
Переключение на другую модель допустимо, если одновременно выполнены несколько условий:
- резервный маршрут поддерживает нужный тип входа;
- резервная модель понимает тот же инструмент;
- формат результата можно проверить тем же валидатором;
- операция безопасна для повтора;
- политика данных разрешает отправку запроса второму поставщику;
- ожидаемое качество выше установленного порога.
Если хотя бы одно условие не выполняется, шлюз должен вернуть контролируемую ошибку или попросить приложение повторить операцию вручную.
Не переключайте маршрут при каждом отклонении ответа. Ошибка политики, неподходящий формат запроса или некорректный инструмент не исчезнут после смены поставщика. Fallback предназначен прежде всего для временной недоступности, тайм-аута или ограничения квоты, а не для маскировки ошибок интеграции.
Зафиксируйте в журнале:
- основной маршрут;
- резервный маршрут;
- причину переключения;
- число попыток;
- итоговый статус;
- длительность;
- качество результата по тестовому валидатору.
Так вы увидите, действительно ли резервный маршрут повышает доступность или только скрывает неисправность основной конфигурации.
Шаг 6. Добавьте бюджеты, лимиты и наблюдаемость
Контроль расходов должен начинаться на уровне запроса. Для каждого tenant или проекта задайте:
- разрешённые псевдонимы моделей;
- максимальный размер входа;
- максимальный размер ответа;
- лимит запросов;
- лимит токенов;
- тайм-аут;
- доступные инструменты;
- действие после достижения бюджета.
Используйте два порога. Мягкий порог отправляет уведомление владельцу проекта, а жёсткий ограничивает новые запросы или переводит их на разрешённый недорогой маршрут. Не заменяйте модель автоматически без проверки качества: увеличение числа повторов и исправлений может сделать формально дешёвый маршрут более затратным.
| Поле журнала | Назначение | Требование к защите |
|---|---|---|
trace_id |
Связь приложения, шлюза и поставщика | Не содержит секрет |
tenant_id |
Распределение расходов и прав | Внутренний идентификатор |
| Поставщик и модель | Анализ реального маршрута | Не полагаться только на входной псевдоним |
| Время до первого события | Анализ потоковой задержки | Хранить отдельно от общего времени |
| Общая длительность и статус | Поиск тайм-аутов и отказов | Разделять ошибки шлюза и поставщика |
| Использование токенов | Расчёт бюджета | Отмечать отсутствие данных |
| Причина fallback | Оценка надёжности маршрутов | Не сохранять секретный ответ целиком |
Полные промпты и ответы не следует включать в общий производственный лог по умолчанию. Для отладки используйте маскирование персональных данных, ограниченный срок хранения и отдельный доступ. В большинстве случаев для технического аудита достаточно размера запроса, хэша содержимого, типа операции, статуса и метаданных маршрута.
Отслеживайте не только доступность, но и полезность:
- долю ответов, прошедших схему;
- успешность вызова инструментов;
- процент fallback;
- количество повторов;
- задержку до первого токена;
- долю прерванных потоков;
- расходы по tenant;
- частоту ошибок по модели и поставщику.
Шаг 7. Подготовьте приёмочные тесты
Перед запуском корпоративного AI Gateway используйте фиксированный тестовый набор. Он должен включать:
- обычный текстовый запрос;
- длинный контекст;
- структурированный ответ;
- одиночный вызов инструмента;
- несколько последовательных вызовов;
- потоковую передачу;
- отмену клиентом;
- превышение лимита;
- неверный ключ;
- тайм-аут;
- недоступность основного поставщика;
- переключение на резервную модель;
- заблокированный политикой запрос;
- ошибку внешнего инструмента.
Для каждого сценария определите ожидаемые:
- внутренний код;
- HTTP-статус;
- финальное событие;
- наличие
trace_id; - возможность повтора;
- запись в аудит;
- минимальное качество ответа.
Проверяйте не только синтаксис JSON. Резервная модель может вернуть формально правильный объект, но пропустить обязательное поле, использовать неверный тип аргумента или вызвать несуществующий инструмент. Поэтому после каждого ответа запускайте схему и бизнес-валидатор.
Для потокового режима клиент должен различать частичный текст, событие вызова инструмента, финальное событие и ошибку. Если ошибка возникла после передачи части ответа, нельзя автоматически считать операцию безопасной для повторной отправки.
Шаг 8. Сопровождайте модели через серый запуск
Поставщики меняют модели, версии API, ограничения и конечные точки. Бизнес-приложения не должны напрямую следовать каждому изменению имени модели. Используйте последовательность:
- обновите реестр возможностей;
- проверьте документацию поставщика;
- запустите фиксированный тестовый набор;
- направьте на новую модель ограниченную долю трафика;
- сравните качество, задержку, ошибки и переходы fallback;
- оставьте возможность быстрого отката;
- удалите старый маршрут только после подтверждения отсутствия зависимостей.
Регулярно пересматривайте:
- активные и неиспользуемые ключи;
- права доступа;
- срок хранения журналов;
- действующие лимиты;
- фактические расходы;
- долю трафика по псевдонимам;
- причины переключения;
- неиспользуемые модели и конечные точки.
Если шлюз разворачивается в удалённой среде для разработки и тестирования, заранее определите способ доступа, срок использования и процедуру удаления секретов. Для такого сценария можно изучить варианты аренды Mac mini, а перед выбором периода проверить условия тарифа. Для краткого цикла проверки интеграции это позволяет не покупать отдельное оборудование до подтверждения архитектуры.
Решение по архитектуре: какой вариант выбрать
Используйте условия ниже как рабочую схему принятия решения:
- Если у вас один поставщик, одно приложение и нет разделения бюджета по tenant, то начните с официального SDK и тонкого внутреннего интерфейса.
- Если приложение одновременно использует OpenAI, Claude и Gemini, то внедряйте LLM Gateway с адаптерами, псевдонимами моделей и общей схемой ошибок.
- Если требуется только маршрутизация и технический аудит, то не храните полное содержимое запросов и ответов без отдельной необходимости.
- Если используются инструменты, персональные данные или платные действия, то запрещайте автоматический fallback без проверки идемпотентности и совместимости.
- Если требования к региону обработки различаются, то создавайте отдельные маршруты и политики данных.
- Если нагрузка постоянная и предсказуемая, то оценивайте выделенную инфраструктуру с контролем сети, секретов и журналов.
- Если требуется только временная интеграция, миграционный тест или демонстрационная среда, то выбирайте окружение с ограниченным сроком доступа и заранее подготовленным чек-листом.
Прямые вызовы из нескольких приложений постепенно создают разрозненные ключи, разные правила повторов, непрозрачный бюджет и сложное расследование ошибок. Поэтому для постоянной платформы единый шлюз обычно оправдан. Однако при коротком тестовом цикле не всегда разумно сразу покупать физическую инфраструктуру: аренда Mac у ZavCloud может дать временную среду для проверки API, автоматизации и удалённого доступа без длительной привязки к простаивающему оборудованию. Для постоянной высоконагруженной системы сначала сравните срок эксплуатации, сетевые требования, требования к физическим интерфейсам и стоимость сопровождения; для валидации архитектуры заранее ограничьте период доступа и проведите все тесты из приёмочного списка.
ZavCloud Developer Infrastructure
Надёжная среда для вашего LLM Gateway
Арендуйте удалённый Mac в ZavCloud для разработки, тестирования и сопровождения приложений, работающих с несколькими поставщиками моделей.
Используйте удалённый доступ к Mac, чтобы проверять маршрутизацию запросов, потоковую передачу и обработку ошибок в единой среде.