Почему твои команды llama.cpp работают в три раза медленнее, чем могли бы
Скопировал команду из чата, запустил модель — работает. Доволен? А теперь посмотри на токены в секунду. 12 вместо 45. 8 вместо 32. Разница не в магии, а в десятке флагов, которые ты не указал, потому что не знал, зачем они нужны.
Документация llama.cpp — это справочник, а не руководство. Она перечисляет аргументы, но молчит о том, что сочетание -ngl 99 -t 8 на 6-ядерном процессоре превратит твой ПК в обогреватель, не добавив скорости. Что -c 4096 на модели с контекстом 8192 — это не просто "запас", а гарантия переполнения памяти через час работы.
Главная ошибка новичков: копировать команды без понимания. То, что работает на RTX 4090 с 24 ГБ VRAM, убьет RTX 4060 с 8 ГБ. То, что ускоряет инференс на CPU, заставит GPU простаивать.
Аргументы — это не флаги, а рычаги управления ресурсами
Представь, что llama.cpp — это двигатель внутреннего сгорания. Аргументы — педаль газа, коробка передач, система охлаждения. Можно ехать на первой передаче с красной зоной тахометра. А можно включить пятую и катить с минимальными оборотами. Результат один — движение. Но износ, шум, расход — разные.
Вот три категории аргументов, которые ты путаешь:
- Ресурсные (-t, -ngl, -tb): распределяют нагрузку между CPU, GPU, RAM. Неправильная настройка = драка за память, троттлинг, падения.
- Качественные (-c, --temp, --top-p): влияют на содержание ответов. Меняют креативность, последовательность, длину.
- Системные (--mlock, --no-mmap, --verbose): работают с ОС. Фиксируют модель в RAM, отключают кэширование, включают отладку.
Разбор аргументов: что скрывается за короткими флагами
| Аргумент | Что делает на самом деле | Опасность |
|---|---|---|
| -t N | Количество потоков CPU. Не равно количеству ядер! На 8-ядерном CPU с Hyper-Threading ставишь 8, а не 16. Потому что llama.cpp лучше работает с физическими ядрами. | Указать больше потоков, чем физических ядер. Получишь переключение контекста, падение производительности на 20-30%. |
| -ngl N | Слои модели на GPU. Не путай с "процентами модели". Каждый слой — это вычисления. 32 слоя на 7B модели = примерно 45% модели в VRAM. | Поставить -ngl 99 на карте с 8 ГБ VRAM для модели 13B. Модель не влезет, начнется swapping в RAM, скорость упадет в 10 раз. |
| -c N | Размер контекста. Потребление памяти растет квадратично! 4096 токенов — это не в 2 раза больше памяти, чем 2048. А в 4 раза. | Выставить -c 8192 "на всякий случай" для модели с 4K контекстом. Получишь OOM (Out Of Memory) на ровном месте. |
| --mlock | Фиксирует модель в RAM. Не дает ОС выгрузить ее в swap. Ускоряет повторные запуски, но съедает RAM постоянно. | Включить на системе с 16 ГБ RAM для модели 13B. ОС не сможет кэшировать диск, система начнет тормозить. |
Сборка команд под конкретное железо: от ноутбука до сервера
1 Ноутбук: i7-14700HX + RTX 4060 (8 ГБ VRAM)
Типичная конфигурация 2024 года. Мощный CPU (20 ядер), но слабая VRAM. Ошибка — грузить все на GPU. Правильно — распределить.
Для модели Llama 3.1 8B (Q4_K_M):
Неправильно: ./main -m llama-3.1-8b.Q4_K_M.gguf -ngl 99 -t 20 --color -c 4096
Почему плохо: -ngl 99 попытается засунуть всю модель в VRAM. Не влезет. Начнется swapping. -t 20 возьмет все логические ядра, но Hyper-Threading мешает.
Правильно: ./main -m llama-3.1-8b.Q4_K_M.gguf -ngl 32 -t 16 -c 2048 -b 512 --mlock
Объяснение: -ngl 32 — примерно 40% модели в VRAM, остальное в RAM. -t 16 — физические ядра (8P+8E). -c 2048 — достаточно для диалога, экономит память. -b 512 — размер батча, оптимально для 8 ГБ VRAM. --mlock — фиксируем в RAM, ноутбук не уходит в сон с моделью.
2 Стационарный ПК: Ryzen 7 5800X + RTX 4090 (24 ГБ VRAM)
Здесь можно позволить себе больше. Но не все.
Для модели Qwen2.5 32B (Q3_K_M):
Неправильно: ./main -m qwen2.5-32b-q3_k_m.gguf -ngl 99 -t 32 -c 8192
Почему плохо: Модель 32B даже в квантованном виде огромна. -ngl 99 попытается загрузить все слои в VRAM. Не влезет даже в 24 ГБ. -t 32 на 8-ядерном Ryzen — абсурд.
Правильно: ./main -m qwen2.5-32b-q3_k_m.gguf -ngl 40 -t 16 -c 4096 -tb 8 --no-mmap
Объяснение: -ngl 40 — часть слоев на GPU, часть на CPU. -t 16 — 8 ядер с Hyper-Threading. -c 4096 — разумный контекст для тяжелой модели. -tb 8 — 8 ГБ тензорной памяти в RAM для слоев с CPU. --no-mmap — отключаем memory mapping, потому что модель не влезает в VRAM целиком.
3 Сервер без GPU: Dual Xeon E5-2690 v4 (56 ядер)
Много ядер, но старых. Нет AVX-512, только AVX2. Здесь важна оптимизация под CPU.
Для модели Mistral 7B (Q4_K_S):
Неправильно: ./main -m mistral-7b-q4_k_s.gguf -t 56 -c 8192 --mlock
Почему плохо: -t 56 загрузит все логические ядра, но Xeon E5 v4 — это 28 физических ядер. Hyper-Threading на таких старых CPU дает минимальный прирост. -c 8192 съест всю память.
Правильно: ./main -m mistral-7b-q4_k_s.gguf -t 28 -c 2048 -b 1024 --threads-batch 28 --no-mmap
Объяснение: -t 28 — только физические ядра. -c 2048 — экономия памяти. -b 1024 — большой батч для CPU-инференса. --threads-batch 28 — отдельная настройка потоков для батч-обработки. --no-mmap — на серверах часто проблемы с mmap на больших файлах.
Если у тебя AMD видеокарта, не пытайся использовать CUDA-флаги. Тебе нужен Vulkan или ROCm. Подробности в нашем гиде "Оптимизация llama.cpp под AMD видеокарты".
Специальные сценарии: не только диалог
Пакетная обработка текстов (например, суммаризация 100 документов)
Здесь важна скорость, а не интерактивность. Используем флаги для батч-режима.
Команда: ./main -m model.q4_k_m.gguf -t 8 --prompt-cache /tmp/cache.bin --prompt-cache-all -b 2048 --no-interactive --file /path/to/prompts.txt
Что это дает: --prompt-cache и --prompt-cache-all кэшируют эмбеддинги промптов. При обработке 100 документов с похожими промптами ускоряет работу в 3-5 раз. -b 2048 — большой батч для пакетной обработки. --no-interactive — отключает интерактивный режим, экономит память.
Долгий диалог с сохранением контекста
Работаешь с моделью несколько часов, контекст растет. Надо избежать переполнения.
Команда: ./main -m model.q4_k_m.gguf -c 8192 --keep N --interactive-first --reverse-prompt "\nUser:" --color
Объяснение: --keep N — оставляет в контексте только последние N токенов, когда контекст заполняется. Предотвращает OOM. --interactive-first — сразу запускает интерактивный режим. --reverse-prompt — автоматически останавливает генерацию при появлении строки "\nUser:", удобно для диалога.
Тестирование производительности
Сравниваешь разные квантования или настройки. Нужны точные, воспроизводимые результаты.
Команда: ./main -m model.gguf -t 8 -ngl 20 -c 2048 --no-display-prompt --temp 0 --seed 42 -p "Once upon a time" -n 256
Ключевые флаги: --no-display-prompt — не показывает промпт, только результат. --temp 0 — детерминированная генерация. --seed 42 — фиксированный сид для воспроизводимости. -n 256 — генерирует ровно 256 токенов.
Ошибки, которые ломают все
| Ошибка | Симптомы | Лечение |
|---|---|---|
| "llama_new_context_with_model: failed to allocate context" | Модель не запускается, хотя VRAM/RAM достаточно | Уменьши -c (контекст). Память растет квадратично! 8192 → 4096 может освободить 60% памяти. |
| Генерация работает 2 секунды, потом пауза 10 секунд | Swapping. Модель не влезает в VRAM, данные идут в RAM | Уменьши -ngl. Используй -tb для явного указания тензорной памяти в RAM. |
| Скорость 5 токенов/сек на RTX 4090 | Модель полностью на CPU. GPU не используется | Добавь -ngl 1 хотя бы. Проверь, что llama.cpp собран с поддержкой CUDA/Vulkan. |
| "illegal instruction" при запуске | Бинарник собран с AVX-512, а CPU поддерживает только AVX2 | Пересобери llama.cpp с правильными флагами. См. нашу статью о сборке. |
| Модель "забывает" начало диалога | Контекст переполнился, старые токены вытесняются | Используй --keep N или увеличь -c. Или разбивай диалог на сессии. |
Неочевидные комбинации, которые работают
Иногда правильная настройка — это не интуитивно.
- -t 6 -ngl 20 на 8-ядерном CPU: Лучше, чем -t 8 -ngl 20. Почему? Два ядра остаются для системы, обработки ввода-вывода. Падение скорости 5%, зато система не лагает.
- --mlock + --no-mmap: Кажется, противоречат друг другу. Но нет. --no-mmap загружает модель в RAM сразу целиком. --mlock не дает ее выгрузить. Результат: максимальная скорость повторных запусков, но модель висит в RAM постоянно.
- -c 1024 при размере контекста модели 8192: Не "жадничай". Для большинства диалогов хватает 1024 токенов. Экономия памяти в 64 раза (!) по сравнению с 8192.
Что дальше? Автоматизация
Надоело каждый раз подбирать аргументы? Есть варианты.
Используй веб-интерфейсы с автоподбором параметров. Или настрой llama.cpp RPC-server для распределенных вычислений.
Самый важный совет: не копируй команды слепо. Запусти ./main --help. Прочитай описание каждого флага, который используешь. Потратишь 10 минут. Сэкономишь часы дебага и получишь в 3 раза больше токенов в секунду.
И последнее: если твоя команда работает, но медленно — не останавливайся. Поиграй с -ngl, -t, -c. Уменьшай, пока не упадет скорость. Потом увеличь на 10%. Это и есть оптимум.