Free Router — бесплатный OpenAI-совместимый шлюз для LLM
📂 Исходный код на GitHubБесплатный OpenAI-совместимый шлюз с маршрутизацией по бесплатным LLM-провайдерам
Free Router — локальный OpenAI-совместимый шлюз, который автоматически подбирает и маршрутизирует запросы к бесплатным LLM-моделям. Указываете клиенту адрес http://127.0.0.1:8787/v1, выбираете модель free-best — и шлюз сам ранжирует доступные бесплатные модели, переключается при rate limit или падении провайдера, ротирует ключи. Работает с Gemini, OpenRouter, TokenRouter, BAI, HashNeuron и любым другим OpenAI-совместимым провайдером.
Зачем это нужно
Бесплатные API для LLM разбросаны по десяткам провайдеров: у Gemini свой бесплатный тир, у OpenRouter свои бесплатные модели, у TokenRouter — свои. Каждый ставит свои лимиты, меняет доступность моделей, уводит их за платную стену. Ручной мониторинг и переключение — рутина.
Free Router решает эту задачу: один локальный эндпоинт, а за ним — все бесплатные модели, автоматически отсортированные по качеству. Если текущая модель отвечает 429 или падает — шлюз переходит к следующей без участия клиента.
Поддерживаемые провайдеры
| Провайдер | Переменная окружения | Получить ключ |
|---|---|---|
| Google Gemini | GEMINI_API_KEY |
AI Studio |
| OpenRouter | OPENROUTER_API_KEY |
openrouter.ai/keys |
| TokenRouter | TOKENROUTER_API_KEY |
Аккаунт TokenRouter |
| BAI | BAI_API_KEY |
chat.b.ai |
| HashNeuron | HASHNEURON_API_KEY |
hashneuron.space/v1 |
Каждый провайдер поддерживает несколько ключей с автоматической ротацией. Ключи задаются через .env, через веб-интерфейс или в config.local.json.
Добавление нового провайдера не требует изменения кода — достаточно записи в конфиге с baseUrl и опциональным списком бесплатных моделей.
Как работает ранжирование
Шлюз поддерживает маршрут free-best — единый ранжированный список моделей. Пиннинг зафиксирует модель на верхних позициях, остальные ранжируются по результатам автоматического discovery:
- Каждые 2 дня шлюз проверяет каталоги провайдеров на наличие новых бесплатных моделей
- Каждая новая модель получает гибридную оценку: бенчмарки (рассуждения, инструкции), метаданные (инструменты, контекст) и латентность
- Учёт реального трафика: success rate модели корректирует её позицию — 100% успеха поднимает, 60% и ниже — опускает
- Модели без ключа или вышедшие из бесплатного тира пропускаются автоматически
Оценка модели складывается из трёх частей: бенчмарки (до 65 баллов), метаданные (до 20), латентность (до 6). Ни одна часть не может доминировать — это гарантирует сбалансированный рейтинг.
Discovery исключает узкоспециализированные модели через discovery.exclude — по регулярным выражениям на ID модели и описанию. Финансовые, медицинские, юридические модели автоматически отсеиваются, но остаются доступными при прямом вызове по ID.
Установка
Node.js:
git clone https://github.com/www222fff/free-router-proxy.git
cd free-router-proxy
cp .env.example .env
# добавьте ключи провайдеров в .env
./start.sh
Остановка: ./stop.sh. Шлюз слушает 127.0.0.1:8787 по умолчанию.
Docker:
docker compose up -d
Ключи передаются из .env при запуске контейнера и не зашиваются в образ. Состояние discovery временное — сбрасывается при пересборке.
Конфигурация
Конфигурация работает в два слоя:
config.json— дефолты, не меняется при обновленияхconfig.local.json— ваши переопределения (gitignored), объекты мёрджатся рекурсивно, массивы заменяются
Приоритет: переменные окружения > config.local.json > config.json > дефолты кода.
Ключи также можно задавать через .env — при первом запуске они автоматически импортируются в config.local.json. Веб-интерфейс (http://127.0.0.1:8787/) позволяет управлять ключами, маршрутами, квотами и настройками провайдеров без редактирования файлов.
Интерфейс локализован на 12 языков и автоматически определяет язык браузера.
Использование с любым клиентом
Указывайте базовый URL http://127.0.0.1:8787/v1 и модель free-best. Клиентское API-ключ может быть любым значением — шлюз подставляет ключи провайдеров сам.
curl -s http://127.0.0.1:8787/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "free-best",
"messages": [{"role": "user", "content": "Привет"}]
}'
В ответе заголовки X-Free-Router-Provider и X-Free-Router-Model показывают, какая модель и провайдер были выбраны.
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8787/v1", api_key="local")
response = client.chat.completions.create(
model="free-best",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)
Мониторинг и квоты
./models.sh # текущий порядок free-best с колонками today / 7d / fail
./models.sh --usage # дневная и недельная статистика по моделям
Данные о использовании хранятся в discovered-free-models.json, автоматически очищаются через usage.retentionDays (по умолчанию 7 дней). Веб-интерфейс показывает текущие лимиты, количество запросов за день и статус discovery.
Архитектура
Сервер (server.mjs) — один процесс Node.js без зависимостей. Ядро — маршрутизатор, который:
- Ранжирует модели из
free-bestс учётом пиннинга, бенчмарков и трафика - Для каждой модели пробует провайдеров по порядку, пропуская недоступные
- Применяет кулдауны по провайдерам и ключам при ошибках
- Каждые 15 минут обновляет каталоги, каждые 2 дня — discovery новых бесплатных моделей
- Удаляет модели, ставшие платными или недоступными
- Буферизует reasoning-only чанки — пустые модели заменяются до отправки клиенту
Конфиденциальность: шлюз автоматически маскирует API-ключи в запросах к upstream-провайдерам, вырезая значения переменных *_API_KEY, *_TOKEN, *_SECRET, *_PASSWORD из тела запроса. Значения с новыми строками или NUL-символами отклоняются — одно поле не может записать второе присваивание в .env. Файл .env записывается с правами 0600.
Эндпоинты: GET /v1/models — список доступных моделей, POST /v1/chat/completions — основной эндпоинт чата, GET /health — статус шлюза с версией, discovery и квотами. Веб-интерфейс: GET /, API управления: POST /api/keys, POST /api/providers, POST /api/routes, POST /api/limits, POST /api/discovery.
Для автозапуска доступен systemd user-сервис — достаточно скопировать юнит-файл и включить его через systemctl --user enable --now free-router-proxy.