====== llama.cpp: большие MoE-модели с NVMe + RAM на TrueNAS (Docker, Custom App) ====== ===== Введение ===== Инструкция описывает, как на сервере **TrueNAS** запустить большую MoE-модель (**Qwen3.8-Flash-Next**, 80–190 GB), которая **не помещается целиком в RAM+VRAM**: веса лежат на NVMe-накопителе, горячая часть держится в оперативной памяти и в кэше на видеокарте. Движок — **llama.cpp** (''llama-server'', OpenAI-совместимый API), запуск — Docker-приложение через веб-интерфейс TrueNAS. Главное отличие от [[:truenas:application:strata_qwen_server|Strata на TrueNAS]]: llama.cpp **работает на текущем драйвере NVIDIA 550** (проверено на сервере), обновлять TrueNAS не нужно, и модель не «закрепляет» RAM — память, занятая под веса, отдаётся другим приложениям по требованию. **Статус инструкции.** На сервере проверено: образ llama.cpp запускается и видит GPU на драйвере 550.142, поддерживает архитектуру модели (''qwen4exp'') и нужные ключи. Сама модель на сервере ещё не запускалась, скорость не замерялась — такие места помечены **(проверить)**. ===== Почему это работает ===== Qwen3.8-Flash-Next — модель Mixture-of-Experts (данные из заголовка GGUF): ^ Параметр ^ Значение ^ | Архитектура | ''qwen4exp'' | | Слоёв | 48 | | Экспертов в слое | **512**, из них на каждый токен работают только **10** | | Контекст | до 262 144 токенов | На каждый токен читается лишь малая часть весов (~2% экспертов). Поэтому: * **общие веса** (внимание, эмбеддинги) и KV-кэш — на GPU; * **эксперты** — в файле на NVMe, отображённом в память (''mmap''): Linux сам держит в RAM часто нужные страницы и дочитывает остальное с диска; * **самые горячие эксперты** — дополнительно в GPU-кэше (''--moe-cache-mib''). Чем больше модель превышает свободную RAM, тем чаще чтения с NVMe и тем медленнее генерация — но запускается и работает. ===== Какие движки умеют NVMe + RAM и что подходит этому серверу ===== ^ Движок ^ Как использует SSD ^ На этом сервере ^ | **llama.cpp** (''llama-server'') | ''mmap'' весов + эксперты MoE в RAM (''--cpu-moe'') + GPU-кэш экспертов (''--moe-cache-mib''); режим Direct I/O (''-lm dio'') | **работает сейчас** (драйвер 550, проверено) — **эта инструкция** | | **Strata** | свой движок, часть экспертов в RAM, остальное с диска; на ПК — самый быстрый вариант | только после обновления до TrueNAS 25.10.7+ (нужен драйвер 580), закрепляет RAM — [[:truenas:application:strata_qwen_server|отдельная инструкция]] | | **Ollama** (уже стоит на сервере) | внутри llama.cpp, ''mmap'' | проще, но меньше контроля над выгрузкой экспертов; поддержка ''qwen4exp'' **(проверить)** | | **SGLang «SSD Expert Pack»** | эксперты на NVMe, Direct I/O, GPU-кэш; для гигантских моделей (DeepSeek-V4-Flash, Kimi-K3) | **(проверить)** — вероятно, нужен более новый драйвер; см. блог LMSYS, 2026-08 | ===== Сервер ===== ^ Параметр ^ Значение ^ | Система | TrueNAS SCALE 25.04.2.6, драйвер NVIDIA **550.142** | | CPU | Intel Core i5-14500 (6 P-ядер + 8 E-ядер, 20 потоков) | | RAM | 62 GB | | GPU | RTX 2000 Ada, 16 GB | | NVMe | пул ''appData'' — 2 × Samsung 990 PRO 4 TB, ''/mnt/appData'' | Проверка образа на сервере: $ docker run --rm --gpus all ghcr.io/ggml-org/llama.cpp:server-cuda --version version: 0.9.0-dev (build 12316, commit 5d4c8eeb2) $ docker run --rm --gpus all ghcr.io/ggml-org/llama.cpp:server-cuda --list-devices Available devices: CUDA0: NVIDIA RTX 2000 Ada Generation (16075 MiB, 4178 MiB free) ''4178 MiB free'' — остальную видеопамять в этот момент держали другие приложения (см. «Шаг 1»). Образ (4.4 GB) уже скачан на сервер. ===== Шаг 1: Освободить видеокарту ===== На GPU сервера уже работают Ollama, Whisper, LibreTranslate, XTTS/VoxCPM — вместе ~12 из 16 GB. Для модели нужно хотя бы 8–10 GB свободных (общие веса + KV-кэш + кэш экспертов). На время работы остановите GPU-приложения: **Apps → Installed → (приложение) → Stop**. В первую очередь ''ollama'' — она держит загруженные модели в VRAM. nvidia-smi --query-gpu=memory.used,memory.total --format=csv Остальные приложения (Nextcloud, Jellyfin и т.д.) **можно не останавливать**: память под веса модели — это кэш страниц Linux, он вытесняется, когда памяти не хватает. Чем больше свободной RAM, тем быстрее генерация. ===== Шаг 2: Датасет для моделей на NVMe ===== **Datasets** → ''appData'' → **Add Dataset**: * Name: ''llm-models'' * Dataset Preset: **Generic** * **Advanced Options**: * Record Size: **1M** (большие файлы читаются крупными блоками) * Compression: **OFF** (GGUF почти не сжимается) * ATime: **Off** * Save. Путь: ''/mnt/appData/llm-models''. Места — с запасом под модели (на пуле ~3.3 TB свободно). **Кэш ZFS (ARC) и mmap.** Файл модели, читаемый через ''mmap'', на ZFS кэшируется дважды: в ARC и в кэше страниц Linux — RAM тратится впустую. Рекомендуется для этого датасета отключить кэширование данных в ARC (останутся только метаданные) — в **System → Shell** под root (''sudo -i''): zfs set primarycache=metadata appData/llm-models zfs get primarycache,recordsize,compression appData/llm-models **(проверить)** влияние на скорость: сравните ''tokens/s'' до и после (см. «Шаг 7»). Вернуть: ''zfs set primarycache=all appData/llm-models''. ===== Шаг 3: Выбор модели ===== Все варианты — Qwen3.8-Flash-Next в GGUF. «Свободно RAM» на сервере: ~30–38 GB при работающих приложениях, ~55 GB при остановленных. Что не поместилось в RAM — читается с NVMe. ^ Вариант ^ Размер ^ Где взять ^ Ожидание на этом сервере **(проверить)** ^ | ''UD-Q2_K_XL'' | 80 GB | ''unsloth/Qwen3.8-Flash-Next-GGUF'' | быстрее всех, качество ниже | | **RVN ''IQ3_S''** | 83 GB | уже скачан на ПК: ''F:\projects\inst\qwen-iq3s'' (8 файлов) | **рекомендуется для начала** — ничего не качать, только скопировать | | ''UD-IQ3_XXS'' / ''UD-Q3_K_XL'' | 84 / 90 GB | Unsloth | близко к IQ3_S | | ''UD-IQ4_XS'' | 94 GB | Unsloth | 4 бита, чуть больше чтений с диска | | ''UD-Q4_K_XL'' | 111 GB | Unsloth | **лучше качество**; заметная часть экспертов — с NVMe, медленнее | | ''UD-Q5_K_XL'' … ''Q8_0'' | 158–188 GB | Unsloth | запустится, но в основном с диска — медленно; имеет смысл после добавления RAM | **Примечание про RVN IQ3_S.** Этот же набор файлов не принял движок Strata (ему нужны служебные тензоры в BF16), а llama.cpp такие типы тензоров (IQ3_S, IQ4_NL) читает. Архитектура в файле — ''qwen4exp'', её поддерживает текущий llama.cpp. **(проверить запуск)** ===== Шаг 4: Загрузить модель на сервер ===== ==== Вариант А: скопировать RVN IQ3_S с ПК ==== - **Shares → Windows (SMB) Shares → Add**: Path ''/mnt/appData/llm-models'', Name ''llm-models'', Save (TrueNAS предложит включить службу SMB — согласиться). Доступ — вашему пользователю. - На ПК (PowerShell): New-Item -ItemType Directory -Force \\TRUENAS\llm-models\qwen-rvn-iq3_s | Out-Null robocopy F:\projects\inst\qwen-iq3s \\TRUENAS\llm-models\qwen-rvn-iq3_s *.gguf /J /NP 83 GB по гигабитной сети — ~15 минут. ==== Вариант Б: скачать с Hugging Face прямо на сервер ==== В **System → Shell** (или SSH) — одноразовый контейнер, который скачивает выбранный квант и удаляется: docker run --rm -v /mnt/appData/llm-models:/models python:3.12-slim sh -c \ "pip install -q -U huggingface_hub hf_xet && \ hf download unsloth/Qwen3.8-Flash-Next-GGUF --include '*UD-Q4_K_XL*' --local-dir /models/unsloth-ud-q4_k_xl" ls -la /mnt/appData/llm-models/unsloth-ud-q4_k_xl/* Для другого кванта поменяйте ''UD-Q4_K_XL'' в обоих местах. Загрузка возобновляется при повторном запуске. **(проверить точные имена папок в репозитории Unsloth)** В YAML («Шаг 6») указывается **первый** файл набора (''...-00001-of-0000N.gguf''), остальные части llama.cpp подхватит сам. ===== Шаг 5: API-ключ ===== openssl rand -hex 24 Ниже — ''<КЛЮЧ>''. Без ключа сервер будет открыт всей сети. ===== Шаг 6: Custom App через веб-интерфейс ===== **Apps → Discover Apps → ⋮ → Install via YAML**: * Name: ''llama-qwen'' * Custom Config: services: llama-qwen: image: ghcr.io/ggml-org/llama.cpp:server-cuda-b12316 container_name: llama-qwen restart: unless-stopped ports: - "30081:8080" volumes: - /mnt/appData/llm-models:/models:ro command: - -m - /models/qwen-rvn-iq3_s/RVN-Qwen3.8-Flash-Next-IQ3_S-00001-of-00008.gguf - --alias - qwen3.8-flash-next - --host - 0.0.0.0 - --port - "8080" - --api-key - "<КЛЮЧ>" - -c - "65536" - -ngl - "99" - --cpu-moe - --moe-cache-mib - "6144" - -fa - "on" - -ctk - q8_0 - -ctv - q8_0 - -t - "6" - --jinja deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] Что делает каждая строка: ^ Параметр ^ Смысл ^ | ''server-cuda-b12316'' | закреплённая версия llama.cpp (сборка 12316, CUDA 12 — работает на драйвере 550). Обновление — сменить номер сборки | | ''30081:8080'' | снаружи порт **30081** (8080/8081 заняты, 30080 зарезервирован под Strata) | | ''/models:ro'' | датасет с моделями, только чтение | | ''-m'' | первый файл набора GGUF | | ''--alias'' | имя модели в API (''/v1/models'') — его указывают клиенты | | ''-c 65536'' | контекст 64K (больше — больше VRAM под KV-кэш) | | ''-ngl 99'' | все слои на GPU… | | ''--cpu-moe'' | …**кроме экспертов**: они остаются в RAM/mmap (а значит, на NVMe) | | ''--moe-cache-mib 6144'' | 6 GB видеопамяти — кэш самых используемых экспертов. Если VRAM мало — уменьшить; если свободно больше — увеличить | | ''-fa on'', ''-ctk/-ctv q8_0'' | Flash Attention и KV-кэш в 8 бит — меньше VRAM под контекст | | ''-t 6'' | потоки CPU: по числу P-ядер i5-14500. **(проверить)** ''-t 12'' и ''-t 14'' | | ''--jinja'' | шаблон чата из модели (нужен для вызова инструментов агентами) | | ''deploy … nvidia'' | доступ к GPU (как у ваших ''whisper'' и ''libretranslate'') | Лимит памяти и ''memlock'' **не нужны**: в режиме ''mmap'' (по умолчанию) память под веса отдаётся системе по требованию. ===== Шаг 7: Запуск и проверка ===== **Apps → Installed → llama-qwen → Logs**. Нормальная загрузка выглядит так (суть строк): модель найдена, ''CUDA0 model buffer'' — часть на GPU, ''CPU_Mapped model buffer'' — эксперты отображены из файла, затем ''server is listening on http://0.0.0.0:8080''. Загрузка — от десятков секунд до нескольких минут. На сервере: curl -s http://127.0.0.1:30081/health curl -s http://127.0.0.1:30081/v1/models -H "Authorization: Bearer <КЛЮЧ>" С ПК (PowerShell), с замером скорости — в ответе поле ''timings.predicted_per_second'' (токенов/с генерации): '{"model":"qwen3.8-flash-next","messages":[{"role":"user","content":"Объясни кратко, чем list отличается от tuple в Python"}],"max_tokens":300}' | Out-File -Encoding utf8 req.json curl.exe -s http://192.168.1.135:30081/v1/chat/completions -H "Authorization: Bearer <КЛЮЧ>" -H "Content-Type: application/json" --data-binary "@req.json" **Первые запросы будут медленными** — эксперты ещё не в RAM и читаются с NVMe. После нескольких запросов «горячие» эксперты оседают в кэше, скорость растёт. Замеряйте 3–5 запросов подряд. ===== Шаг 8: Подстройка скорости ===== Меняйте по одному параметру (**Apps → llama-qwen → Edit**) и сравнивайте ''predicted_per_second'': * **''--moe-cache-mib''** — больше кэша экспертов на GPU, если VRAM свободна (''nvidia-smi''). Обычно самый заметный эффект. * **''--n-cpu-moe N''** вместо ''--cpu-moe'' — эксперты первых N слоёв на CPU, остальных — **целиком на GPU**. Например ''--n-cpu-moe 44'' — эксперты 4 последних слоёв в VRAM. Подбирать, пока хватает VRAM. * **''-t''** — 6 / 12 / 14 потоков; E-ядра иногда замедляют. * **''-c''** — меньше контекст → больше VRAM под эксперты. * **Свободная RAM** — остановка тяжёлых приложений даёт больше места под кэш страниц → меньше чтений с NVMe. * **''-lm dio''** (Direct I/O) — читать веса в обход кэша страниц. Обычно медленнее, имеет смысл только для экспериментов. Активность диска: **Reports → Disk** (или ''zpool iostat -v appData 2'' под root) — при «прогретом» кэше чтений с NVMe во время генерации должно быть мало. ===== Шаг 9: Подключение клиентов ===== ^ Параметр ^ Значение ^ | Тип API | OpenAI Compatible | | Base URL | ''http://192.168.1.135:30081/v1'' | | Chat Completions | ''http://192.168.1.135:30081/v1/chat/completions'' | | API Key | ''<КЛЮЧ>'' | | Модель | ''qwen3.8-flash-next'' (значение ''--alias'') | ==== Goose Desktop ==== Settings → Models → **Add Custom Provider**: Provider Type **OpenAI Compatible**, Display Name ''llama.cpp Server'', API URL ''http://192.168.1.135:30081/v1/chat/completions'', API Key ''<КЛЮЧ>'', Available Models ''qwen3.8-flash-next'', Streaming — вкл. Или файлом ''%APPDATA%\Block\goose\config\custom_providers\custom_llama_server.json'': { "name": "custom_llama_server", "engine": "openai", "display_name": "llama.cpp Server", "description": "llama.cpp on TrueNAS 192.168.1.135:30081", "api_key_env": "CUSTOM_LLAMA_SERVER_API_KEY", "base_url": "http://192.168.1.135:30081/v1/chat/completions", "models": [ { "name": "qwen3.8-flash-next", "context_limit": 65536 } ], "headers": null, "timeout_seconds": 600, "supports_streaming": true, "requires_auth": true } Ключ — в Settings → Models у провайдера. Русский язык и MCP — как в [[:truenas:application:strata_qwen_goose|инструкции для ПК]]. ==== Open WebUI (уже стоит на сервере) ==== Admin Panel → Settings → Connections → OpenAI API → URL ''http://192.168.1.135:30081/v1'', Key ''<КЛЮЧ>''. Остальные клиенты (OpenCode, Claude Code, Python) — как на странице [[:truenas:application:strata_qwen_server|Strata на TrueNAS]], с адресом ''http://192.168.1.135:30081/v1'' и моделью ''qwen3.8-flash-next''. ===== Несколько моделей / смена модели ===== * **Сменить модель** — **Edit** → поменять путь в ''-m'' (и при желании ''--alias'') → Save. * **Не запускайте одновременно** ''llama-qwen'' и ''strata'' (после обновления TrueNAS) — они делят одну видеокарту. * Удалить ненужную модель — удалить её папку в ''/mnt/appData/llm-models''. ===== Безопасность ===== * Порт 30081 открыт всей домашней сети — ключ обязателен. Не пробрасывайте порт на роутере в интернет; доступ извне — через VPN или ''nginx-proxy-manager'' с HTTPS. ===== Проблемы и решения ===== ==== unknown model architecture: 'qwen4exp' ==== Слишком старая сборка llama.cpp. Используйте свежий тег ''server-cuda-bNNNNN'' (поддержка добавлена в 2026-08, PR #27742). ==== Нет GPU в логах / no CUDA devices ==== В YAML нет блока ''deploy … nvidia'' или видеокарту не видит Docker: на сервере ''docker run --rm --gpus all ghcr.io/ggml-org/llama.cpp:server-cuda-b12316 --list-devices''. ==== CUDA out of memory при загрузке ==== Видеокарту держат другие приложения («Шаг 1») — либо уменьшите ''--moe-cache-mib'' и ''-c''. ==== Очень медленно (меньше 1–2 токенов/с) ==== * Кэш ещё не прогрет — сделайте несколько запросов. * Мало свободной RAM — остановите тяжёлые приложения; проверьте ''free -g'' (столбец ''available''). * Модель слишком большая для RAM этого сервера — возьмите квант меньше. * Попробуйте ''primarycache=metadata'' («Шаг 2»). ==== Модель не найдена ==== Путь в ''-m'' — **внутри контейнера** (''/models/...''), а не ''/mnt/appData/...''. Проверка: ''ls /mnt/appData/llm-models/<папка>''. ===== Шпаргалка ===== docker logs -f llama-qwen nvidia-smi free -g curl -s http://192.168.1.135:30081/v1/models -H "Authorization: Bearer <КЛЮЧ>" ^ Что ^ Значение ^ | Адрес API | ''http://192.168.1.135:30081/v1'' | | Модель (API) | ''qwen3.8-flash-next'' | | Модели на диске | ''/mnt/appData/llm-models'' (NVMe) | | Образ | ''ghcr.io/ggml-org/llama.cpp:server-cuda-b12316'' |