Files

5.2 KiB
Raw Permalink Blame History

llm-proxy

Прозрачная прослойка/роутер OpenAI API. Принимает /v1/chat/completions и /v1/models, маршрутизирует между объявленными в YAML апстримами по внутреннему учёту конкурентности и мержит patch-слои (provider → upstream → model) в тело запроса. Подробная спецификация конфига — в CONFIG.md.

Конфиг

Конфигурация — в YAML-файле (по умолчанию config.yaml в каталоге проекта, CWD; переопределяется env CONFIG_PATH). Блоки: server (интерфейс биндинга host + port, дефолты 0.0.0.0 / 8100), providers, upstreams, models. Старый механизм env-переменных (UPSTREAM_URL, ROUTER_API_KEY, EXCLUDED_PROVIDERS, THINKING_MODELS, PORT) удалён — его поведение теперь в декларативном patch и блоке upstreams, а порт/интерфейс — в блоке server.

Лимит конкурентности max_concurrency можно задать и на провайдере (лимит по умолчанию для его апстримов), и на апстриме (перекрывает провайдерский); без обоих — безлимит.

Обработку think-тегов включает опциональный флажок think_tags у провайдера или апстрима (off по умолчанию, split — рассуждения из think-тегов уходят в reasoning_content, strip — выбрасываются); работает и в стриме, и в non-stream.

Повторяющиеся сбои апстрима увязываются экспоненциальным backoff: поле backoff (ISO-8601-потолок, напр. P1M) задаётся на провайдере (общий счётчик на его модели) и/или на апстриме (приоритет). Первая ошибка — отдых 1s, далее 2s, 4s, … до потолка; успех сбрасывает. Все апстримы модели в откате — 503 с Retry-After.

Для stream=true запросов действует watchdog на первый байт ответа: first_byte_timeout (ISO-8601, дефолт PT30S, PT0S отключает) — если апстрим не прислал ни одного байта за окно, слот освобождается, ошибка идёт в backoff и роутер фейловерит на следующего свободного апстрима. Приоритет: upstreams[].first_byte_timeout → providers[].first_byte_timeout → PT30S.

Пока апстрим «отдыхает» в backoff-откате, его можно фоново пинговать: probe_interval (ISO-8601, дефолт PT1S, PT0S отключает) — HealthProber шлёт апстриму минимальный запрос (2+2=?, max_tokens=4) и, как только тот ответил, снимает его с отката немедленно, не дожидаясь истечения backoff-интервала. Пинг не занимает слот конкурентности и не засчитывается в backoff. Приоритет: upstreams[].probe_interval → providers[].probe_interval → PT1S.

Прокси отдаёт Prometheus-метрики по GET /metrics (запросы по model/upstream/provider/result, занятые слоты, счётчик и окно backoff-отката) — подключите скрейп в Prometheus и стройте дашборды/алерты в Grafana. Список метрик — в CONFIG.md, раздел «Prometheus-метрики».

Переменная Default Описание
CONFIG_PATH config.yaml (CWD) Путь к YAML-конфигу
Ключ конфига Default Описание
server.host 0.0.0.0 Интерфейс/адрес биндинга
server.port 8100 Порт сервера

Таймаут на запрос к нейронке (весь ответ, включая стриминг) — константа UPSTREAM_REQUEST_TIMEOUT_MS = 5 минут; без неё дефолт CIO-движка Ktor — 15 секунд, и длинные генерации обрываются. Значение логируется при старте.

Сборка и деплой

  • CI (Gitea Actions, на release): ./gradlew fatJar → образ images.binom.pw/llm-proxy:<tag> (zot).
  • Запуск на 76.179 (llm-router): podman-compose up -d из podman-compose.yaml (образ тянется из images.binom.pw, сеть bifrost_default — туда же Bifrost ходит по имени llm-proxy).
  • Bifrost: в config_providers провайдера Routerai network_config_json.base_url = http://llm-proxy:8100 (после смены — рестарт bifrost_gateway).