Когда терпение заканчивается: что стоит за этими тремя минутами
Вы запускаете llama.cpp, отправляете первый запрос и... ждете. Три минуты. Иногда пять. Модель молчит, процессор гудит, а вы смотрите на пустой экран. Знакомо? Эта задержка - не баг, а фича. Очень раздражающая фича.
Что происходит в эти три минуты? Модель не "думает". Она делает две вещи: загружает веса в оперативку (или VRAM) и компилирует вычислительные ядра под ваше железо. Каждый раз. При каждом запуске. Даже если вы только что закрыли и снова открыли программу.
Вот вам цифры: модель на 13 миллиардов параметров в формате Q4_K_M занимает около 7.5 ГБ. Загрузка с SSD на скорости 500 МБ/с - это 15 секунд. Остальные 2:45 - компиляция ядер. Каждый. Раз.
Хирургическое вмешательство: отключаем ненужные проверки
Основной виновник - флаг --no-kv-offload. Вернее, его отсутствие. По умолчанию llama.cpp пытается оптимизировать использование памяти, что приводит к постоянной перекомпиляции ядер. Нужно это отключить.
Второй момент - кэш компилированных ядер. Он существует, но работает... странно. Иногда сбрасывается. Иногда не применяется. Нужно заставить его работать принудительно.
1 Готовим инструменты: что понадобится
Вам нужна свежая версия llama.cpp. Не та, что вы скачали месяц назад. За последние полгода в компиляцию ядер внесли десятки улучшений. Качаем и собираем:
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make clean && make -j$(nproc)
Если у вас NVIDIA карта, добавьте LLAMA_CUDA=1. Для AMD с ROCm - LLAMA_HIPBLAS=1. Подробнее про оптимизацию под AMD есть в отдельном гайде.
2 Первый запуск: создаем кэш ядер
Запускаем модель с ключевыми флагами. Вот команда, которая выглядит страшно, но работает:
./main -m models/mistral-7b-v0.1.Q4_K_M.gguf \
--prompt "Hello" \
--n-predict 10 \
--no-kv-offload \
--flash-attn \
--batch-size 512 \
--ctx-size 2048 \
--keep 0
--no-kv-offload - отключает оптимизацию памяти, которая заставляет перекомпилировать ядра. --flash-attn - использует более быстрые ядра (если поддерживаются). --batch-size 512 и --ctx-size 2048 - фиксируют размеры, чтобы кэш был актуален для ваших типичных запросов.Этот запуск все еще займет 2-3 минуты. Но теперь он создаст кэш ядер. Не прерывайте его, даже если видите "Hello" в ответе. Дождитесь полного завершения.
3 Проверяем и фиксируем кэш
Кэш ядер сохраняется в ~/.cache/ggml/ или ~/.cache/llama.cpp/ в зависимости от версии. Найдите файлы с расширением .cl (OpenCL) или .cu (CUDA).
Скопируйте их в безопасное место:
mkdir -p ~/llama_cache
cp ~/.cache/ggml/*.cl ~/llama_cache/ 2>/dev/null || true
cp ~/.cache/ggml/*.cu ~/llama_cache/ 2>/dev/null || true
Теперь, даже если системный кэш сбросится, у вас будет резервная копия.
Серверный режим: здесь все еще хуже
Если вы используете llama-server, проблема усугубляется. Сервер компилирует ядра при каждом запуске, даже если модель уже загружена в память. И да, это касается и RPC-сервера.
Решение: запустить сервер в фоновом режиме один раз и не выключать. Но если нужно перезагрузить - вот рецепт.
./server -m models/llama-2-13b.Q4_K_M.gguf \
--host 0.0.0.0 \
--port 8080 \
--no-kv-offload \
--flash-attn \
--cont-batching \
--parallel 1 \
--ctx-size 4096 \
--batch-size 1024
Ключевые моменты: --cont-batching включает непрерывную обработку батчей (меньше пауз), --parallel 1 отключает параллельную обработку нескольких запросов (которая ломает кэш).
Внимание: если вы планируете использовать несколько моделей одновременно, для каждой нужен отдельный серверный процесс. И для каждой - свой кэш ядер. Иначе компиляция все равно произойдет.
Где собака зарыта: частые ошибки
Вы все сделали по инструкции, а задержка осталась? Вот где обычно ошибаются:
- Меняете размер контекста. Кэш ядер привязан к конкретному
--ctx-size. Если в первый раз было 2048, а потом вы запустили с 4096 - компиляция начнется заново. - Обновили драйверы видеокарты. Новые драйверы = новый кэш. Придется перекомпилировать.
- Используете разные версии llama.cpp. Кэш от версии v1000 несовместим с v1001. Разработчики меняют форматы.
- Не хватает памяти. Если при компиляции ядер система начинает свопиться, кэш может записаться с ошибками. Проверьте
free -hперед запуском.
Еще один подводный камень - модели с разной квантованием. Q4_K_M и Q5_K_S требуют разных ядер. Да, даже если это одна и та же архитектура.
А что насчет Windows и Mac?
На Windows та же история, но пути к кэшу другие: %APPDATA%\ggml\ или %LOCALAPPDATA%\llama.cpp\. Флаги командной строки идентичные.
На Mac с Apple Silicon есть своя особенность: Metal Shading Language кэшируется в системном кэше, который чистится реже. Но если вы столкнулись с преждевременным EOS (как в случае с GLM-4.5-Air), компиляция может сбрасываться чаще.
Для Mac добавляем:
--metal
--gpu-layers 999
Последний флаг загружает все слои на GPU, что уменьшает задержки на обмене с RAM.
Экстремальная оптимизация: когда каждая секунда на счету
Если вы готовы потратить час на настройку, но потом получать ответы за 2 секунды вместо 3 минут, вот план:
- Создайте скрипт предзагрузки, который запускает все ваши модели с типичными параметрами и ждет завершения компиляции.
- Настройте systemd-юнит (на Linux), который запускает этот скрипт при загрузке системы.
- Для сервера используйте супервизор типа supervisorctl, который перезапускает процесс, если он падает, но сохраняет кэш.
- Регулярно (раз в неделю) обновляйте кэш, запуская скрипт заново.
Пример скрипта предзагрузки:
#!/bin/bash
MODELS=("models/mistral-7b.Q4_K_M.gguf" "models/llama-2-13b.Q4_K_M.gguf")
CTX_SIZES=(2048 4096)
for i in "${!MODELS[@]}"; do
echo "Precompiling ${MODELS[i]} with ctx-size ${CTX_SIZES[i]}"
timeout 300 ./main -m "${MODELS[i]}" \
--prompt "test" \
--n-predict 1 \
--no-kv-offload \
--ctx-size "${CTX_SIZES[i]}" \
--batch-size 512 \
--flash-attn \
--silent
echo "Done"
done
Этот скрипт прогружает все модели по очереди. timeout 300 убивает процесс через 5 минут, если что-то пошло не так.
Что делать, если ничего не помогло
Бывает. Обычно в трех случаях:
- У вас очень старая видеокарта без поддержки современных вычислительных стандартов.
- Модель использует экзотическую архитектуру (например, с Sliding Window Attention, как PLaMo 3), для которой в llama.cpp нет оптимизированных ядер.
- Вы запускаете модель, которая не помещается в память, и система постоянно свопится.
В первых двух случаях поможет только апгрейд железа или ожидание новых версий llama.cpp. В третьем - уменьшение размера модели или использование более агрессивного квантования.
И последний совет: иногда проще смириться с задержкой на первом запросе, но настроить --keep -1 (бесконечный контекст) и просто не выключать llama.cpp сутками. Неэлегантно, но работает.
А если серьезно - разработчики llama.cpp знают о проблеме. В каждом релизе улучшают кэширование. Возможно, через полгода эта статья станет неактуальной. Но пока - пользуйтесь.