Files
vidconf/docs/deploy/llm-setup.md
Max Ronzhin 693db6e774 install.sh, docs: pass --env-file explicitly to docker compose
docker compose определяет .env для подстановки ${VAR} по каталогу
compose-файла (deploy/), а не по текущей директории — repo-root .env,
который использует install.sh и вся документация, молча не подхватывался.
Это и была причина "WARN: LIVEKIT_API_KEY not set" на боевом сервере:
секреты были в .env, но compose их не видел и подставлял небезопасные
дефолты (см. таблицу разведки сервера).

Теперь ставшие обязательными ${VAR:?} в docker-compose.yml (см. предыдущий
коммит) без этого немедленно проваливали бы конфиг на любой из
документированных команд. Добавлен `--env-file .env`/"$ENV_FILE" ко всем
вызовам docker compose в install.sh и в командах из README/docs.

install.sh дополнительно: ensure_default (аналог ensure_secret без генерации
секрета) для новых не-секретных параметров nginx/coturn/livekit
(NGINX_SERVER_NAMES, NGINX_CERT_NAME, LIVEKIT_USE_EXTERNAL_IP,
LIVEKIT_NODE_IP, TURN_EXTERNAL_IP) — дефолты только для локальной
разработки, не перезаписывают значения, заданные вручную на боевом
сервере. Плюс вызов deploy/render-templates.sh перед сборкой/подъёмом
стека.
2026-07-25 21:58:03 +03:00

122 lines
7.7 KiB
Markdown
Raw 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-сервера (Qwen3.5, профили compose `llm`/`llm-gpu`)
Плагин суммаризации `qwen_local` (`backend/core/plugins/qwen_local.py`)
обращается к OpenAI-совместимому серверу `llama.cpp`. Модель и параметры —
единый источник истины ADR-004 (`docs/architecture/adr/004-ai-tier-matrix.md`)
и константная матрица `backend/services/ai_tiers.py`. В обычной установке всё
описанное ниже делает `install.sh` (см. `docs/deploy/dev-setup.md`) — этот
раздел актуален для ручного/точечного запуска профиля без инсталлятора.
## 1. Компоненты
| Сервис | Образ | Профиль | Назначение |
|---|---|---|---|
| `llm-models-init` | `busybox` | `llm`/`llm-gpu` | фиксирует владельца тома `llm-models` (обходит дефект прав доступа) |
| `llm-model-init` | `curlimages/curl` | `llm`/`llm-gpu` | однократное скачивание GGUF-модели и tokenizer.json уровня AI |
| `llm` | `ghcr.io/ggml-org/llama.cpp:server-b<build>` | `llm` | CPU-инференс (`/v1/chat/completions`), уровни `min`/`medium` |
| `llm-gpu` | `ghcr.io/ggml-org/llama.cpp:server-cuda-b<build>` | `llm-gpu` | GPU-инференс, уровень `max` (ADR-004: GPU обязателен) |
Файлы:
- `deploy/llm/download-model.sh` — генерализованный скрипт скачивания
(параметризован `LLM_MODEL_FILE`/`LLM_MODEL_URL`/`LLM_MODEL_MIN_SIZE`/
`LLM_TOKENIZER_FILE`/`LLM_TOKENIZER_URL`; их пишет `install.sh` по
выбранному пресету — см. `install.sh --help`).
- `deploy/docker-compose.yml` — сервисы `llm-models-init`/`llm-model-init`/
`llm`/`llm-gpu`, volume `llm-models`, монтирование
`llm-models:/models/qwen:ro` в сервис `worker` (там же считаются токены
чанкером — `QwenTokenCounter`).
## 2. Модели по уровням AI (ADR-004)
| Уровень | Модель | Квант | Файл (`LLM_MODEL_FILE`) | Источник GGUF (`LLM_MODEL_URL`) |
|---|---|---|---|---|
| `min` (пресет 3) | Qwen3.5-4B-Instruct | Q4_K_M ≈ 2,6 ГиБ | `qwen3.5-4b-instruct-q4_k_m.gguf` | `unsloth/Qwen3.5-4B-GGUF` |
| `medium` (пресет 4) | Qwen3.5-9B-Instruct | Q4_K_M ≈ 5,3 ГиБ | `qwen3.5-9b-instruct-q4_k_m.gguf` | `unsloth/Qwen3.5-9B-GGUF` |
| `max` (пресет 5) | Qwen3.5-35B-A3B-Instruct (MoE) | Q4_K_M ≈ 20,5 ГиБ | `qwen3.5-35b-a3b-instruct-q4_k_m.gguf` | `unsloth/Qwen3.5-35B-A3B-GGUF` |
`tokenizer.json` (переименован под `LLM_TOKENIZER_FILE` — нужен
`QwenTokenCounter`, `backend/core/summarization/tokens.py`) берётся из
официальных репозиториев `Qwen/Qwen3.5-<размер>` (публичные, без gate;
GGUF-репозитории `Qwen/…-GGUF` — gated, поэтому источник GGUF — публичное
зеркало `unsloth/…-GGUF`, файлы идентичны по содержимому квантизации).
Имена файлов на диске (`LLM_MODEL_FILE`/`LLM_TOKENIZER_FILE`) — КОНТРАКТ с
детектом доступности уровня AI (`backend/services/ai_levels.py` через
`backend/services/ai_tiers.py::TIERS[level].model_files`): именно эти пути
проверяются на «модель скачана» в админке.
Скачивание идемпотентно (проверка по наличию и минимальному размеру файла,
`LLM_MODEL_MIN_SIZE`) — повторный запуск на уже заполненном томе ничего не
перекачивает. Ручной запуск (прогреть volume заранее):
```bash
LLM_MODEL_FILE=qwen3.5-4b-instruct-q4_k_m.gguf \
LLM_MODEL_URL=https://huggingface.co/unsloth/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf \
LLM_TOKENIZER_FILE=qwen3.5-4b-instruct.tokenizer.json \
LLM_TOKENIZER_URL=https://huggingface.co/Qwen/Qwen3.5-4B/resolve/main/tokenizer.json \
docker compose -f deploy/docker-compose.yml --env-file .env --profile llm run --rm llm-model-init
```
## 3. Запуск профиля
CPU (уровни `min`/`medium`, пресеты 3/4):
```bash
docker compose -f deploy/docker-compose.yml --env-file .env \
--profile media --profile transcribe --profile llm up -d
```
GPU (уровень `max`, пресет 5 — GPU обязателен):
```bash
docker compose -f deploy/docker-compose.yml --env-file .env \
--profile media --profile transcribe-gpu --profile llm-gpu up -d
```
Проверка готовности (порт `8080``llm`, `8081``llm-gpu` на хосте;
внутри docker-сети оба доступны как `llm:8080`/`llm-gpu:8080`, `llm-gpu`
также отвечает под алиасом `llm` — см. комментарий в `deploy/monitoring/prometheus.yml`):
```bash
curl http://localhost:8080/health
# пока модель грузится: {"error":{"code":503,"message":"Loading model",...}}
# сервер готов: {"status":"ok"}
```
## 4. Включение провайдера `qwen_local`
Дефолт репозитория в `config/plugins.yaml``summarizer.provider: "null"`
(безопасно для dev-окружений без LLM-сервера). Уровень `min` включается по
образцу закомментированного примера в `config/plugins.yaml`; уровни
`medium`/`max` собираются автоматически из `TIERS` (`backend/services/ai_tiers.py`)
при выборе уровня AI в админке — руками их прописывать не нужно (см.
`backend/services/instance_settings.py::_apply_tier_overrides`).
После правки `config/plugins.yaml` (уровень `min`, ручной dev-сценарий)
перезапустить `worker`:
```bash
docker compose -f deploy/docker-compose.yml --env-file .env up -d --force-recreate worker
```
## 5. Проверка вручную
1. Поднять профиль `llm`/`llm-gpu`, дождаться `docker compose ps` → healthy.
2. `curl http://localhost:8080/health``{"status":"ok"}`.
3. Включить уровень AI в админке (или `qwen_local` в `config/plugins.yaml`
для ручного dev-сценария уровня `min`).
4. Прогнать пайплайн на тестовом сеансе (см. `docs/plugins/summarizer.md`)
и убедиться, что `conference_sessions.summary_data` заполняется.
## 6. Ресурсы, thinking-режим и мониторинг
- Требования CPU/RAM/GPU по пресетам — `docs/architecture/adr/004-ai-tier-matrix.md`.
- `LLAMA_ARG_CTX_SIZE=16384`с запасом на чанк до 8000 токенов + промпт +
вывод (per-tier `max_tokens_map`/`max_tokens_reduce`, ADR-004).
- Thinking-режим (семейство Qwen3.5) отключается флагом `LLAMA_ARG_REASONING=off`
(актуальная замена `--chat-template-kwargs '{"enable_thinking":false}'` из
ADR-004 — та же семантика, но без деприкейшен-варнинга в логе на каждый
запуск, проверено через find-docs по `common/arg.cpp` проекта llama.cpp).
- `/metrics` (`LLAMA_ARG_ENDPOINT_METRICS=1`) собирает Prometheus, профиль
compose `monitoring``deploy/monitoring/prometheus.yml`, job `llm`.