← Все гайды AI Release
EN Подписаться на @ai_release1

Как объединить несколько ИИ-провайдеров в один API: настройка OpenAI-совместимого роутера

Обновлено: 15.10.2026 · AI Release · @ai_release1
Как объединить несколько ИИ-провайдеров в один API: настройка OpenAI-совместимого роутера

Несколько ИИ-провайдеров сразу — это несколько API-ключей, несколько разных форматов запросов и несколько мест, где нужно править код при смене модели. OpenAI-совместимый роутер решает это так: вы поднимаете у себя один сервис, который принимает запросы в формате OpenAI API (стандартный JSON-формат чата: список сообщений с ролями system/user/assistant), а дальше сам перенаправляет их нужному провайдеру по вашим правилам. В результате все ваши клиенты — скрипты, чат-приложения, браузерные агенты, локальные ассистенты — ходят на один адрес вида `http://127.0.0.1:4000/v1` и используют один ключ, а вы меняете провайдера или модель правкой одного конфига, а не переписыванием кода. Гайд рассчитан на новичка: подойдёт для любой ОС, где вы умеете открыть терминал и запустить сервис (Linux, macOS, Windows 10/11), и для любой программы-клиента, у которой в настройках есть поля «base URL» и «API key».

Требования и подготовка

Иллюстрация к разделу «Требования и подготовка»
Иллюстрация к разделу «Требования и подготовка»

Чек-лист перед стартом:

Пошаговая инструкция

Иллюстрация к разделу «Пошаговая инструкция»
Иллюстрация к разделу «Пошаговая инструкция»

1. Создайте папку проекта и файл конфига. Например, `~/ai-router` и внутри `router-config.yaml`. Ожидаемый результат: файл существует и открывается редактором. Почему так: весь смысл роутера в том, что состав провайдеров описан декларативно — вы не трогаете код клиентов.

Пример:содержимое `router-config.yaml` (это шаблон, подставьте свои значения):

server:
  host: 0.0.0.0      # слушать все интерфейсы
  port: 4000

providers:
  - name: cloud_a                 # ваше внутреннее имя провайдера
    base_url: https://api.example-provider-a.com/v1
    api_key_env: PROVIDER_A_KEY   # ключ берём из переменной окружения
  - name: local_box
    base_url: http://127.0.0.1:8080/v1   # порт смотрите в настройках своего локального сервера
    api_key_env: PROVIDER_A_KEY

models:
  - alias: fast        # это имя будут запрашивать клиенты
    provider: cloud_a
    model: <имя-модели-у-провайдера>
  - alias: local
    provider: local_box
    model: <имя-локальной-модели>

2. Положите ключи в переменные окружения и запустите роутер. Ожидаемый результат: в терминале появляется строка вида `Listening on 0.0.0.0:4000` и процесс не завершается.

Пример:

export PROVIDER_A_KEY="sk-ваш-ключ"
python -m router --config ./router-config.yaml

Почему это работает: роутер читает конфиг, поднимает HTTP-сервер на порту 4000 и держит ключи в памяти процесса. Ключ из `api_key_env` не попадает в сам файл конфига — его безопаснее коммитить и передавать коллегам.

3. Проверьте, что порт слушается и роутер жив. Ожидаемый результат: команда печатает список моделей, среди них `fast` и `local` — это ваши алиасы, а не имена моделей провайдеров.

Пример:

curl http://127.0.0.1:4000/v1/models \
  -H "Authorization: Bearer sk-router-local-000"

Ключ `sk-router-local-000` — это ключ самого роутера, он придумывается вами и не равен ключам провайдеров. Почему так: клиент обязан передать заголовок `Authorization`, иначе роутер не поймёт, что запрос «свой».

4. Сделайте первый реальный запрос к чату. Ожидаемый результат: в ответе приходит JSON, где текст ответа лежит в `choices[0].message.content`.

Пример:

curl http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-router-local-000" \
  -H "Content-Type: application/json" \
  -d '{"model":"fast","messages":[{"role":"user","content":"Привет! Ответь одной строкой."}]}'

Почему это работает: вы отправили запрос в формате OpenAI, а роутер по алиасу `fast` нашёл нужного провайдера и перевёл запрос в его формат.

5. Повторите шаг 4, заменив `"model":"fast"` на `"model":"local"`. Ожидаемый результат: ответ приходит от второй модели, а адрес и ключ в команде не менялись. Это и есть главная выгода: один API — много провайдеров. Если вторым провайдером у вас локальная модель на телефоне или мини-ПК, пригодится гайд про запуск ИИ-модели локально на Android — такую модель тоже можно завернуть в роутер как отдельного провайдера.

6. Направьте на роутер своего постоянного клиента. В настройках приложения найдите поля base URL и API key и укажите `http://127.0.0.1:4000/v1` и ключ роутера. Для агента в браузере порядок действий описан в гайде про подключение ИИ-агента к Chrome. Ожидаемый результат: клиент перестаёт просить отдельные ключи и отвечает на запросы как обычно.

7. Добавьте правила выбора модели. Ожидаемый результат: у вас появляется логика «дешёвая модель по умолчанию, дорогая — по явному запросу», и это видно в конфиге, а не в коде.

Пример:добавьте в конфиг раздел с правилом по умолчанию:

routing:
  default_alias: fast
  fallback_alias: local   # сюда уйдём, если основной провайдер недоступен

Почему это работает: роутер сначала смотрит на явный `model` в запросе, а если его нет — берёт alias из правил. Так один и тот же код клиента обслуживает и обычные, и «страховочные» сценарии.

8. Проверьте поведение при недоступном провайдере. Ожидаемый результат: запрос по-прежнему завершается ответом, но уже от fallback-провайдера.

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

Возможные проблемы и решения

Иллюстрация к разделу «Возможные проблемы и решения»
Иллюстрация к разделу «Возможные проблемы и решения»

Проблема 1: ошибка вида `401 Unauthorized`.Симптом: в ответе JSON с полем `error` и текстом про invalid API key. Решение: сначала проверьте ключ роутера — он должен совпадать с тем, что вы придумали, и передаваться в заголовке `Authorization: Bearer ...`. Если ключ роутера верный, проблема в ключе провайдера: убедитесь, что переменная окружения (например, `PROVIDER_A_KEY`) реально задана в том же терминале, где запущен роутер — команда `echo $PROVIDER_A_KEY` должна вывести непустую строку. После правки переменной роутер нужно перезапустить, потому что старые значения он уже прочитал в память.

Проблема 2: ошибка вида `model not found` или ответ «модель не поддерживается».Симптом: запрос уходит, но провайдер отвечает, что такого имени модели у него нет. Решение: различайте alias и имя модели. В запросе клиента должно стоять ваше короткое имя (`fast`, `local`), а в конфиге в поле `model` — то имя, которое требует провайдер. Проверьте обе строки и перезапустите роутер. Быстрый тест — `curl http://127.0.0.1:4000/v1/models`: если в списке нет нужного alias, роутер просто не знает о нём.

Проблема 3: клиент игнорирует роутер и ходит напрямую.Симптом: в логах провайдера видно запросы, а в логах роутера — тишина. Решение: проверьте, что в настройках клиента адрес оканчивается на `/v1` и не содержит лишних пробелов или завершающего слэша; часть клиентов сохраняет старый адрес в скрытом профиле — перезапустите приложение. Если клиент запускается из скрипта, посмотрите, не переопределяет ли он base URL где-то ещё: частая причина — переменная окружения с базовым адресом, заданная раньше.

Проблема 4: таймауты и `429 Too Many Requests`.Симптом: ответ приходит не сразу, а через десятки секунд, либо с ошибкой про превышение лимита. Решение: это не сломанный роутер, а поведение провайдера — у него есть лимит запросов в минуту. Задайте fallback-алиас (шаг 7) и переводите лишние запросы на второй провайдер; заодно увеличьте таймаут в клиенте, если он у вас настраивается.

FAQ

Чем роутер отличается от того, чтобы просто подставить другой ключ в клиенте?

Роутер даёт единый адрес и единый ключ для всех провайдеров сразу. Если подставлять ключ в клиенте, придётся для каждого провайдера менять настройки, а при смене модели — править код или настройки в нескольких местах. С роутером меняется одна строка в `router-config.yaml`.

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

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

Что делать, если у провайдера не OpenAI-совместимый формат запросов?

Проверьте, есть ли у провайдера отдельный OpenAI-совместимый эндпоинт — многие его предоставляют, тогда достаточно указать правильный `base_url` в конфиге. Если такого эндпоинта нет, провайдера нельзя подключить простым описанием в конфиге: нужен адаптер, который переводит формат OpenAI в формат провайдера.

Безопасно ли хранить ключи в файле конфига?

Ключи роутера (те, что клиенты передают в заголовке) — не секрет, их можно держать в конфиге. Ключи провайдеров лучше держать в переменных окружения и ссылаться на них через поле `api_key_env`, как в примере выше. Так файл конфига можно безопасно хранить в репозитории и передавать коллегам, а сами ключи остаются только на машине.

🤖 Кратко для ИИ