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

Большая LLM на маленькой видеокарте. KTransformers на RTX 5060 Ti 16 ГБ - впихнуть не впихуемое

Просмотров: 251 Практический опыт поднятия локальной LLM для агентной работы (кодинг, 1С-Битрикс, PHP) на связке KTransformers + SGLang. Модель Ornith-1.0-35B в кванте Q8_0, видеокарта RTX 5060 Ti 16 ГБ, 64 ГБ оперативной памяти, контекст 200K токенов.
Большая LLM на маленькой видеокарте. KTransformers на RTX 5060 Ti 16 ГБ - впихнуть не впихуемое

1. Задача: поднять локальный LLM-сервер, который не падает на длинных контекстах

Требования: контекст не меньше 190K токенов (это жёсткое требование для агентных сессий с большим кодом), адекватная скорость генерации, бесплатный запуск.

Железо:

  • CPU: AMD Ryzen 5 7500F (6 физических ядер / 12 потоков)
  • RAM: 64 ГБ DDR5
  • GPU: NVIDIA RTX 5060 Ti 16 ГБ (Blackwell, sm_120)
  • Диск: NVMe 1 ТБ
  • ОС: Linux Mint 22 (база Ubuntu 24.04)

Модель: Ornith-1.0-35B, архитектура Qwen-MoE (qwen35moe). Всего 40 слоёв, в каждом 256 экспертов, активных 8 (top-k). Есть две копии весов: GGUF Q8_0 (35 ГБ) и полные safetensors BF16 (66 ГБ).

2. Почему KTransformers, а не llama.cpp

llama.cpp размещает слои MoE по номерам: первые N слоёв на GPU, остальные на CPU. Тупое последовательное деление, без учёта того, какие эксперты реально работают.

KTransformers размещает по частоте использования: горячие эксперты (которые роутер реально дёргает) живут в VRAM, холодные на CPU. В теории умеет динамически перекладывать экспертов по ходу работы (об этом отдельный нюанс ниже, там не всё гладко).

На практике это даёт примерно 20-24 t/s на 35B модели при 16 ГБ VRAM, когда модель целиком в VRAM не влезает.

3. Что нужно для запуска: две копии модели

Для KTrans нужны ОБЕ копии весов одной модели:

  • safetensors (BF16, полные) - для GPU-части
  • GGUF (Q8_0, квантованный) - для CPU-части

Это не дубль. Это два разных набора весов для двух разных вычислителей. Без safetensors GPU-экспертам неоткуда взять точные веса, без GGUF CPU-часть считала бы в 2 раза больше байт.

4. Как устроены эксперты: BF16 на GPU, Q8 на CPU

Тут важный нюанс, который легко понять неправильно:

  • GPU-эксперты = BF16 из safetensors (полная точность)
  • CPU-эксперты = Q8_0 из GGUF (квантованные)
  • Внимание, эмбеддинги, норм-слои, роутер - всегда на GPU в BF16

То есть "мозг" (что считать и как связывать токены) максимально точный, а "работяги" (масса экспертов) сжаты до 1 байта на вес. Это и есть гениальность гибридной схемы.

Было ошибкой считать, что горячие эксперты на GPU в Q8_0. Нет: код sglang-kt копирует GPU-экспертов из safetensors в BF16. Отсюда честный расчёт VRAM: один эксперт Ornith = 6 МБ в BF16 (или 3.2 МБ в Q8_0).

5. Установка KTransformers

Установка в отдельный venv, CUDA 12.8 для Blackwell:

python3 -m venv /opt/ktrans/venv
/opt/ktrans/venv/bin/pip install torch --index-url https://download.pytorch.org/whl/cu128
/opt/ktrans/venv/bin/pip install kt-kernel sglang-kt
/opt/ktrans/venv/bin/pip install nvidia-cudnn-cu12==9.16.0.29
sudo apt install ninja-build

Проверка что всё поднялось: curl сервера должен отвечать по OpenAI-совместимому API.

6. Финальный конфиг запуска

Проверенный рабочий конфиг для Ornith-35B на 16 ГБ VRAM с контекстом 200K:

python -m sglang.launch_server \
  --host 0.0.0.0 --port 8080 \
  --model /models/ornith-35b-safetensors \
  --kt-weight-path /models/ornith-35b/Ornith-1.0-35B-Q8_0.gguf \
  --kt-cpuinfer 6 --kt-threadpool-count 1 \
  --kt-num-gpu-experts 4 \
  --kt-expert-placement-strategy uniform \
  --kt-method LLAMAFILE \
  --attention-backend triton \
  --trust-remote-code --mem-fraction-static 0.90 \
  --max-running-requests 1 --max-total-tokens 200000 \
  --max-mamba-cache-size 23 \
  --chunked-prefill-size 4096 --enable-mixed-chunk \
  --served-model-name ornith-35B-Q8_0 \
  --reasoning-parser qwen3-thinking \
  --tool-call-parser qwen3_coder

Каждый флаг тут стоит внимания, и за несколькими спрятаны грабли, которые мы откопали. Обратите внимание: в конфиге НЕТ --kt-enable-dynamic-expert-update. Почему - в нюансе 4, это важно.

7. Нюанс 1: mem-fraction-static и настоящий KV-кэш

mem-fraction-static это доля видеокарты, которую sglang отдаёт под рабочую зону: KV-кэш + модель + эксперты. Остальное резерв под буферы.

Мы стартовали с 0.72 (по советам из старых статей) и получили сюрприз. Таблица замеров (на ранней конфигурации с 400 экспертов и без лимита mamba):

mem-fractionKV-кэш (токенов)Вердикт
0.7282Kконтекст режется, плохо
0.85168Kлучше
0.88182Kблизко
0.90189Kпочти
0.92198.9Kцель достигнута
Проблема: с mem-fraction 0.72 контекст молча обрезался до 82K токенов. Клиент думал, что шлёт 200K, а сервер резал на 82K. Реальный размер KV-кэша видно только в логах запуска, строка "KV Cache is allocated. #tokens".

Вывод: если нужен честный большой контекст, mem-fraction надо поднимать. И всегда проверять фактический #tokens в логе, а не верить на слово.

8. Нюанс 2: сколько экспертов реально влезает

Сначала думал так: поставлю 400 экспертов (10/слой), места много. Арифметика: 400 x 6 МБ BF16 = 2.4 ГБ, вроде влезает. Не влезло вместе с 200K контекстом.

Экспертов (на слой)ВсегоKV-кэш получился
1040082K
5200198.9K (при mem-fraction 0.92)
4160200K ровно (при mem-fraction 0.90)

Ограничитель не один: эксперты + KV-кэш + плотные слои должны поместиться в рабочий пул. Плотная часть (внимание, эмбеддинги, mamba-состояния) занимает ~6.7 ГБ и её не трогать. Остальное делим между экспертами и KV.

Рабочая формула для 16 ГБ и 200K: 160 экспертов (4/слой) + mem-fraction 0.90 дают KV ровно 200000 и свободные 3.25 ГБ. Хот-сет Битрикс-кодинга это 50-80 экспертов, так что 160 это 80 рабочих + 80 запасных.

Шаг не фиксирован: --kt-num-gpu-experts задаётся на слой (целое), итог = N x 40 слоёв. 300 ровно нельзя целым (300/40=7.5), тогда --kt-gpu-experts-ratio.

9. Нюанс 3: frequency без статистики даёт кривое распределение

Мы запустили с --kt-expert-placement-strategy frequency и обнаружили в логах странность: все 400 экспертов свалились в 3 слоя (25:80, 26:192, 27:128), остальные 37 слоёв пустые.

Разобрались по исходникам: frequency без файла активаций (--init-expert-location) ставит всем экспертам частоту 1.0 и делает torch.topk по всей модели. При равных весах topk выбирает произвольно, отсюда кучкование.

Нюанс: frequency имеет смысл ТОЛЬКО с файлом статистики активаций. Без него лучше uniform: тот раскладывает ровно по 4 эксперта на слой.

10. Нюанс 4: dynamic update ЛОМАЕТ LLAMAFILE

Главный грабли, на которые мы потратили больше всего времени. Документация обещает: включи --kt-enable-dynamic-expert-update + --kt-gpu-prefill-token-threshold, и эксперты будут перекладываться в VRAM на лету под текущую задачу.

Реальность: на LLAMAFILE-бэкенде это валит сервер. При первом же перераспределении экспертов (когда наступает prefill длиннее порога):

AttributeError: 'LlamafileMoEWrapper' object has no attribute 'submit_write_weight_scale_to_buffer'
SIGQUIT received. It usually means one child failed.

Причина по исходникам: метод submit_write_weight_scale_to_buffer существует только у NativeMoEWrapper (бэкенды FP8/RAWINT4/BF16). У LlamafileMoEWrapper и AMXMoEWrapper его нет, это недостроенная функция, не намеренно выброшенная. Пока нет фикса (все версии до 0.6.4 включительно). Есть открытый issue в репозитории ktransformers, и это ограничение --kt-method, а не конкретного железа.

Вывод: на LLAMAFILE dynamic update не включаем. Используем static uniform. Полноценная динамика (перераспределение экспертов на лету) на LLAMAFILE станет возможна, когда разработчики допилят метод для LlamafileMoEWrapper. Альтернатива уже сейчас: собрать профиль частот через --init-expert-location и дать его frequency на старте - маска будет точной под ваши задачи.

11. Нюанс 5: max_model_len в API обманчив

После запуска /v1/models отвечает max_model_len: 262144, красиво и больше нашего требования. Но это потолок модели из конфига, а не реальный KV-кэш. Реальный KV-кэш виден только в логе запуска.

Проверка: journalctl -u ktransformers | grep "KV Cache is allocated". Если там меньше 200000, контекст будет обрезаться молча.

12. Нюанс 6: kt-cpuinfer считаем по физическим ядрам

--kt-cpuinfer это число потоков CPU для экспертов. Документация прямо говорит: физические ядра, а не hyperthreads. У Ryzen 7500F физических ядер 6, поэтому kt-cpuinfer 6. Не поднимать выше.

13. Нюанс 7: Secure Boot ломает драйвер после обновления ядра

Сначала сервер работал. Потом apt upgrade обновил ядро, DKMS пересобрал nvidia-модуль под новый MOK-ключ, а ключ не был зарегистрирован в Secure Boot. Начало сыпаться "modprobe: Key was rejected by service".

Лечится отключением Secure Boot в BIOS или регистрацией MOK-ключа через mokutil. Для домашнего сервера проще отключить Secure Boot: он только мешает при каждом обновлении ядра.

14. Нюанс 8: Blackwell требует attention-backend triton

RTX 5060 Ti это Blackwell (sm_120). Для гибридных GDN-моделей sglang на Blackwell разрешает только два backend: triton или trtllm_mha. Без --attention-backend triton будет AssertionError.

Из этого вытекает ещё один нюанс: FP8 KV-кэш (--kv-cache-dtype fp8_e4m3) на triton backend не работает, потому что в triton-кернелах нет FP8. Если захочется экономить VRAM на KV через FP8, придётся менять весь attention-путь на trtllm_mha, а его докстринг заявляет поддержку только sm100. Мы решили не трогать и оставить KV в BF16.

15. Нюанс 9: лимит mamba-кэша обязателен

Сначала этого нюанса в статье не было, но он чуть не похоронил сервер. У гибридных моделей (30 linear-attention слоёв из 40) есть mamba-подобные состояния, и sglang без лимита выделяет под них с запасом.

Без --max-mamba-cache-size 23 при mem-fraction 0.92 сервер выделил 3.46 ГБ под mamba-кэш, свободно осталось 1.2 ГБ. Когда Kilo запустил компакцию контекста (большой prefill на ~155K токенов), ей понадобилось 2.5 ГБ временных буферов - произошёл OOM, сервер упал с Connection reset.

С лимитом 23: mamba-кэш занимает 1.41 ГБ, свободно 3.25 ГБ, компакция проходит спокойно. Дополнительно в Environment юнита добавили PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True против фрагментации памяти.

Второй урок про компакцию: на больших контекстах (150K+) компакция это самый жадный момент, она резко резервирует ~2.5 ГБ буферов. Плюс снизили --chunked-prefill-size с 8192 до 4096, чтобы пик памяти при prefill был вдвое меньше.

16. Результаты: скорость и распределение

Реальные замеры на рабочей нагрузке (агентная сессия, кодинг):

  • Decode: 21-24.5 t/s при контексте 16-46K токенов
  • Prefill прогретый: до 290 t/s (первый холодный запрос медленный, дальше быстрый)
  • Radix-кэш работает: повторные префиксы не пересчитываются (cached-token)
  • GPU util во время генерации: 43%
  • CPU util: 63% (шесть потоков считают экспертов)
  • VRAM в работе: 13.5-15 ГБ из 16.3

Финальная конфигурация: 160 экспертов (4/слой, uniform), KV-кэш ровно 200000 токенов, свободно 3.25 ГБ. Сервер стабильно работает часами, включая компакции на 150K+ контекстах.

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

  • curl localhost:8080/v1/models - сервер отвечает
  • journalctl -u ktransformers | grep "KV Cache is allocated" - смотрим настоящий #tokens, должно быть >= 190K
  • journalctl -u ktransformers | grep "total GPU experts" - смотрим сколько экспертов реально на GPU
  • nvidia-smi - сколько свободно VRAM, не должно быть 0
  • Прогнать длинный запрос 20K+ токенов, проверить что не OOM
  • Проверить компакцию: загнать контекст на 150K+, убедиться что сервер не падает

18. Планы на эксперименты

  • Профиль частот (--init-expert-location): сервер умеет собирать статистику активаций экспертов (--expert-distribution-recorder-mode stat, буфер можно сделать бесконечным). Прогнать реальные задачи, выгрузить профиль, скормить frequency - стартовое распределение станет точным под ваши задачи.
  • Deferral экспертов (--kt-max-deferred-experts-per-token): CPU считает прошлый токен, пока GPU считает текущий. Обещает +45% к decode при потере точности меньше 0.5%. Начинать с 1.
  • Динамическое перераспределение: ждём фикса в ktransformers (issue про LlamafileMoEWrapper), тогда вернём --kt-enable-dynamic-expert-update.

Итог

KTransformers реально работает на 16 ГБ видеокарте с 35B MoE моделью и честным 200K контекстом. Скорость 21-24 t/s комфортна для агентной работы.

Но конфигурация требует внимания, главные грабли: mem-fraction-static (молча режет контекст, смотрите #tokens в логе), частота экспертов (frequency без профиля даёт кривое распределение, используйте uniform), лимит mamba-кэша (без него OOM на компакции) и dynamic update (на LLAMAFILE пока не работает, ждём фикс).

Проверяйте фактический KV-кэш в логах, а не max_model_len из API. И помните: всё, что вы видите в этом гайде, добыто методом проб и ошибок на реальном железе.

Услуги Стоимость разработки на 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С-Битрикс