Files

74 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).