Модель установлена, запущена, но работает медленно. 5 токенов в секунду — и ты смотришь на экран, как в 90-е на загрузку через dial-up. В этом посте — конкретные параметры и техники, которые реально ускоряют локальные LLM на CPU. Без магии, только измеряемый результат.
Что влияет на скорость
Прежде чем крутить параметры, нужно понимать, где теряется время. Генерация токенов в LLM — это последовательный процесс: каждый новый токен зависит от всех предыдущих. Поэтому есть два режима работы:
Prefill (обработка промпта) — модель читает ваш запрос и строит внутреннее представление. Здесь можно распараллелить вычисления, и скорость измеряется в тысячах токенов в секунду.
Generation (генерация ответа) — модель выдаёт токены один за другим. Здесь параллелизм ограничен, и скорость падает до единиц или десятков токенов в секунду.
Для QA-задач критична именно скорость генерации — мы не загружаем романы в контекст, но ждём, пока модель напишет тест-кейс или код.
Параметры llama.cpp, которые реально работают
1. Количество потоков (-t, --threads)
Самый очевидный параметр. По умолчанию llama.cpp использует все доступные ядра, но на практике оптимальное значение часто меньше максимума.
# Посмотреть количество ядер
sysctl -n hw.ncpu # macOS
nproc # Linux
# Запуск с разным количеством потоков
llama-cli -m model.gguf -t 4 --temp 0.7
llama-cli -m model.gguf -t 8 --temp 0.7
llama-cli -m model.gguf -t 16 --temp 0.7
Мои измерения на Intel i7-1265U (10 ядер, 12 потоков):
| Потоки | Скорость (ток/сек) | Нагрузка CPU |
|---|---|---|
| 4 | 5.2 | 45% |
| 8 | 8.1 | 78% |
| 12 | 8.5 | 95% |
| 16 | 7.8 | 100% |
Вывод: для этого CPU оптимум — 8 потоков. Больше — только нагрев и шум вентилятора, скорость не растёт. На вашем железе цифры будут другие, принцип тот же: найдите точку, где добавление потока перестаёт давать прирост.
2. Размер батча (-b, --batch-size)
Batch size — сколько токенов модель обрабатывает параллельно на этапе prefill. Для коротких промптов (наши QA-задачи) большой батч не нужен. Но если вы загружаете логи или ТЗ — имеет значение.
# По умолчанию 2048, для коротких промптов можно уменьшить
llama-cli -m model.gguf -b 512 --temp 0.7
# Для длинных документов — увеличить
llama-cli -m model.gguf -b 4096 --temp 0.7
Эффект заметен только на prefill. Для генерации ответа batch size не влияет.
3. GPU Offload (-ngl, --n-gpu-layers)
Самый мощный способ ускорения — перенос вычислений на GPU. Но здесь есть нюансы.
macOS с Apple Silicon: Unified Memory означает, что RAM и VRAM — это одно и то же. Ollama и llama.cpp автоматически используют GPU, если доступно. Параметр -ngl 999 говорит «offload все слои на GPU».
# Mac — offload всё на GPU
llama-cli -m model.gguf -ngl 999 --temp 0.7
# Если модель не помещается — уменьшайте
llama-cli -m model.gguf -ngl 20 --temp 0.7 # offload 20 слоёв
Windows с NVIDIA: нужны CUDA-драйверы и llama.cpp, собранный с поддержкой CUDA. Ollama делает это автоматически.
# Windows + NVIDIA — проверьте, что CUDA доступна
llama-cli -m model.gguf -ngl 999 --temp 0.7
# Если не работает — Ollama проще
ollama run my-model
Windows с Intel/AMD GPU: поддержка хуже. Попробуйте Vulkan-backend или оставайтесь на CPU.
Мои измерения на MacBook Air M4 (Qwen 3.5 9B):
| Режим | Скорость (ток/сек) | Разница |
|---|---|---|
| CPU only | 12 | baseline |
| GPU 50% слоёв | 22 | +83% |
| GPU 100% слоёв | 35 | +192% |
4. Размер контекста (-c, --ctx-size)
Большой контекст — это хорошо, но он требует памяти. И не только RAM: при генерации модель «освежает» весь контекст, что замедляет выдачу каждого нового токена.
# Минимальный контекст для чек-листов
llama-cli -m model.gguf -c 2048 --temp 0.7
# Средний — для анализа требований
llama-cli -m model.gguf -c 8192 --temp 0.7
# Большой — для логов и кодовой базы
llama-cli -m model.gguf -c 32768 --temp 0.7
Мои измерения (Qwen 3.5 9B на M4):
| Контекст | Скорость (ток/сек) | Память |
|---|---|---|
| 2K | 38 | 4.2 GB |
| 8K | 35 | 5.1 GB |
| 32K | 28 | 7.8 GB |
| 128K | 18 | 14.2 GB |
Вывод: для 90% QA-задач достаточно 8K контекста. 32K — если анализируете большие логи. 128K — редко нужен, и цена в скорости существенна.
5. Квантизация модели
Квантизация — это сжатие весов модели. Вместо 16 бит на параметр используется 4 или 5 бит. Потери качества минимальны (особенно для QA-задач), а выигрыш в скорости и памяти — колоссальный.
Основные форматы:
- Q4_K_M — баланс качества и размера. Рекомендую как базовый.
- Q5_K_M — чуть лучше качество, чуть больше размер. Если RAM позволяет.
- Q3_K_M — агрессивное сжатие. Для слабого железа, но качество падает заметно.
- Q6_K — максимальное качество при квантизации. Почти неотличим от оригинала.
- FP16 — без сжатия. 4x больше памяти, минимальный выигрыш в качестве.
Мои измерения (Qwen 3.5 9B на M4):
| Формат | Размер | Скорость | Качество кода |
|---|---|---|---|
| Q3_K_M | 3.8 GB | 42 ток/с | 65% компилируется |
| Q4_K_M | 4.9 GB | 38 ток/с | 78% компилируется |
| Q5_K_M | 5.9 GB | 35 ток/с | 82% компилируется |
| Q6_K | 6.8 GB | 32 ток/с | 85% компилируется |
Вывод: Q4_K_M — золотая середина. Q5_K_M — если у вас достаточно RAM и вы пишете много кода. Q3_K_M — только если совсем тесно.
Практические сценарии оптимизации
Сценарий 1: Корпоративный ноутбук, нужна максимальная скорость
Железо: Intel i7, 16 GB RAM, без дискретной GPU.
# Модель: Qwen 2.5 4B Q4_K_M (2.5 GB)
# Контекст: минимальный, только для чек-листов
# Потоки: 8 (оптимум для этого CPU)
llama-cli \
-m qwen2.5-4b-q4_k_m.gguf \
-t 8 \
-c 4096 \
-b 512 \
--temp 0.7 \
-p "Напиши чек-лист..."
# Ожидаемая скорость: 10-15 ток/сек
Сценарий 2: MacBook Air, нужен баланс
Железо: M2, 16 GB RAM.
# Модель: Qwen 3.5 9B Q4_K_M (5.8 GB)
# GPU offload: максимальный
# Контекст: средний
llama-cli \
-m qwen3.5-9b-q4_k_m.gguf \
-ngl 999 \
-c 8192 \
--temp 0.7 \
-p "Напиши тест-кейс..."
# Ожидаемая скорость: 25-30 ток/сек
Сценарий 3: Максимальное качество кода
Железо: машина помощнее — MacBook Pro с 36 GB RAM. Это расчётный сценарий: у меня Air с 16 GB, а 14B в Q5 туда уже не влезает.
# Модель: Qwen 2.5 Coder 14B Q5_K_M (11 GB)
# GPU offload: полный
# Контекст: большой (можем себе позволить)
llama-cli \
-m qwen2.5-coder-14b-q5_k_m.gguf \
-ngl 999 \
-c 16384 \
--temp 0.3 \
-p "Напиши Page Object для..."
# Ожидаемая скорость: 15-20 ток/сек
# Качество: максимальное
Оптимизация Ollama
Если используете Ollama — тоже есть рычаги. Создайте или отредактируйте Modelfile:
FROM ./models/qwen3.5-9b-q4_k_m.gguf
# Параметры генерации
PARAMETER temperature 0.7
PARAMETER num_ctx 8192
PARAMETER num_thread 8
# Оптимизации
PARAMETER num_batch 512
PARAMETER num_gpu 999
SYSTEM "Ты — QA automation engineer..."
Или передайте параметры при запуске:
OLLAMA_NUM_THREAD=8 OLLAMA_NUM_GPU=999 ollama run my-model
Техники, которые НЕ работают
Чтобы сэкономить ваше время — список того, что я проверил и что не дало результата:
- Изменение seed (-s) — влияет только на случайность ответа, не на скорость
- Отключение логов (--log-disable) — экономия наносекунд, не заметна
- Использование FP32 вместо FP16 — только медленнее, качество не улучшается
- «Оптимизированные» сборки из интернета — чаще всего вирусы или placebo
Измеряйте, не гадайте
Главное правило оптимизации — измеряйте, а не гадайте.
llama.cpp выводит скорость генерации в конце каждого запроса:
llama_print_timings: load time = ...
llama_print_timings: sample time = ...
llama_print_timings: prompt eval time = ...
llama_print_timings: eval time = ...
llama_print_timings: total time = ...
llama_print_timings: tokens per second = 12.34
Фокусируйтесь на «tokens per second». Это ваша метрика успеха.
И помните: оптимизация — это компромисс. Максимальная скорость на слабом железе достигается ценой качества (меньшая модель, агрессивная квантизация). Максимальное качество — ценой скорости (большая модель, минимальная квантизация). Найдите свой баланс.
В следующем посте — практика. Конкретные промпты для генерации чек-листов, тест-кейсов, кода автотестов. Копируй и используй.
Discussion
No comments yet - start the thread.