From bad24ff6aa347a2468c15ed638cc62b4ce7e40f3 Mon Sep 17 00:00:00 2001 From: Hermes Team Date: Mon, 24 Aug 2026 10:46:04 +0700 Subject: [PATCH] =?UTF-8?q?docs(task):=20A25=20=E2=80=94=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=B2=D0=B5=D0=B4=D0=BA=D0=B0=20=D0=B2=D1=8B=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BD=D0=B5=D0=BD=D0=B0,=20=D0=B7=D0=B0=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D1=81=D1=82=D1=80=D0=BE=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BD=D0=B0=20=D1=84=D0=B0=D0=BA=D1=82=D0=B0?= =?UTF-8?q?=D1=85=20=D1=81=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Владелец дал доступ по ключу. На 192.168.1.81 работают два сервера llama.cpp, оба OpenAI-совместимые, проверено запросами: 8081 Qwen3.8-27B-Q4_K_M reasoning on, контекст 65536, -ngl 99 8082 Qwen3-4B-Instruct reasoning off, «compressor» GET /v1/models и POST /v1/chat/completions отвечают 200 на обоих. Видеокарта Tesla V100-32GB, занято 28.7 из 32.7 ГБ. Три следствия внесены в задание как определяющие реализацию: - оба слушают только 127.0.0.1, снаружи недоступны; варианты решения предложены владельцу, выбор за ним; - у обоих --parallel 1, то есть один запрос за раз: лизы Hub обязаны ограничивать локального провайдера, иначе роли заблокируют друг друга; - памяти видеокарты на третью модель нет, слотов ровно два. Co-Authored-By: Claude Opus 5 --- .../2026-08-24-A25-local-llm-provider.md | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/agents/inbox/2026-08-24-A25-local-llm-provider.md b/agents/inbox/2026-08-24-A25-local-llm-provider.md index 7d71518..0c533b0 100644 --- a/agents/inbox/2026-08-24-A25-local-llm-provider.md +++ b/agents/inbox/2026-08-24-A25-local-llm-provider.md @@ -43,24 +43,45 @@ git push -u origin antigravity/local-llm-provider - **`deepseek_adapter.py`** — готовый образец OpenAI-совместимого адаптера: берёт `profile.custom_base_url`, зовёт `{base_url}/chat/completions`. Локальные серверы (Ollama, vLLM, LM Studio, llama.cpp) выставляют тот же интерфейс; - у владельца в Hermes уже настроен профиль `deepseek` через `provider: custom, endpoint: https://limitdeckai.ru/v1` — то есть путь проверен на практике. -## P0-1. Разведка — сначала выяснить, что за сервер +## P0-1. Разведка выполнена — вот что на сервере -**Не угадывайте.** Прежде чем писать адаптер, определите, что именно слушает на 192.168.1.81 и по какому интерфейсу. +Владелец дал доступ по ключу, ревьюер зашёл и всё выяснил. **Заново не выясняйте.** -Ревьюер проверил снаружи: **пинг проходит, открыты порты 22 и 3000**. Порт 3000 — это Rocket.Chat, к моделям отношения не имеет. Порт Ollama по умолчанию (11434) **закрыт снаружи** — значит сервер слушает только localhost либо использует другой порт. +На `192.168.1.81` работают **два сервера llama.cpp**, оба OpenAI-совместимые: -Попросите владельца выполнить **на сервере** и приложите вывод в отчёт: +| Порт | Модель | Настройки | +|---|---|---| +| **8081** | `Qwen3.8-27B-Q4_K_M.gguf` | `-ngl 99`, контекст 65536, flash-attn, KV-кэш q8_0, **reasoning on** (бюджет 4096, формат deepseek), temp 0.2, top-p 0.9 | +| **8082** | `Qwen3-4B-Instruct-2507-Q4_K_M.gguf` | то же, но **reasoning off**; в имени каталога — «compressor» | + +Проверено запросами: ``` -ss -tlnp | grep -E '11434|8000|8080|1234|5000|5001' -curl -s localhost:11434/api/tags | head -20 -curl -s localhost:8000/v1/models | head -20 -docker ps --format '{{.Names}}\t{{.Ports}}\t{{.Image}}' +GET /v1/models -> список моделей, формат llama.cpp +POST /v1/chat/completions -> 200 (на обоих портах) ``` -От результата зависит: адрес, порт, наличие `/v1/models`, нужен ли ключ, и слушает ли сервис только localhost — в последнем случае Hub с другой машины до него не достучится без правки конфигурации сервера. +Видеокарта: **Tesla V100-PCIE-32GB, занято 28.7 ГБ из 32.7**. -Ревьюер не имеет доступа по SSH (вход по ключу не настроен, пароли не используются), поэтому эту часть выполняет владелец. +### Три следствия, которые определяют реализацию + +1. **Оба сервера слушают только `127.0.0.1`.** Снаружи, в том числе с машины владельца под Windows, они недоступны. Пока это не решено, провайдер работать не будет. Решение выбирает владелец, вариант в отчёт: + - перезапустить llama.cpp с `--host 0.0.0.0` — модель станет доступна всем в домашней сети; + - держать Hub на самом сервере — там уже стоят Hermes и Hub, и `127.0.0.1` доступен напрямую; + - проброс по SSH — не годится для службы, туннель придётся держать поднятым. + +2. **У обоих серверов `--parallel 1`.** Это значит **один запрос за раз**. Второй встанет в очередь и будет ждать. Для маршрутизации это принципиально: лизы Hub обязаны ограничивать локального провайдера одним одновременным вызовом, иначе роли начнут блокировать друг друга и таймауты пойдут лавиной. + +3. **Память видеокарты почти исчерпана** — 28.7 из 32.7 ГБ. Третью модель не поднять, и это не проблема Hub, а факт, который надо учитывать: локальный провайдер даёт ровно две модели. + +### Что это значит для ролей + +Набор напрашивается сам: + +- **27B с reasoning** — тяжёлые роли: `reviewer`, `coder-secondary`. Модель рассуждающая, с большим контекстом; +- **4B** — `fast`: быстрые вспомогательные вызовы, ради чего она и поднята. + +Предложить владельцу, не менять цепочки молча. ## P0-2. Провайдер локальных моделей @@ -69,7 +90,7 @@ docker ps --format '{{.Names}}\t{{.Ports}}\t{{.Image}}' 1. **Адаптер**: OpenAI-совместимый `POST {base_url}/chat/completions`. Ключ необязателен: локальные серверы обычно его не требуют. Если ключа нет — не выдумывать заголовок авторизации. 2. **Обнаружение моделей**: `GET {base_url}/models`. Это штатный способ, и он избавляет от той боли, что была с `agy models`. Список кладётся в тот же `ModelDiscoveryService`. 3. **`health_check`**: запрос к `{base_url}/models` с коротким таймаутом. Локальная сеть быстрая, но сервер может быть выключен — отказ должен быть быстрым и внятным, а не висеть. -4. **Профили и слоты**: добавить `local-1`, `local-2`, `local-3` во встроенные умолчания, чтобы миграция из A9 довела их до существующих конфигураций. Проверить, что `find_free_slot("local")` возвращает существующий профиль. +4. **Профили и слоты**: добавить `local-1` и `local-2` во встроенные умолчания — ровно по числу поднятых моделей; третью на этой видеокарте не запустить, чтобы миграция из A9 довела их до существующих конфигураций. Проверить, что `find_free_slot("local")` возвращает существующий профиль. ## P0-3. Квоты: у локальной модели их нет, и это надо сказать прямо @@ -83,7 +104,7 @@ docker ps --format '{{.Names}}\t{{.Ports}}\t{{.Image}}' ## P0-4. Мастер подключения -Добавить локального провайдера в мастер. Поля: **адрес сервера** (например `http://192.168.1.81:11434/v1`), необязательный ключ, кнопка проверки. +Добавить локального провайдера в мастер. Поля: **адрес сервера** (у владельца это `http://192.168.1.81:8081/v1` и `:8082/v1`), необязательный ключ, кнопка проверки. Проверка должна быть настоящей: запрос к `/models`, показ найденных моделей. Не «сохранено», а «сервер ответил, доступно N моделей» с их перечислением. @@ -91,7 +112,9 @@ docker ps --format '{{.Names}}\t{{.Ports}}\t{{.Image}}' ## P0-5. Роль по умолчанию -Предложить владельцу, куда поставить локальную модель в цепочках, и обосновать. Разумно — последним резервом у `fast` и `research`: она бесплатна и не исчерпывается, значит подходит как последняя линия, когда платные квоты кончились. +Предложить владельцу, куда поставить обе модели, и обосновать. Разумно исходить из их назначения: 27B с включённым reasoning — последним резервом у `reviewer` и `coder-secondary`, 4B — у `fast`. Обе бесплатны и не исчерпываются, значит годятся как последняя линия, когда платные квоты кончились. + +Помнить про `--parallel 1`: ставить одну и ту же локальную модель резервом сразу нескольким ролям опасно — при одновременной нагрузке они выстроятся в очередь друг за другом. **Не менять цепочки владельца молча.** Предложить в отчёте, решение за ним.