62 lines
7.0 KiB
Markdown
62 lines
7.0 KiB
Markdown
# llm-router-failover-proxy
|
||
|
||
## Goal
|
||
|
||
LLM-роутер / failover-прокси для pi (кодинг-агент на Windows-воркстейшне vitya). Группирует все deepseek-v4-flash модели из разных роутеров в один алиас (`deepseek-flash`), отдельно deepseek-v4-pro (`deepseek-pro`). Приоритет: **free-модели первыми**, затем по приоритету провайдеров, официальный DeepSeek API (платный) — последним fallback'ом. При ошибке апстрима (429/5xx/таймаут/сеть) — автоматический переход к следующему.
|
||
|
||
Заказчик: vitya (через snolla-сессию). **Решение, куда деплоить — за админом** (см. «Деплой»).
|
||
|
||
## Контекст
|
||
|
||
Потребитель один — pi на машине vitya (`~/.pi/`). Сейчас модели прописаны вручную в `~/.pi/agent/models.json` (4 провайдера, ключи в `~/.pi/agent/auth.json`):
|
||
|
||
| Провайдер | baseUrl | deepseek-v4-flash | deepseek-v4-pro |
|
||
|---|---|---|---|
|
||
| teamorouter | https://api.teamorouter.com/v1 | `deepseek-v4-flash-free` (free) | `deepseek-v4-pro-free` (free) |
|
||
| orcarouter | https://api.orcarouter.ai/v1 | `deepseek/deepseek-v4-flash-free` (free) | `deepseek/deepseek-v4-pro-free` (free) |
|
||
| anymodel | https://anymodel.org/v1 | `am/deepseek-v4-flash` (free) | `am/deepseek-v4-pro` (free) |
|
||
| routerai | https://routerai.ru/api/v1 | — | — |
|
||
| deepseek (официальный) | https://api.deepseek.com | `deepseek-chat` (платный) | `deepseek-reasoner` (платный) |
|
||
|
||
- Ключи всех апстримов уже лежат в `~/.pi/agent/auth.json` (формат: `{ "<provider>": { "type": "api_key", "key": "..." } }`). Конфиг прокси может ссылаться на них или держать свои копии — на усмотрение админа (ключи не публиковать, gitignore).
|
||
- Все free-модели — это deepseek-v4-flash/pro у разных посредников. Официальный DeepSeek API платный — **последний** в цепочке (fallback, когда все free лежат).
|
||
- Ранее обсуждено (рекомендация, НЕ приказ): деплой локально на Windows как winsw-сервис (паттерн agents-task-runner уже обкатан), Node-прокси без docker/WSL2. **Решение за админом.**
|
||
|
||
## Требования
|
||
|
||
1. **OpenAI-совместимый эндпоинт** (`/v1/chat/completions`, openai-completions API). pi подключается одной записью в `~/.pi/agent/models.json` (провайдер + алиасы).
|
||
2. **Алиасы моделей**: `deepseek-flash` → пул flash-апстримов, `deepseek-pro` → пул pro-апстримов.
|
||
3. **Приоритет выбора**: free-апстримы (teamorouter → orcarouter → anymodel, порядок конфига) → платный официальный DeepSeek → (остальные провайдеры, если появятся).
|
||
4. **Failover**: на 429 / 5xx / таймаут / сетевую ошибку — retry к следующему апстриму в порядке приоритета. Желательно: cooldown для упавших апстримов (не долбить мёртвый), опционально circuit-breaker.
|
||
5. **Прозрачный passthrough**: SSE-стриминг, tool-calls (pi использует активно, много раундов), thinking-блоки deepseek (reasoning) — всё должно доезжать без искажений. Модель в ответе — какую реально использовал.
|
||
6. **Логика по умолчанию**: если все free живы — платный апстрим не вызывается (экономия).
|
||
7. **Конфиг** — файл (YAML/JSON): алиас → упорядоченный список апстримов (baseUrl, key-ref, model-id, free/paid флаг, таймауты).
|
||
8. **Учёт**: лог, какой апстрим обслужил запрос + usage. Cost-трекинг не обязателен (модели free), но знать, что сработал платный fallback — обязательно.
|
||
9. **Тесты**: TDD (см. ниже).
|
||
|
||
## Acceptance
|
||
|
||
- [ ] pi подключается к прокси одной записью в `~/.pi/agent/models.json`; `/model` (или `pi --list-models`) показывает `deepseek-flash` / `deepseek-pro`.
|
||
- [ ] Стриминг работает: ответ идёт потоком (не цельным blob).
|
||
- [ ] Tool-calls работают: несколько последовательных инструмент-раундов (типа как pi вызывает tools).
|
||
- [ ] Failover доказан тестом: верхний апстрим недоступен → запрос обслуживает следующий; при живых free — платный НЕ вызывается.
|
||
- [ ] Thinking/reasoning-контент deepseek не ломается (хотя бы smoke: ответ не пустой, без мусора).
|
||
- [ ] Инструкция для pi-интеграции (что писать в models.json) + как запускать/останавливать прокси (сервис/скрипт).
|
||
- [ ] Деплой выполнен (локально или VDS — решение админа) и живой smoke пройден.
|
||
|
||
## Деплой (решение за админом)
|
||
|
||
Рекомендация заказчика: **локально** на Windows (Node-процесс, winsw-сервис — паттерн agents-task-runner; ключи не уходят на сервер; потребитель один — pi на этой машине; docker/WSL2 на Windows — боль). Если админ видит причину иначе (VDS, доступ с других устройств, Portainer-стек) — обосновать и сделать. Ключи апстримов на VDS — только если деплой туда, тогда по правилам админа (pass / env, не в git).
|
||
|
||
## Обязательные скилы — вызвать до начала работы
|
||
|
||
- invoke `tdd-criteria` — до написания кода
|
||
- invoke `using-tasks` — управление статусом задачи
|
||
- invoke `project-discipline` — коммиты/пуши
|
||
- invoke `using-wiki` после закрытия — заингесть `.wiki/concepts/llm-router-failover-proxy.md` (архитектура, решения, runbook)
|
||
|
||
**TDD:** да — failover/приоритет/стриминг это чистые юнит-кейсы; тест-харнесс обязателен (мок-апстримы).
|
||
**Разрешения:** интерны: да | автопуш: да
|
||
**Weight:** needs-claude
|
||
**Notify:** victor/snolla
|