Не влезет — не жмись: почему локальный LLM тормозит, и кто виноват
Ты собрал станцию за $15 000, поставил Mistral Large 2 (или даже Nemotron 4 340B в 4-bit). Запускаешь первый запрос... и ждёшь 40 секунд. Знакомо?
В 2026 году локальные LLM перестали быть игрушкой — но без грамотной оптимизации даже RTX 6090 с 48 GB VRAM будет задыхаться. Проблема не в модели, а в том, как её кормят и как забирают результат. Давай разберёмся, где теряются токены и как превратить свою железку в реактивный двигатель.
Главный враг локального инференса — не количество параметров, а пропускная способность памяти и неэффективное использование вычислений. GPU не считает медленно, он ждёт данные.
🧠 Квантование: первая и самая жирная линия обороны
Квантование — это не компрессия «на глаз», а скорее научный подход к снижению битности весов. В 2026 году стандарт де-факто — GGUF (для CPU/GPU гибрида) и EXL2 (для чистого GPU). Если ты используешь Ollama, скорее всего, модель уже в GGUF. Но правильный выбор quant — это половина успеха.
1 Как НЕ надо: Q4_K_M — универсальный, но не для всех задач
Q4_K_M даёт хороший баланс между размером и качеством, но на длинных контекстах (32K+) начинает проседать по perplexity. Если тебе важна точность кода или фактов — бери Q6_K или Q8_0. Вот как переквантовать модель с помощью llama.cpp (ветка b4235, последняя на июнь 2026):
# Скачиваешь оригинальные веса Hugging Face (например, mistralai/Mistral-Large-123B)
git clone https://huggingface.co/mistralai/Mistral-Large-123B
cd Mistral-Large-123B
# Конвертируешь в FP16 GGUF
python3 convert.py . --outfile model-fp16.gguf
# Квантуешь в Q6_K
./quantize model-fp16.gguf model-q6_k.gguf Q6_K
# Удаляешь промежуточные файлы, чтобы не забить диск
rm model-fp16.gguf
Совет: для инференса на одном GPU (24 GB) бери Q4_K_M, на двух — Q5_K_M, на четырёх — Q6_K. Если у тебя RTX 5090 с 48 GB — смело ставь Q8_0.
Ошибка: квантовать модель до Q2_K или IQ2_XXS на продакшене. Да, размер меньше, но качество падает катастрофически — модель начинает «галлюцинировать» даже на простых вопросах. Используй IQ-кванты только для тестов.
🚀 vLLM: когда одного llama.cpp мало
llama.cpp прекрасен для однопользовательского чата, но для серверного инференса с batch-запросами нужен настоящий движок. vLLM v0.8 (релиз апрель 2026) принёс PagedAttention v3 и поддержку FP8 на Blackwell. Разница в throughput — до 10x против обычного llama.cpp server.
Запускаем Mistral Large 2 (123B) на двух A100 с vLLM:
# Установка через pip (Python 3.12 обязательно)
pip install vllm==0.8.0
# Запуск с FP8 квантованием (если GPU поддерживает)
python -m vllm.entrypoints.openai.api_server \
--model mistralai/Mistral-Large-123B \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.95 \
--quantization fp8 \
--max-model-len 65536 \
--max-num-batched-tokens 8192 \
--enable-prefix-caching
Ключевые флаги:
--enable-prefix-caching — кэширует общие префиксы промптов (например, system prompt). Экономит до 30% вычислений на повторяющихся запросах.
--max-num-batched-tokens — ограничивает размер батча, чтобы не вылететь по OOM. Подбирай экспериментально: для 2x A100 80 GB можно ставить 16384.
💻 CPU Offloading: как выжать всё из старой фермы
Не у всех есть кластер A100. Если у тебя одна RTX 3060 12 GB, а модель — Qwen2.5 72B в Q4_K_M, без offloading не обойтись. Но просто выгрузить часть слоёв на CPU — путь к скорости 0.5 tok/s. Надо делать умно.
В llama.cpp (коммит b4235) появилась поддержка asymmetric offload: тяжёлые слои (attention) оставляем на GPU, лёгкие (FFN) — на CPU. Конфиг выглядит так:
./server \
--model qwen-72b-q4_k_m.gguf \
--ngl 36 \
--n-gpu-layers-dense 28 \
--split-mode none \
--threads 16 \
--ctx-size 8192
Флаг --n-gpu-layers-dense говорит: «дорогие» dense слои оставь на GPU, остальное — на CPU. Прирост скорости — от 3 до 5 токенов/с на Ryzen 7950X против 1.5 tok/s без оптимизации.
Бонус: если у тебя несколько CPU (dual socket Epyc), добавь --numa — распределение памяти по numa-узлам даёт ещё +15% к пропускной способности.
📦 KV Cache и Speculative Decoding: вещи, о которых молчат доки
Каждый шаг генерации LLM пересчитывает ключи и значения (KV) всех предыдущих токенов. Это главный потребитель памяти и времени. Решений два: кэшировать или угадывать.
Prefix caching (поддерживается в vLLM, llama.cpp с флагом --cache-type k) автоматически переиспользует KV-кэш для одинаковых промптов. Если у тебя чат-бота с одним system prompt — включи обязательно.
Speculative decoding — техника, когда маленькая модель (drafter) генерирует несколько токенов, а большая их верифицирует за один проход. В версии llama.cpp b4235 реализована поддержка совместного использования моделей. Пример для Ollama:
# Запускаем модель с drafter
ollama run qwen2.5:72b-instruct-q4_K_M --speculative qwen2.5:0.5b-instruct-q4_K_M
Ты получаешь скорость большой модели, но с задержкой маленькой. На практике — 2-3x ускорение на коротких ответах (до 256 токенов). Длинные генерации выигрывают меньше.
⚙️ Batch Inference и Continuous Batching
Если твой сервис обрабатывает много запросов параллельно (RAG, AI-ассистент), то без батчирования ты теряешь 90% производительности GPU. vLLM и TGI умеют на лету собирать запросы в батч — это называется continuous batching.
Вот конфиг для TGI (Text Generation Inference v2.2.0, релиз май 2026) с динамическим батчем:
# config.yaml
model_parallel_size: 1
max_batch_size: 64
max_batch_prefill_tokens: 4096
max_input_length: 8192
max_total_tokens: 16384
# Включаем continuous batching
dynamic_batching: true
Запускаем:
text-generation-launcher \
--model-id mistralai/Mistral-Large-123B \
--num-shard 1 \
--max-batch-size 64 \
--max-batch-prefill-tokens 4096 \
--dynamic-batching
Разница с отключенным батчем — пропускная способность растёт с 10 req/s до 120 req/s. Но следи за latency: каждый запрос будет ждать, пока наберётся батч. Компромисс — ставить max_batch_size не выше 32 для интерактивных сценариев.
🔧 Тонкая настройка: что ещё стоит попробовать
- Flash Attention 3 — интегрирован в vLLM 0.8 и llama.cpp. Включается флагом
--use-flash-attn. Даёт прирост 10-20% на длинных контекстах за счёт эффективного использования shared memory. - Prompt tuning / Low-rank adaptation — если у тебя частые запросы одного стиля, лучше дообучить маленький LoRA-адаптер, чем гонять большой промпт.
llama.cpp поддерживает LoRA с флагом --lora. - Memory profiling — перед продакшеном запусти
vllm.py --profile, чтобы увидеть, сколько реально памяти жрёт модель. Часто можно снизитьgpu-memory-utilizationс 0.95 до 0.80 без потери скорости. - CPU-only инференс — для моделей до 7B на современных CPU (AMD Zen 5, Intel Lunar Lake) llama.cpp с AVX-512 даёт 10-15 tok/s. Не списывай CPU со счетов: вокруг LLM нужно хостить не только инференс, но и тулинг.
🔥 Ошибки, которые я видел сотни раз
- Квантование модели без тестов — взял Q4_K_M, а она начала писать бред на русском. Проверяй perplexity на своём датасете. Разница в 0.5 может убить качество.
- Слепая вера в флаг --numa — если у тебя односокетный CPU, флаг только замедлит из-за лишних проверок.
- Запуск vLLM с одним GPU и моделью 70B+ — OOM гарантирован. Либо квантуй до 2-bit (плохо), либо используй железо за $15 000.
- Не использовать --enable-prefix-caching в продакшене — грех, который стоит 30% лишних вычислений.
🧩 Техники, которые ещё не вошли в мейнстрим (но зря)
Medusa — speculative decoding, но без отдельной модели. Дообучаешь несколько голов на той же модели, они предсказывают следующие токены. На A100 даёт 2x ускорение. Пока только для vLLM, но в llama.cpp планируют в 2027.
Splitwise — продвижение от Flash Attention: обрабатывать prefilling и decoding на разных GPU. Prefill — на быстрых H100, decode — на дешёвых A10. В open-source пока нет, но следи за репозиторием splitwise.
Если хочешь глубже разобраться, как управлять контекстом модели, почитай про RLM: управление контекстом без гниения — это новая техника, которая скоро заменит обычное sliding window.
Локальный LLM — это не про «запустил и забыл». Это про выбор правильного quant, настройку batch-пайплайна и умный offload. Потрать час на бенчмарки — сэкономишь недели продакшена. А если лень копаться самому, попробуй Ollama — он уже включает 90% этих оптимизаций из коробки.
И запомни: vLLM с FP8 и prefix caching — твой лучший друг. Остальное — детали.