# Настройка локального 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` | `llm` | CPU-инференс (`/v1/chat/completions`), уровни `min`/`medium` | | `llm-gpu` | `ghcr.io/ggml-org/llama.cpp:server-cuda-b` | `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`.