golang

Auto AI Router: высокопроизводительный прокси-роутер для LLM API на Go

  • воскресенье, 26 апреля 2026 г. в 00:00:12
https://habr.com/ru/articles/1027878/

Если вы работаете с LLM-провайдерами, то наверняка сталкивались с одной и той же проблемой: у OpenAI лимит 100 RPM на ключ, у Vertex AI — свои квоты на проект, у Anthropic — отдельные ограничения. В итоге приходится держать несколько ключей, балансировать нагрузку вручную, следить, чтобы один заблокированный доступ не уронил всё приложение, и при этом хочется сохранить единый OpenAI-совсместимый эндпоинт для клиентского кода.

Именно для этого и создан Auto AI Router — лёгкий прокси-роутер на Go, который принимает запросы в формате OpenAI API и прозрачно распределяет их между несколькими провайдерами и ключами с балансировкой нагрузки, защитой от банов и контролем RPM-лимитов.

Репозиторий

Документация: auto_ai_router

Зачем ещё один роутер? Почему не LiteLLM?

LiteLLM — отличный инструмент, но он написан на Python и несёт весь соответствующий груз: интерпретатор, GIL, потребление памяти 200–500 МБ даже в простой конфигурации. Для высоконагруженного прокси, где каждые несколько миллисекунд задержки на маршрутизацию имеют значение, это не идеал.

Auto AI Router написан на Go и компилируется в единый статический бинарник. Типичное потребление RAM — десятки мегабайт, старт — меньше секунды. Это делает его удобным для деплоя в сайдкар-контейнерах или на ресурсоограниченных узлах.

Принципиальные отличия:

Аспект

LiteLLM

Auto AI Router

Язык

Python

Go

Бинарник

нет (pip/docker)

один статический бинарник / docker

Потребление RAM

200–500 МБ

~30–80 МБ

Round-robin балансировка

есть

есть, исправлен классический баг распределения

Session-sticky routing

нет

есть (по user, session_id)

Fail2ban per credential

нет

есть (настраиваемые правила по HTTP-кодам)

LiteLLM DB совместимость

нативная

интеграция с БД LiteLLM (PostgreSQL)

Режим прокси-цепочки

нет (есть кривая fallback система)

есть (proxy-credential → другой роутер)

Redis для rate limiting

нет

есть (глобальные счётчики для кластера)

Важный момент: Auto AI Router не заменяет LiteLLM полностью — он не управляет виртуальными ключами, моделями и пользователями через UI. Его задача уже и конкретнее: быть максимально быстрым и надёжным прокси-слоем между вашими приложениями и LLM-провайдерами.

Архитектура

Архитектура
Архитектура

Роутер принимает все запросы в формате OpenAI Chat Completions и конвертирует их в нативный формат нужного провайдера. Для Vertex AI — это Google GenAI SDK, для Anthropic — Messages API, и т.д. Ответы конвертируются обратно в OpenAI-формат.

Основные возможности

1. Multi-provider routing

Один endpoint может обслуживать несколько провайдеров:

  • OpenAI

  • Vertex AI

  • Anthropic

  • Gemini AI Studio

  • Amazon Bedrock

  • Proxy — отправка запроса в другой Auto AI Router

Клиент продолжает работать через OpenAI SDK, а роутер берёт на себя маршрутизацию и конвертацию.

2. Round-robin балансировка между credentials

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

credentials:
  - name: vertex_cred_1
    type: vertex-ai
    project_id: project-a
    credentials_file: sa-a.json
    rpm: 100

  - name: vertex_cred_2
    type: vertex-ai
    project_id: project-b
    credentials_file: sa-b.json
    rpm: 100

models:
  - name: gemini-2.5-flash
    credential: vertex_cred_1
  - name: gemini-2.5-flash
    credential: vertex_cred_2

В этом примере gemini-2.5-flash получает уже не 100 RPM, а 200 RPM суммарно. Запросы будут чередоваться между vertex_cred_1 и vertex_cred_2.

Отдельный момент — корректная реализация round-robin при пропуске ключей. Если креды временно забанен или упираются в лимит, роутер не “залипает” на первом доступном, а сохраняет честное чередование между оставшимися.

3. Fail2ban для credentials

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

fail2ban:
  max_attempts: 3
  ban_duration: permanent
  error_codes: [401, 403, 429, 500, 502, 503, 504]
  error_code_rules:
    - code: 429
      max_attempts: 5
      ban_duration: 5m

Например:

  • 429 — временный бан на 5 минут;

  • 401 или 403 — повод навсегда убрать credential из ротации;

  • 5xx — можно трактовать как временную деградацию upstream.

За счёт этого один проблемный ключ не ломает всю систему.

Пример отслеживания блокировок ключей
Пример отслеживания блокировок ключей

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

4. Session-sticky routing

WIP - находится на стадии клиентского тестирования

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

Проблема в том, что обычный round-robin разрушает такую привязку.

Решение — session-sticky routing. Роутер запоминает, какой кред уже обслуживал конкретную сессию, и направляет следующие запросы туда же.

response = client.chat.completions.create(
    model="gemini-2.5-flash",
    messages=[...],
    user="conversation-id-123",
)

Достаточно передать стабильный идентификатор сессии, например через user.

Сценарий

Без sticky

С sticky

Запрос 1 (10 000 токенов)

cred_A, полная стоимость

cred_A, полная стоимость

Запрос 2 (10 200 токенов)

cred_B, полная стоимость

cred_A, 200 новых токенов

Запрос 3 (10 400 токенов)

cred_A, полная стоимость

cred_A, 200 новых токенов

Для длинных контекстов экономия достигает 80–90%.

Источники session_id поддерживаются по приоритету: extra_body.litellm_session_id, extra_body.chat_id, extra_body.session_id, session_id, user, safety_identifier, prompt_cache_key.

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

5. Двухуровневый rate limiting

Лимиты задаются сразу на двух уровнях:

  • Per-credential — RPM и TPM для конкретного ключа;

  • Per-model — RPM и TPM для конкретной модели.

credentials:
  - name: openai_main
    rpm: 200
    tpm: 100000

models:
  - name: gpt-4o
    credential: openai_main
    rpm: 100
    tpm: 50000

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

Это позволяет гибко настраивать поведение: например, ограничивать конкретную модель сильнее, чем весь ключ целиком.

Мониторинг TPM
Мониторинг TPM

Благодаря логике Ai-router проекты способы держать нагрузку до нескольких десятков миллионов TPM без ошибок или необходимости поиска дорогостоящих энтерпрайз-решений от провайдеров.

6. Redis для распределённого rate limiting

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

С Redis лимиты становятся глобальными — все реплики делят единый счётчик:

redis:
  enabled: true
  addresses:
    - "valkey:6379"
  force_single_client: true

Реализовано через Lua-скрипты на стороне Redis: sliding window в sorted set, атомарная проверка всех 4 счётчиков (credential RPM + credential TPM + model RPM + model TPM) в одном вызове без TOCTOU-гонок.

7. Proxy chains

Можно настроить fallback на другой Auto AI Router:

credentials:
  - name: proxy_backup
    type: proxy
    base_url: http://backup-router.internal:8080
    api_key: sk-remote-master-key
    is_fallback: true

При недоступности всех primary-кредентиалов трафик автоматически уходит на резервный роутер. Статистика с удалённого /health синхронизируется каждые 30 секунд.

8. Поддержка Vertex AI, Anthropic и других провайдеров

Для OpenAI запросы идут почти напрямую. Для остальных провайдеров роутер берёт на себя адаптацию OpenAI-совместимого формата к нативному API. Например, для Vertex AI он поддерживает мультимодальность, streaming через SSE, tools, structured output на основе JSON Schema, thinking/reasoning для Gemini, генерацию изображений и маппинг reasoning_effort из OpenAI- и Anthropic-форматов.

# Чтобы включить thinking на Gemini 2.5 Flash,
# достаточно передать стандартный параметр
response = client.chat.completions.create(
    model="gemini-2.5-flash",
    messages=[...],
    reasoning_effort="high",
)

Это позволяет использовать один и тот же OpenAI-совместимый клиентский интерфейс поверх разных провайдеров без переписывания интеграции.

9. Responses API

Роутер поддерживает и OpenAI Responses API на endpoint /v1/responses:

  • конвертирует input в messages и обратно; (для моделей, у которых нет официальной поддержки Responses API)

  • поддерживает multi-turn через previous_response_id;

  • хранит историю в bbolt или Redis;

  • может использовать сохранённый credential для продолжения той же цепочки запросов.

r1 = client.responses.create(
    model="gpt-4o",
    input="Привет! Я работаю над проектом на Go.",
    store=True,
    user="conv-123",
)

r2 = client.responses.create(
    model="gpt-4o",
    input="Расскажи о горутинах.",
    previous_response_id=r1.id,
    store=True,
    user="conv-123",
)

10. Интеграция с LiteLLM DB

Если у вас уже развёрнут LiteLLM с PostgreSQL — роутер может:

  • Валидировать API-ключи через таблицу LiteLLM_VerificationToken

  • Логировать расходы в LiteLLM_SpendLogs с батчевой записью

  • Агрегировать дневные расходы по пользователям, командам

litellm_db:
  enabled: true
  database_url: "os.environ/LITELLM_DATABASE_URL"
  log_batch_size: 100
  log_flush_interval: 5s

Это позволяет использовать Auto AI Router как высокопроизводительный прокси-слой поверх существующей LiteLLM-инфраструктуры, не мигрируя всю систему.

Мониторинг

Пример визуализации ДБ по Heath
Пример визуализации ДБ по Heath

Роутер предоставляет несколько способов наблюдения за состоянием системы:

  • /health — JSON со статусом credentials, моделей и удалённых proxy;

  • /vhealth — HTML-страница для быстрого визуального осмотра;

  • /metrics — Prometheus-метрики.

monitoring:
  prometheus_enabled: true

Пример Grafana-дашборда можно построить на метриках:

  • auto_ai_router_credential_rpm_current — загрузка креда

  • auto_ai_router_credential_banned — 1 = кред забанен

  • auto_ai_router_requests_duration_seconds — распределение задержки (latency distribution)

Средняя задержка по креду в Grafana
Средняя задержка по креду в Grafana

Быстрый старт

Docker

docker run -p 8080:8080 \
  -v $(pwd)/config.yaml:/app/config.yaml \
  ghcr.io/mixaill76/auto_ai_router:latest

Минимальный config.yaml

server:
  port: 8080
  master_key: "sk-your-master-key"

credentials:
  - name: openai_main
    type: openai
    api_key: "os.environ/OPENAI_API_KEY"
    base_url: "https://api.openai.com"
    rpm: 100
    tpm: 50000

models:
  - name: gpt-4o
    credential: openai_main

Запрос через OpenAI SDK

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8080/v1",
    api_key="sk-your-master-key",
)

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)

Для клиентского кода меняются только base_url и api_key.

Безопасность

Безопасность — ещё один важный аргумент в пользу Auto AI Router. Для прокси-слоя, через который проходят ключи, лимиты и маршрутизация запросов, безопасность — базовое требование. У Auto AI Router здесь есть понятное преимущество: это более узкий и простой по устройству инструмент, чем крупные универсальные решения. А значит, его легче проверять, изолировать внутри инфраструктуры, ограничивать сетевой доступ и использовать строго по назначению — как слой маршрутизации ключей и запросов, без лишних интерфейсов и дополнительной логики.

Из последних проблем с LiteLLM
Из последних проблем с LiteLLM

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

  • Секреты в конфиге через os.environ/VAR_NAME — ключи не хранятся в файлах

  • Аутентификация по master key через Authorization: Bearer header

  • Дополнительно: валидация по токенам LiteLLM DB

  • /health, /vhealth, /metrics — без аутентификации (для мониторинга)

Итоги

Auto AI Router решает прикладную задачу: принять OpenAI-совместимый запрос и надёжно доставить его до нужного LLM-провайдера, даже если у вас несколько ключей, несколько поставщиков и разные ограничения по rate limit.

Он особенно полезен, если:

  • у вас несколько доступов для одного или нескольких LLM-провайдеров;

  • нужен единый OpenAI-совместимый эндпоинт без переписывания клиентского кода;

  • важны отказоустойчивость и автоматическое исключение проблемных ключей;

  • хочется использовать кэширование запросов эффективнее за счёт session-sticky routing;

  • уже есть LiteLLM DB, но нужен более лёгкий и быстрый прокси-слой.

При этом Auto AI Router не пытается заменить LiteLLM как систему управления доступом, моделями и пользователями. Это более узкий инструмент: быстрый маршрутизатор и прокси для LLM API.

Репозиторий: github.com/MiXaiLL76/auto_ai_router

Документация: auto_ai_router