Михаил Базаров Разработка на 1С-Битрикс Михаил Базаров

Большие LLM на маленькой видеокарте - впихнуть не впихуемое

Просмотров: 57 Собирал себе локальную нейросеть для разработки (PHP, 1С-Битрикс, кодинг). Облачные API жрут деньги и тормозят, а свой сервер работает бесплатно и без интернета. Расскажу, почему взял Linux, как собрал llama.cpp с MoE Hot-Cache и как запустить всё это у себя по шагам.

Исходные условия: недорогой системник с видеокартой на 16 ГБ VRAM. Один из главных вопросов - а влезет ли большая модель в маленькую карту. Влезает, если правильно подойти. Ниже весь мой практический опыт, включая грабли, на которые я наступил.

Железо

Собирал на такой конфигурации:

  • CPU: AMD Ryzen 5 7500F (6 ядер / 12 потоков)
  • RAM: 64 ГБ DDR5
  • GPU: NVIDIA RTX 5060 Ti 16 ГБ (Blackwell, sm_120)
  • Диск: NVMe 937 ГБ
  • ОС: Ubuntu 24.04

64 ГБ оперативки и NVMe тут не роскошь, а необходимость. Большие модели (например 122B) целиком в 16 ГБ VRAM не влезают, поэтому веса ложатся в RAM, а часть ещё дальше - в swap. Диск нужен быстрый, чтобы читать модель без фризов.

Почему Linux, а не Windows

  • llama.cpp и форки собираются под Linux в разы проще. Windows чаще всего требует WSL или готовые бинарники, а когда нужен свой форк с нестандартными флагами (как MoE Hot-Cache) - под WSL это мучение.
  • Headless. Сервер не должен грузить графическую оболочку. На Windows интерфейс и фоновая графика висят в памяти и постоянно мешают. На Linux серверную часть можно оставить вообще без десктопа.
  • Меньше оверхеда в RAM. Голая Ubuntu без GUI ест полтора-два гигабайта. Windows со своим интерфейсом отжирает в несколько раз больше, а каждый гигабайт в 64 ГБ на счету.
  • NVIDIA-драйвер и CUDA ставятся из коробки под Ubuntu. Плюс Secure Boot я отключил в BIOS, чтобы обновления ядра не ломали модуль драйвера (об этом ниже).
  • Автозапуск и systemd. Сервисы, ватт-лимит GPU, поднимание swap - всё это штатно описывается юнитами и поднимается при старте, без шаманств.

Если коротко: для серверного процесса Linux даёт предсказуемое окружение, которое работает само и не мешает. Windows в этой роли просто неудобен.

Почему именно llama.cpp с MoE Hot-Cache

Классический llama.cpp раскладывает слои MoE-модели по номерам: первые N слоёв в VRAM, остальные в RAM - без учёта того, какие эксперты реально работают. А в MoE-моделях на каждый токен активируется только маленькая часть экспертов (top-k), остальные сотни просто ждут.

Форк с MoE Hot-Cache работает умнее: он собирает статистику, какие эксперты роутер реально дёргает под ваши задачи, и держит именно их в VRAM. Холодные эксперты живут в RAM и догружаются при необходимости. Для кодинга на Битриксе горячий набор экспертов стабильный, поэтому ускорение реальное, а не на бумаге.

На практике на моих моделях hit-rate (доля обращений к экспертам, которые уже лежат в VRAM) держится на уровне 50-70%. Скорость decode у KAT-Coder (35B MoE) получилась 42-45 t/s на 16 ГБ карте. Для агентной работы с большим кодом это комфортно.

Что в итоге за модели я гоняю

Остановился на связке из нескольких моделей под разные задачи:

  • KAT-Coder-V2.5 (35B MoE, Q8_0) - основная рабочая лошадка для кода. Быстрая, хорошо понимает PHP и Битрикс.
  • Qwen3.6-Heretic (35B MoE, Q8_0) - без цензуры, для творческих и общих задач.
  • Qwen3.5-122B (MoE, UD-Q6_K, ~117 ГБ) - когда нужно максимальное качество и не жалко времени. Работает через swap, медленно (~4 t/s), но для сложных архитектурных вопросов незаменима.
  • Gemma-4-12B (dense, Q8_0 / Q6_K / uncensored-Q4) - лёгкие dense-модели для быстрых задач.
  • Qwen3.8-4B (dense, BF16 / Q8_0) - самая маленькая и мгновенная.

Все они висят в одном конфиге и переключаются одной командой.

Установка: драйвер и CUDA

Ставил свежие драйвер и CUDA Toolkit. У RTX 5060 Ti архитектура Blackwell (sm_120), поэтому нужен именно свежий тулкит, старые версии не поймут эту архитектуру.

# Драйвер NVIDIA
sudo apt install nvidia-driver-595

# CUDA Toolkit (в моём случае 13.2)
wget https://developer.download.nvidia.com/compute/cuda/
sudo sh cuda-toolkit.run --toolkit

# Проверка
nvidia-smi
Обязательно отключи Secure Boot в BIOS. Иначе после первого же обновления ядра DKMS пересоберёт nvidia-модуль под новый MOK-ключ, ключ не зарегистрирован, и драйвер перестанет грузиться с ошибкой "Key was rejected by service". Для домашнего сервера Secure Boot только мешает.

Сборка llama.cpp с MoE Hot-Cache

Скачивал форк, собирал под свою архитектуру. Ключевой момент - сборка с поддержкой CUDA именно для sm_120.

git clone https://github.com/adrianhoehne/llama.cpp-hotcache.git
cd llama.cpp-hotcache
mkdir build && cd build

cmake .. -DGGML_CUDA=ON \
  -DCMAKE_CUDA_ARCHITECTURES=120 \
  -DGGML_NATIVE=OFF

make -j$(nproc)

На выходе получаем бинарник llama-server, который умеет в флаги MoE hot-cache. Проверить наличие можно так:

./bin/llama-server --help | grep -i moe-hot-cache

Куда складывать модели

Все модели лежат в отдельной папке, чтобы легко управлять размером и не путаться. Для многотомных GGUF (когда модель разбита на несколько файлов) llama.cpp сам подхватывает все части, если указать первый файл с суффиксом вида -00001-of-00004.

mkdir -p /opt/llm/LLM_MODELS/MY_MODELS

Качал с HuggingFace прямым curl-ом с поддержкой докачки. Удобно, когда оборвалось или комп переносили:

curl -L --fail --retry 3 -C - \
  -o ModelName-Q8_0.gguf \
  "https://huggingface.co/author/Model-GGUF/resolve/main/ModelName-Q8_0.gguf"

Флаг -C - позволяет продолжить докачку с места обрыва. Для больших моделей это спасение.

Конфиг моделей

Завёл файл models.conf, в котором каждая строка описывает одну модель. Поля разделены символом |:

# имя|путь|reasoning(off/on)|MOE_MAX_MIB|MOE_RESERVE_MIB|extra

# MoE модели (горячий кэш экспертов работает)
KAT-Coder-V2.5-Q8_0|/opt/llm/LLM_MODELS/MY_MODELS/KAT-Q8_0.gguf|off|-1|3072|

# Dense модели (hot-cache не нужен, MOE_MAX_MIB=0)
Gemma-4-12B-Q8_0|/opt/llm/LLM_MODELS/MY_MODELS/gemma-q8_0.gguf|off|0|3072|--ctx-size 155000

# Большая MoE с особыми флагами (колонка extra)
Qwen3.5-122B|/opt/llm/LLM_MODELS/MY_MODELS/qwen-00001-of-00004.gguf|on|-1|5120|--batch-size 1024 --ubatch-size 1024

Разберу поля:

  • reasoning - off отключает блок размышлений модели, on включает. Для думающих моделей я ставлю лимит бюджета размышлений.
  • MOE_MAX_MIB - размер горячего кэша экспертов в мегабайтах. -1 это автосайзинг под свободную VRAM, 0 отключает hot-cache (для dense-моделей он не нужен), положительное число фиксирует размер.
  • MOE_RESERVE_MIB - резерв памяти, который не трогаем, чтобы хватило на KV-кэш и рабочие буферы.
  • extra - дополнительные флаги, которые перекрывают базовые. Пригодилось для 122B (уменьшить batch) и для ограничения контекста у некоторых моделей.

Скрипт управления llm.sh

Написал простой менеджер llm.sh, который умеет показывать статус, запускать и останавливать любую модель из конфига. Вызывается так:

# Показать статус и список моделей
llm.sh status

# Запустить конкретную модель
llm.sh start KAT-Coder-V2.5-Q8_0

# Остановить
llm.sh stop

# Интерактивное меню
llm.sh menu

Скрипт собирает аргументы для запуска. Базовый набор общий для всех:

--ctx-size 200000 --batch-size 4096 --ubatch-size 4096 \
--n-gpu-layers 99 --flash-attn on \
--cache-type-k q8_0 --cache-type-v q8_0

Для MoE-моделей (когда MOE_MAX_MIB не ноль) добавляются флаги горячего кэша:

--cpu-moe \
--moe-hot-cache profile.json \
--moe-hot-cache-max-mib -1 \
--moe-hot-cache-auto-reserve-mib 3072 \
--moe-hot-cache-update-rate 0.10 \
--moe-hot-cache-pp-reduce-merge auto \
--moe-hot-cache-shrink-low-water-mib 1024 \
--moe-hot-cache-refill-min-gain-mib 256 \
--auto-learn

--auto-learn собирает профиль активации экспертов под warmup-промпт. У меня warmup-промпт под Битрикс-кодинг: попросить написать PHP-функцию с MySQL и HTML-таблицей. Профиль сохраняется и переиспользуется, так что при следующем старте распределение экспертов уже точное.

Лимит размышлений для думающих моделей

У моделей вроде Qwen есть режим рассуждений (reasoning), когда модель сначала "думает" и выдаёт блок с размышлениями, а потом ответ. На длинных задачах этот блок может раздуться до десятков тысяч токенов и съесть всё время и контекст.

Ставлю жёсткий лимит бюджета размышлений, чтобы модель не улетала в бесконечное самокопание:

--reasoning on --reasoning-preserve --reasoning-budget 500

Модель может подумать, но не больше 500 токенов на размышления. Для кодинга этого обычно хватает. Когда лимит исчерпан, сервер принудительно закрывает блок думания тегом </think>, и модель переходит к обычному ответу. Ответ получается менее продуманным на сложных задачах, но он всегда будет целым - сервер не зависнет и не упадёт.

Параметры лимита задаются в конфиге по полю reasoning: on включает размышления с лимитом, off отключает их полностью.

Грабли 5: модель зацикливается в размышлениях

Тут я наступил на интересную граблю. Думающая модель иногда начинала генерировать одно и то же предложение внутри блока размышлений бесконечно - по кругу, пока не упрётся в лимит контекста. Выглядит как зависание, хотя процесс жив.

Причина - повтор токенов при "жадном" (низкотемпературном) сэмплинге, который используется на этапе размышлений. Любой малейший bias в распределении вероятностей выливается в зацикленное повторение одной фразы.

Лечится тремя параметрами, которые в llama.cpp борются именно с повторами:

--repeat-penalty 1.3 \
--presence-penalty 0.4 \
--frequency-penalty 0.4

Разбор:

  • --repeat-penalty - штраф за повторение токенов. Значение 1.3 значит, что уже сгенерированный токен получает меньше шансов появиться снова. Это главный борец с зацикливанием.
  • --presence-penalty - штраф за то, что токен уже встречался в тексте. Давит на повторение целых фраз.
  • --frequency-penalty - штраф тем сильнее, чем чаще токен попадался. Отсекает очень частые повторы.

Один важный нюанс. В моём менеджере llm.sh сначала была глупая ошибка: переменная из конфига записывалась под именем reason, а проверялась как reasoning. Из-за этого значение из конфига никогда не подхватывалось, и все модели запускались с --reasoning off, как бы я их ни настраивал. Модель "думала как попало", а некоторые и вовсе без размышлений. Так что если у вас думающая модель ведёт себя не так, как настроена - в первую очередь проверьте, что скрипт реально читает нужную переменную и передаёт флаг в команду запуска (я проверял через ps -o args).

Анти-повтор флаги добавляю только думающим моделям (когда reasoning=on). Для кодеров без размышлений они не нужны - там точность важнее разнообразия, а без повторов в обычном ответе она и так редко зацикливается.

Грабли 1: CUDA OOM при старте большой модели

Первое, с чем я столкнулся, запуская 122B, - сервер падал на старте с ошибкой cudaMalloc failed: out of memory. Причина в том, что горячий кэш экспертов забирал много VRAM, а потом рабочему буферу не хватало места. Итоговое потребление (кэш + буферы) превышало свободную память карты.

Лечится так:

  • уменьшить --batch-size и --ubatch-size (с 4096 до 1024), это напрямую уменьшает размер рабочих буферов;
  • поднять MOE_RESERVE_MIB, чтобы hot-cache сам не съел весь запас.

В конфиге для 122B это выглядит так:

Qwen3.5-122B|/opt/.../qwen-00001-of-00004.gguf|on|-1|5120|--batch-size 1024 --ubatch-size 1024

После этого 122B стартует и работает, хоть и медленно (через swap).

Грабли 2: модель "зависает" после закрытия SSH

Запускаешь сервер через SSH, закрываешь сессию - и модель молчит, хотя процесс живой. Долго не мог понять, пока не глянул статус процесса: он был в состоянии T (stopped).

Причина в том, что в команде запуска я перенаправил в лог только stdout и stderr, а stdin остался привязан к SSH-терминалу. Когда терминал закрывается, процесс пытается читать stdin, получает сигнал и замирает.

Лечение - перенаправить stdin из /dev/null, чтобы процесс полностью отвязался от терминала:

nohup "$SERVER" "${args[@]}" < /dev/null > server.log 2>&1 &

После этого закрывай SSH сколько хочешь, сервер продолжает работать.

Грабли 3: dense-модели не требуют hot-cache

По началу я было хотел применить ко всем моделям одинаковые флаги. Но у dense-моделей (Gemma-4-12B, Qwen3.8-4B) нет экспертов, значит и горячий кэш им не нужен. Для них ставлю MOE_MAX_MIB=0, тогда скрипт не добавляет MoE-флаги и модель стартует как обычная. Это и быстрее, и меньше мест для ошибок.

Грабли 4: контекст в VRAM для dense

У dense-моделей весь KV-кэш живёт в VRAM (в отличие от MoE, где часть уходит в hot-cache). Если модель весит 12 ГБ, а контекст огромный, KV-кэш может не влезть в 16 ГБ. Тогда ограничиваю контекст через поле extra:

--ctx-size 155000

Для лёгких моделей огромный контекст и не нужен, так что ничего не теряем.

Долгие закачки и перенос компа

Модели на 60-120 ГБ качаются часами. Качал в tmux-сессиях, чтобы закачка жила независимо от SSH. Когда понадобилось выключить комп и перенести, я просто остановил curl - файл остался на диске, а при включении докачал его с того же места флагом -C -. Ничего не потерял.

Что проверить сразу после запуска

  • curl localhost:8080/v1/models - сервер отвечает по OpenAI-совместимому API;
  • curl localhost:8080/health - здоровье;
  • nvidia-smi - сколько занято VRAM, не должно быть 0 и не должно упираться в потолок;
  • в логе запуска посмотреть строку про hot-cache budget, чтобы понять, сколько экспертов реально влезло;
  • прогнать тестовый запрос с реальным кодом и посмотреть hit-rate и скорость decode.

Результаты

На RTX 5060 Ti 16 ГБ с форком llama.cpp и MoE Hot-Cache получается так:

  • KAT-Coder-V2.5 (35B MoE, Q8_0): decode 42-45 t/s, hit-rate 50-70%.
  • Qwen3.5-122B (117 ГБ, через swap): ~4 t/s. Медленно, но работает, что для такого размера уже чудо.
  • Dense-модели (Gemma, Qwen3.8-4B) - почти полностью в VRAM, летают.

Всё отдаётся по OpenAI-совместимому API на порту 8080, так что к серверу цепляются любые инструменты: Continue, Kilo, любые клиенты. Локально, бесплатно, без интернета.

Итог

Связка Linux + llama.cpp с MoE Hot-Cache + RTX 5060 Ti 16 ГБ оказалась очень рабочей для разработчика. MoE-модели на 35B спокойно живут на 16 ГБ видеокарте и выдают приличную скорость, а большую модель можно поднять через swap, когда нужно качество.

Главные грабли, которые стоит держать в голове: не отключайте stdin при запуске через SSH (иначе процесс зависнет), для dense-моделей выключайте hot-cache, для больших MoE уменьшайте batch, ставьте лимит размышлений, а против зацикливания думания добавляйте --repeat-penalty и штрафы повторов. И обязательно проверяйте, что скрипт реально передаёт в команду те флаги, что вы настроили.

Всё, что описано в этом гайде, добыто методом проб и ошибок на реальном железе. Модель ошибается, я ошибаюсь, но вместе мы ошибаемся реже, чем я один без модели. Особенно когда речь о сигнатурах методов и событиях Битрикса.

Услуги Стоимость разработки на 1С-Битрикс

Стоимость разработки сайта зависит от объёма и сложности проекта. Ниже приведены ориентировочные цены, как правило не выходят за обозначенные рамки. Срок разработки зависит от сложности проекта: как правило называю сроки с запасом.
Финальная стоимость и сроки разработки обговариваются на этапе обсуждения. Скачайте опросник на разработку, заполните как можно подробнее и вышлите удобным способом. После ознакомления смогу задать уточняющие вопросы и оценить проект.
Поддержка и доработки проектов
от 3 000 руб. от 1 часа

Выполнение доработок любой сложности. Поддержка, модернизация и расширение функционала существующих проектов. Решение задач: от мелких правок вёрстки до разработки новых модулей.

Подробнее
Сайт на готовом решении 1С-Битрикс
от 70 000 руб. от 5-ти дней

Вариант для тех, кто не хочет тратить много средств на индивидуальный проект, и не имеет серьезных требований к сайту. Магазин, быстро запускается на базе одного из 200-та готовых решений.

Подробнее
Индивидуальная разработка магазина
от 400 000 руб. от 5-ти недель

Разработка магазина на 1С-Битрикс с нуля. Дизайн, сборка и оптимизация производительности под конкретный проект и требования. Реализация любого функционала без ограничений готовых решений.

Подробнее
Мобильное приложение
от 300 000 руб. от 4-х недель

Разработка кроссплатформенного мобильного приложения, которое не уступает нативным решениям как в производительности, так и пользовательском опыте. Публикуется в AppStore, GooglePlay и RuStore

Подробнее
Инфоресурс
от 170 000 руб. от 3-х недель

Информационный ресурс любой сложности. Сайт для СМИ, городской портал или многопользовательская доска объявлений. Внутренние форумы, блоги- по необходимости.

Подробнее
Сайт компании
от 150 000 руб. от 2-х недель

Корпоративный сайт с информационными разделами, каталогом товаров или услуг. Включает формы обратной связи карточек каталога, любое количество статичных и динамичных разделов.

Подробнее

Включено в стоимость разработки:

  • Лицензия на 1С-Битрикс необходимой редакции, дополнительные модули, для реализации функционала и видео-инструкции по работе с готовым проектом
  • Оптимизация программной части проекта и конфигурации сервера под максимальную скорость работы. Базовая СЕО оптимизация и добавление сайта в поисковые системы.

Блог-note Заметки по 1С-Битрикс