Локальный запуск LLM сегодня обычно упирается не в один «движок», а сразу в несколько уровней:
модель
↓
формат/квантование весов
↓
inference engine
↓
сервер/API
↓
клиент или AI-agent
Из-за этого сравнения вроде «что лучше — EXL3 или GGUF?» часто смешивают разные сущности.
Для начала разложим стек правильно:
ExLlamaV3
= inference engine / Python + C++/CUDA extensions
EXL3
= специализированное квантованное представление весов
TabbyAPI
= OpenAI-compatible API server поверх ExLlamaV3
А с другой стороны:
llama.cpp
= inference engine / C/C++ + множество backend'ов
GGUF
= контейнер модели + metadata + tensors
Q4_K_M / IQ4_XS / Q5_K_M / ...
= конкретные схемы квантования внутри GGUF
llama-server
= OpenAI-compatible сервер из llama.cpp
То есть корректнее сравнивать два полных стека:
EXL3 + ExLlamaV3 + TabbyAPI
против:
GGUF + llama.cpp + llama-server
И у них довольно разные философии.
ExLlamaV3 — специализированная inference-библиотека для запуска LLM на современных потребительских GPU.
Главный целевой сценарий проекта:
NVIDIA GPU
+
модель целиком или почти целиком в VRAM
+
квантованные веса
+
максимальная эффективность локального inference
Актуальный ExLlamaV3 поддерживает, среди прочего:
Это более специализированный проект, чем llama.cpp.
llama.cpp пытается работать практически везде:
CPU
NVIDIA CUDA
AMD HIP
Apple Metal
Vulkan
Intel
CPU + GPU offload
разные архитектуры
разные quant types
ExLlamaV3 концентрируется прежде всего на GPU inference. Отсюда и потенциальное преимущество: когда железо совпадает с целевым сценарием проекта, runtime можно агрессивнее оптимизировать именно под него.
Исторически ExLlama стал популярен как быстрый inference runtime для сильно квантованных Llama-подобных моделей на NVIDIA GPU.
Позже появился ExLlamaV2 и формат EXL2.
Главной особенностью EXL2 была гибкая квантизация с заданным средним количеством bits per weight:
2.5 bpw
3.0 bpw
3.5 bpw
4.0 bpw
4.5 bpw
...
Это отличалось от классической GGUF-логики, где пользователь обычно выбирал дискретные recipes:
Q3_K_M
Q4_K_M
Q5_K_M
Q6_K
...
ExLlamaV3 продолжает идею специализированного GPU runtime, но вводит новый формат EXL3 и значительно перерабатывает inference stack.
EXL3 — новая схема квантования весов в ExLlamaV3.
Она основана на идеях QTIP.
На высоком уровне EXL3 решает задачу:
Как представить веса модели очень малым количеством бит так, чтобы ошибка в поведении нейросети была минимальной?
Это не просто:
float weight
→ округлить до ближайшего int4
EXL3 использует более сложный механизм:
Поэтому EXL3 надо рассматривать не просто как ещё один «Q4».
Обычное блочное квантование можно представить так.
Есть группа весов:
0.13
-0.72
0.08
1.11
...
Мы выбираем небольшой набор допустимых уровней и каждому весу назначаем ближайший.
При 4 битах имеется до 16 кодов на элемент в самой простой интерпретации.
Но ошибка отдельных весов — не лучший критерий качества нейросети.
Один вес можно изменить довольно сильно практически без последствий. Другой может быть намного чувствительнее.
QTIP-подобные методы стараются оптимизировать не просто:
||W - W_quant||²
а ошибку с учётом того, как веса реально влияют на выход слоя.
Условно:
error ≈ (W - Wq) H (W - Wq)^T
где H отражает статистику входных активаций и играет роль приближения Hessian.
Поэтому квантователь учитывает не только:
насколько число после квантования отличается от исходного,
но и:
насколько эта ошибка важна для поведения слоя.
Рассмотрим linear layer:
y = Wx
После квантования:
Wq = W + ΔW
Ошибка выхода:
Δy = ΔW x
Если некоторые направления x часто встречаются во время работы модели, ошибка весов вдоль этих направлений особенно важна.
Calibration data позволяет оценить статистику входов. На её основе квантователь оптимизирует веса с учётом чувствительности слоя.
Именно поэтому advanced post-training quantization часто превосходит простое независимое округление весов.
EXL3 не кодирует каждый вес полностью независимо.
Группы весов рассматриваются как многомерные объекты, которые кодируются через специальную структуру — trellis.
Очень упрощённо:
наивный quantizer:
weight 1 → code
weight 2 → code
weight 3 → code
weight 4 → code
Trellis quantizer:
vector of weights
↓
поиск хорошего пути через компактное множество состояний
↓
последовательность кодов
Для поиска хорошей траектории используется Viterbi-подобный алгоритм.
Это позволяет получить более богатое эффективное представление при малом количестве реально хранимых бит.
В обычной vector quantization можно хранить таблицу:
code 0 → vector A
code 1 → vector B
...
code N → vector N
Но большая таблица сама начинает занимать память.
Procedural codebook задаёт множество возможных reconstruction vectors алгоритмически.
То есть вместо хранения огромной таблицы можно хранить компактный код и восстанавливать нужный vector процедурно.
Именно такой подход позволяет QTIP/EXL3 сохранять высокую выразительность квантованного представления при небольшом bitrate.
Простые integer quants хорошо работают в районе:
4–6 bpw
Но чем ниже мы опускаемся:
4
→ 3
→ 2.5
→ 2
тем больше значение имеет качество самого алгоритма квантования.
При 6–8 битах почти любая разумная схема достаточно точно представляет веса.
При 2–3 битах выбор codebook и оптимизация ошибки становятся критическими.
Именно поэтому advanced методы вроде QTIP, QuIP# и AQLM особенно интересны в low-bitrate режиме.
EXL3 создан как практичный вариант такого подхода, который можно реально конвертировать и запускать на потребительском GPU.
Q4_K_M, а bitrateВ GGUF пользователь часто выбирает:
Q3_K_M
Q4_K_M
Q5_K_M
В EXL3 основной параметр конвертации выглядит иначе:
-b 3.75
Например:
python convert.py \
-i ./model-hf \
-o ./model-exl3-3.75bpw \
-w ./work \
-b 3.75
Здесь 3.75 bpw — целевой средний bitrate весов.
Это удобная модель мышления:
У меня есть X ГБ под weights — какой средний bpw я могу себе позволить?
вместо:
Влезет ли именно Q4_K_M или придётся брать Q3_K_L?
3.75 bpw не означает 3.75 бита для каждого весаФизически дробного бита у отдельного веса нет.
3.75 bpw — средний бюджет по модели.
Конвертер распределяет доступный битовый бюджет между представлениями разных tensors так, чтобы получить нужный общий размер и качество.
Есть и специальные параметры для повышения точности чувствительных компонентов. В актуальном конвертере есть режим повышения bitrate для attention и shared-expert частей.
Для MoE это особенно выгодно:
огромное количество expert weights
→ можно квантизовать агрессивнее
маленькая, но чувствительная часть модели
→ оставить точнее
Output layer:
hidden state
↓
lm_head
↓
vocabulary logits
может быть очень большой.
В ExLlamaV3 для lm_head можно отдельно задать bitrate. Например:
основные weights ≈ 3.5 bpw
lm_head = 6 bit
Это полезно, потому что output layer может быть чувствителен к сильной квантизации.
Исходник обычно выглядит как стандартная Hugging Face model directory:
model/
├── config.json
├── tokenizer.json
├── tokenizer_config.json
├── model-00001-of-000xx.safetensors
├── model-00002-of-000xx.safetensors
└── ...
ExLlamaV3 запускает conversion:
python convert.py \
-i ./model \
-o ./model-exl3 \
-w ./work \
-b 4.0
Квантователь:
HF model
↓
читает tensors
↓
собирает calibration statistics / Hessian information
↓
квантует tensors
↓
trellis encoding
↓
пакует quantized tensors
↓
сохраняет EXL3 model directory
EXL3 старается в значительной степени сохранять исходную структуру и имена tensors Hugging Face модели.
GGUF обычно выглядит так:
Qwen-35B-Q4_K_M.gguf
Один файл может содержать metadata, architecture parameters, tokenizer information и tensors.
EXL3 обычно выглядит скорее так:
Qwen-35B-EXL3-4.0bpw/
├── config.json
├── tokenizer.json
├── *.safetensors
└── другие HF metadata
То есть EXL3 остаётся ближе к Hugging Face ecosystem.
GGUF ≠ Q4
GGUF — контейнер.
Внутри GGUF могут лежать:
FP16
BF16
Q8_0
Q6_K
Q5_K_M
Q4_K_M
IQ4_NL
IQ4_XS
Q3_K_M
IQ2_XXS
...
Поэтому правильный вопрос звучит так:
EXL3 при заданном реальном VRAM footprint в ExLlamaV3 лучше или хуже конкретного GGUF quant recipe в llama.cpp?
И ответ зависит от модели, GPU, bitrate, контекста и runtime kernels.
универсальность
+
переносимость
+
много hardware backends
+
CPU/GPU hybrid inference
+
огромный набор quant schemes
современный GPU
+
специализированная quantization
+
максимально плотное размещение модели в VRAM
+
GPU-optimized inference
Поэтому они часто выигрывают в разных сценариях.
Возьмём обычный GGUF Q4_K_M.
Веса хранятся в компактном quantized representation. Во время matrix multiplication CUDA kernel:
читает quantized block
↓
декодирует scale / codes
↓
умножает на activations
↓
накапливает результат
Главная идея — не деквантизовать всю модель заранее в FP16. Если бы 20 ГБ Q4 весов сначала превращались в десятки гигабайт FP16, смысл квантования исчез бы.
Поэтому dequantization встроена в вычислительные kernels.
EXL3 тоже не разворачивает модель целиком в FP16.
Условно:
packed EXL3 codes
↓
specialized CUDA kernel
↓
reconstruction нужных weight blocks
↓
matrix multiplication
Но reconstruction сложнее, чем у простого integer quant.
У Q4_K_M decoding weights относительно дешёвый. У EXL3 приходится интерпретировать trellis/codebook representation.
Поэтому появляется компромисс:
EXL3:
меньше памяти / потенциально выше fidelity per bit
но
более сложный decode weights
И это напрямую влияет на производительность разных GPU generations.
Представим, что LLM decode memory-bound.
Для каждого токена GPU в основном делает:
прочитать веса из VRAM
+
математика
Если веса уменьшились:
20 GB → 15 GB
мы потенциально читаем меньше данных и должны ускориться.
Но теперь decoding каждого блока стал сложнее.
Если GPU успевает делать reconstruction быстрее, чем память подаёт данные, мы всё ещё bandwidth-bound — это идеальная ситуация.
Если же reconstruction kernels становятся bottleneck:
compute-bound
дальнейшее уменьшение размера weights уже не даёт ожидаемого ускорения.
Разработчик ExLlamaV3 отдельно отмечает, что EXL3 kernels при хороших условиях могут приближаться к memory-bound режиму на современных GPU, но на Ampere это сложнее.
Это особенно важно для:
RTX 3060
RTX 3070
RTX 3080
RTX 3090
A10
A40
У простого GGUF Q4_K_M unpacking дешевле.
Поэтому на Ampere вполне возможна ситуация:
EXL3 занимает меньше VRAM
но:
llama.cpp Q4_K_M генерирует быстрее
при похожем memory footprint.
Это не парадокс: EXL3 тратит больше compute на реконструкцию весов.
Нет.
Главное преимущество на маленькой VRAM может быть не скорость kernel-а, а возможность поместить более сильную модель полностью в GPU.
Например:
GGUF Q4:
модель не помещается полностью
→ CPU offload
→ сильно падает скорость
а:
EXL3 3.2 bpw:
модель целиком помещается в VRAM
→ всё вычисляется на GPU
Тогда EXL3 может выиграть очень сильно, даже если при одинаковом memory footprint Q4_K_M kernel быстрее.
То есть надо сравнивать не отдельный kernel, а полную конфигурацию системы.
Типичный хороший сценарий:
NVIDIA GPU
+
VRAM ограничена
+
модель можно полностью разместить в VRAM после EXL3 quantization
+
нужен высокий decode throughput
+
CPU offload нежелателен
Именно возможность тонко выбрать bitrate позволяет использовать VRAM почти полностью.
Допустим у тебя свободно:
21.3 GB под model weights
GGUF варианты могут условно выглядеть:
Q3_K_M = 18.5 GB
Q4_K_M = 23 GB
Получается:
Q3 недоиспользует несколько GB
Q4 не помещается
EXL3 позволяет попробовать:
3.6 bpw
3.7 bpw
3.8 bpw
и подобрать модель почти точно под memory budget.
Это одно из самых практически полезных свойств EXL-семейства.
Разрыв уже не такой большой, как несколько лет назад.
Современный llama.cpp имеет:
Например:
UD-Q4_K_M
UD-IQ4_NL
UD-IQ4_XS
UD-Q3_K_XL
тоже пытаются распределять bit budget между tensors разумнее.
Поэтому нельзя считать:
EXL3 = smart quant
GGUF = dumb integer rounding
Современные GGUF recipes тоже сложны.
Нет универсального правила:
EXL3 всегда лучше GGUF
или:
GGUF всегда лучше EXL3
При сравнении важно фиксировать не название quant-а, а реальный memory footprint.
Правильнее сравнивать:
EXL3 3.75 bpw
VRAM weights = X GB
с GGUF, который занимает примерно столько же VRAM:
IQ4_XS
Q3_K_L
или другой recipe
А затем измерять:
Сам проект ExLlamaV3 отдельно отмечает, что современные GGUF I-quants хорошо держатся в сравнении с advanced quantization methods.
Inference engine умеет больше, чем просто загрузить quantized weights.
В актуальной версии есть:
continuous batching
dynamic batching
tensor parallel
expert parallel
speculative decoding
quantized cache
LoRA
multimodal
grammar/constrained generation
То есть это полноценный inference runtime.
Если есть несколько GPU:
GPU0 = 12 GB
GPU1 = 12 GB
можно распределить разные слои:
layers 0–19 → GPU0
layers 20–39 → GPU1
Это layer splitting.
Но можно делить сами matrix operations и выполнять части одного слоя одновременно на нескольких GPU.
Это tensor parallelism.
Схематично:
input h
├─→ GPU0: W0 @ h
└─→ GPU1: W1 @ h
↓
combine/reduce
Плюс:
оба GPU работают над одним слоем одновременно
Минус:
между GPU требуется коммуникация почти на каждом слое
Поэтому эффективность зависит от PCIe/NVLink, размера модели и архитектуры.
Память можно логически использовать как:
12 + 12 ≈ 24 GB model capacity
Но физически это две отдельные VRAM.
У каждой карты свои memory controller, CUDA cores и PCIe connection.
Если inference постоянно обменивается activations:
GPU0 ↔ GPU1
PCIe становится частью critical path.
Поэтому 2×12 ГБ обычно хуже одной гипотетической 24-ГБ карты при той же суммарной вычислительной мощности.
Современные модели всё чаще MoE.
MoE layer имеет много experts:
expert 0
expert 1
...
expert 255
но на конкретный токен активируется только небольшая часть.
Это позволяет распределять experts между GPU:
GPU0:
expert 0–127
GPU1:
expert 128–255
Router выбирает нужных экспертов, и вычисления направляются на соответствующие устройства.
Это expert parallelism.
Для крупных MoE architectures такой подход может быть естественнее обычного layer split.
Одна из ключевых особенностей llama.cpp:
модель больше VRAM
→ часть layers остаётся в RAM
→ часть работает на GPU
Например:
40 GB GGUF
24 GB VRAM
64 GB RAM
часть весов может жить на GPU, остальное — в system RAM.
Это может быть медленно, но модель работает.
Именно здесь llama.cpp чрезвычайно гибок.
Современный ExLlamaV3 уже нельзя просто называть «строго GPU-only».
В свежих версиях появились:
Но философия всё равно остаётся GPU-first.
То есть:
llama.cpp:
CPU+GPU hybrid inference — центральный сценарий
ExLlamaV3:
CPU offload — дополнительный механизм вокруг GPU-centric runtime
Если модель сильно превышает VRAM, llama.cpp обычно остаётся более естественным выбором.
При обычном Transformer для каждого токена и attention layer хранятся:
K
V
По мере роста context:
KV memory ∝ context length
Поэтому 128k context может съесть много VRAM даже если сама модель компактная.
ExLlamaV3 поддерживает квантизацию cache, причём bitrate для K и V можно выбирать отдельно.
Keys и Values играют разные роли:
attention scores:
Q · K
output:
softmax(scores) · V
Их чувствительность к quantization может отличаться.
Поэтому имеет смысл использовать, например:
K = 4 bit
V = 3 bit
или:
K = 5
V = 4
вместо одинакового формата.
Разработчик ExLlamaV3 указывал поддержку 2–8 bpw для K и V с небольшим дополнительным overhead.
Это даёт тонкий контроль над памятью длинного контекста.
В llama.cpp знакомый вариант:
--cache-type-k q4_0
--cache-type-v q4_0
или:
--cache-type-k q8_0
--cache-type-v q8_0
Идея та же:
более точный cache
→ больше VRAM
более агрессивный cache quant
→ длиннее context
Разница в конкретных схемах и kernels.
Для одного пользователя batch обычно:
1 request
Но API server может обслуживать одновременно множество запросов:
request A
request B
request C
...
Continuous batching позволяет динамически объединять текущие token steps разных requests в batch.
Это существенно повышает server throughput.
При множестве параллельных запросов KV-cache сложно эффективно размещать.
Если для каждого request заранее выделить огромный непрерывный блок:
max_context × cache_per_token
VRAM быстро закончится.
Paged attention разбивает cache на страницы и распределяет их динамически.
TabbyAPI использует continuous batching engine с paged attention на поддерживаемых NVIDIA GPU.
ExLlamaV3 — библиотека.
AI-agent обычно не хочет напрямую импортировать внутренние Python classes ExLlama.
Ему удобнее обращаться:
POST /v1/chat/completions
Поэтому используется TabbyAPI.
Стек выглядит:
Cursor / agent / application
↓ OpenAI API
TabbyAPI
↓
ExLlamaV3
↓
EXL3 weights
↓
CUDA
TabbyAPI предоставляет OpenAI-compatible API, chat templates, tool calling, model management, grammar/JSON schema, batching и другие server features.
У llama.cpp:
agent
↓ OpenAI API
llama-server
↓
llama.cpp
↓
GGUF
↓
CUDA / CPU / Metal / Vulkan / ...
То есть архитектурно системы похожи.
Разница глубже — в quantization, runtime и hardware assumptions.
Это разделение ответственности.
ExLlamaV3 занимается:
model loading
CUDA kernels
cache
sampling
batching primitives
quantized matmul
TabbyAPI занимается:
HTTP
OpenAI protocol
auth
model management
chat templates
requests
tool calling
concurrency
Аналогично можно разделять llama.cpp core и llama-server.
EXL2 был предыдущим специализированным quant format ExLlamaV2.
EXL3 отличается не просто номером версии.
Упрощённо:
EXL2:
собственная mixed-bit quantization
сильнее преобразовывал tensor structure
EXL3:
QTIP-inspired trellis quantization
более HF-like tensor structure
новые CUDA kernels
новый runtime
TabbyAPI main branch сейчас ориентирован на ExLlamaV3/EXL3; ExLlamaV2 вынесен в legacy branch.
Quantization research сильно продвинулся.
Исследования вроде:
QuIP#
QTIP
AQLM
показали, что сложная vector/trellis quantization может лучше сохранять модель при сильном сжатии.
Проблема в том, что академически хороший quantizer часто неудобен практически: может требовать очень большого compute и сложного inference kernel.
EXL3 пытается сделать advanced quantization практически используемой локально.
Некоторые advanced quantization algorithms могут квантизовать большую модель очень долго.
EXL3 пытается выполнять conversion в одном pipeline:
load tensor
↓
compute required statistics
↓
quantize
↓
trellis encode
↓
save
Ключевые оптимизации:
Это всё равно тяжелее обычной базовой GGUF quantization, но практично на consumer GPU.
Типичный llama.cpp pipeline:
HF model
↓
convert_hf_to_gguf.py
↓
BF16/F16 GGUF
↓
llama-quantize
↓
Q4_K_M.gguf
Advanced варианты могут использовать importance matrix, tensor overrides и mixed quantization.
Но базовый workflow обычно проще EXL3 Hessian/trellis optimization.
Правильный исходник для EXL3 — исходная Hugging Face модель, а не уже квантованный GGUF.
Правильная цепочка:
HF BF16/FP16
├─→ GGUF quant
└─→ EXL3 quant
Нежелательная цепочка:
GGUF Q4
→ восстановить приблизительные weights
→ EXL3
Это re-quantization:
ошибка quant 1
+
ошибка quant 2
Для качественной EXL3-квантизации нужно брать исходные high-precision weights.
В общем случае — нет.
llama.cpp должен иметь loader, metadata rules и kernels конкретного representation.
EXL3 проектировался прежде всего для ExLlamaV3.
EXL3 model directory не является drop-in заменой GGUF.
ExLlamaV3 ориентирован на EXL3 и поддерживаемые HF weights, а не на GGUF.
Сам TabbyAPI отдельно отсылает к sister project для GGUF.
Практически это две разные ecosystems.
Как и GGUF, готовые EXL3 quants распространяются через Hugging Face.
Обычно repository содержит название вроде:
ModelName-EXL3-4.0bpw
или набор вариантов bitrate.
Но доступность EXL3 меньше, чем GGUF.
GGUF сейчас фактически стал массовым consumer-local format, поэтому популярные open-weight модели быстро получают множество GGUF conversions.
Когда выходит новая архитектура:
new attention
new MoE routing
new recurrent layer
new multimodal stack
runtime должен реализовать её.
У llama.cpp огромная community и очень широкий architecture coverage.
ExLlamaV3 развивается быстро, но ecosystem меньше.
Поэтому для совсем новой модели первым вопросом будет:
поддерживает ли её текущий ExLlamaV3?
а уже затем:
есть ли хороший EXL3 quant?
EXL3 старается сохранять исходную структуру модели.
Это помогает потому, что architecture mapping остаётся ближе к Transformers.
Это облегчает поддержку новых architectures, сравнение с HF, multimodal components, LoRA и потенциальную интеграцию с другими runtimes.
ExLlamaV3 поддерживает LoRA adapters поверх quantized base model.
Идея:
W_effective
=
W_quant
+
ΔW_LoRA
Base model остаётся сильно квантованной, а небольшой adapter хранится отдельно.
llama.cpp тоже имеет LoRA support, поэтому это не уникальное преимущество, но важная часть полноценного inference stack.
ExLlamaV3 поддерживает speculative decoding.
Смысл:
дешёвый drafter
→ предлагает несколько токенов
→ большая модель проверяет их batch-ом
Это уменьшает число последовательных target passes.
llama.cpp тоже активно развивает speculative decoding.
Различие здесь скорее в конкретных implementations и поддержке конкретных architectures.
AI-agent много раз делает:
prompt
→ reasoning
→ tool call
→ tool result
→ reasoning
→ code
→ test
→ reasoning
Поэтому важны:
длинный context
decode speed
prompt cache
tool calling
JSON/schema
parallel requests
ExLlamaV3 + TabbyAPI может быть очень подходящим вариантом:
полностью GPU-resident model
+
quantized cache
+
speculative decoding
+
OpenAI API
Но если агент требует model size больше доступной VRAM, преимущество может перейти к llama.cpp из-за более гибкого CPU offload.
| Свойство | ExLlamaV3 / EXL3 | llama.cpp / GGUF |
|---|---|---|
| Главный фокус | Consumer GPU | Универсальный local inference |
| Основной стек | Python + C++/CUDA | C/C++ |
| NVIDIA | Основной сценарий | Отличная поддержка |
| CPU-only | Не основной сценарий | Один из основных |
| Apple Silicon | Не основной target | Очень сильная поддержка |
| AMD | Ограниченнее | HIP/Vulkan |
| Quant format | EXL3 | множество GGUF quant types |
| Точный target bpw | Да | Обычно discrete recipes |
| Advanced low-bpw | Сильная сторона | I-quants/Dynamic тоже сильны |
| CPU+GPU hybrid | Развивается | Зрелый core use case |
| Multi-GPU | Tensor/expert parallel | Layer/row split и др. |
| KV quant | 2–8 bit flexible | Q4/Q8 и др. |
| Continuous batching | Да | Есть server batching |
| OpenAI API | TabbyAPI | llama-server |
| Model availability | Меньше | Огромная |
| Portability | Ниже | Очень высокая |
| «Скачал один файл» | Обычно нет | Да |
| GPU tuning | Очень специализированное | Более универсальное |
Нельзя написать:
ExLlamaV3 всегда быстрее llama.cpp
Производительность зависит от:
GPU generation
model architecture
dense vs MoE
bpw
context length
KV quant
multi-GPU topology
batch size
prefill/decode ratio
На современных GPU EXL3 specialized kernels могут быть очень эффективны.
На Ampere сложность EXL3 reconstruction может уменьшать преимущество, а простой GGUF integer quant иногда оказывается быстрее.
Допустим:
EXL3 = 4.0 bpw
GGUF ≈ 4.x bpw
Фактический memory footprint может отличаться:
Поэтому правильная ось сравнения:
реальная VRAM usage
а не только label quant-а.
Нужно зафиксировать:
одна модель
один context
один prompt
одинаковые sampler settings
одинаковый GPU
и сравнить:
VRAM after load
VRAM at full context
prompt tok/s
generation tok/s
собственные agent/coding tasks
время решения задачи
Именно последний показатель важнее всего.
Допустим:
Quant A:
70 tok/s
но модель делает 20 agent steps
Quant B:
60 tok/s
но делает 12 steps
Вторая конфигурация может решить задачу быстрее.
Сильно квантованная reasoning/coding model может чаще ошибаться, повторять действия и терять constraints.
Поэтому гоняться только за throughput опасно.
Предположим:
Q4_K_M:
90k context
а:
EXL3 3.5 bpw:
132k context
Даже если Q4 модель чуть точнее на коротких тестах, агент с длинной trajectory может работать лучше на EXL3, потому что не вынужден раньше суммаризировать и выбрасывать историю.
Практически можно мыслить так:
4.5–5 bpw
→ высокая fidelity, если VRAM позволяет
~4 bpw
→ хороший универсальный режим
3–3.75 bpw
→ экономим VRAM ради более большой модели/context
2–3 bpw
→ сильное сжатие; обязательно тестировать качество
<2 bpw
→ крайний/экспериментальный режим
Конкретная граница сильно зависит от модели.
Большие модели иногда переживают низкий bpw лучше маленьких за счёт избыточности.
Условно:
70B × 2.5 bit
≈ 21.9 GB raw bits
против:
32B × 5 bit
≈ 20 GB raw bits
без учёта overhead.
Возникает выбор:
более большая, но сильнее квантованная модель
против:
меньшая, но почти lossless
Нередко качество исходной модели выигрывает у лишних quant bits.
Но ниже определённой точки деградация квантования резко растёт, поэтому это надо измерять.
Dense 32B:
32B weights
и примерно все участвуют в каждом token
MoE 35B-A3B:
35B weights хранятся
но около 3B активны на token
Для памяти важны total parameters.
Для compute — active parameters.
Поэтому MoE особенно интересно квантизовать: оно memory-heavy, но compute per token относительно мал.
Есть два разных сценария.
Если:
Q4_K_M / Dynamic Q4
+
нужный context
+
MTP
всё стабильно помещается и скорость устраивает, переход на EXL3 не обязателен.
На Ampere простой Q4 kernel может быть очень эффективным.
Если Q4 не хватает нескольких гигабайт, EXL3 становится особенно интересен.
Можно подобрать:
3.25–3.75 bpw
и получить:
модель полностью в VRAM
+
длинный context
вместо CPU offload.
Вот здесь EXL3 может дать большой системный выигрыш.
RTX 3060 — Ampere.
EXL3 использует более сложные kernels, чем классические integer GGUF quants.
Поэтому возможна картина:
Q4_K_M llama.cpp
→ быстрее decode
EXL3
→ компактнее weights
Но если EXL3 позволяет избежать CPU offload или освободить память под контекст, вся система всё равно может оказаться быстрее и полезнее.
llama.cpp особенно логичен, если:
ExLlamaV3 особенно логичен, если:
Практичный локальный setup вполне может иметь оба:
~/llama.cpp/
~/tabbyAPI/
И разные модели:
models/
├── qwen-q4_k_m.gguf
├── huge-model-q3.gguf
└── qwen-exl3-3.5bpw/
Тогда:
llama.cpp
→ универсальность / CPU offload
ExLlamaV3
→ GPU-resident optimized workloads
Они не обязаны заменять друг друга.
Для конкретного AI-agent:
llama.cpp
GGUF Q4_K_M
KV Q4
132k
ExLlamaV3
EXL3 ~4 bpw
cache сопоставимого размера
132k
ExLlamaV3
EXL3 ~3.5 bpw
более длинный context / больше VRAM reserve
После этого запускать один и тот же набор задач.
weights VRAM
cache VRAM @ 32k
cache VRAM @ 64k
cache VRAM @ 128k
prefill tok/s @ 8k
prefill tok/s @ 32k
prefill tok/s @ 64k
decode tok/s @ 8k
decode tok/s @ 32k
decode tok/s @ 64k
time-to-first-token
agent success rate
avg agent steps
total wall-clock
После такого benchmark выбор становится намного объективнее.
VRAM состоит не только из weights.
Полный budget:
model weights
+
KV/recurrent cache
+
CUDA context
+
compute buffers
+
temporary activations
+
sampling buffers
+
speculative/MTP state
Поэтому файл размером 22 ГБ не означает, что он гарантированно запустится на 24-ГБ GPU.
Нужен резерв под runtime.
Допустим после учёта KV и runtime под weights осталось:
19.2 GB
С GGUF можно оказаться между двумя quant recipes.
EXL3 позволяет подобрать bitrate:
3.75
3.85
3.95
и использовать память плотнее.
Это особенно полезно на consumer GPU, где каждый гигабайт критичен.
Можно выиграть память ещё через:
cache quantization
context length
offloading embeddings
lm_head precision
CPU cache tier
batch size
speculative settings
Поэтому tuning EXL3 многомерный.
Проект распространяет готовые wheels под конкретные сочетания CUDA, PyTorch и Python.
Можно также:
pip install exllamav3
но тогда в некоторых конфигурациях потребуется локальная сборка C++/CUDA extension.
Для полноценного API server разработчики рекомендуют TabbyAPI.
Типичный путь:
git clone https://github.com/theroyallab/tabbyAPI
cd tabbyAPI
./start.sh
Либо Docker:
docker pull ghcr.io/theroyallab/tabbyapi:latest
После запуска API можно использовать как OpenAI-compatible backend.
Если агент использует абстракцию OpenAI API:
client = OpenAI(
base_url="http://localhost:5000/v1",
api_key="..."
)
backend можно менять без переписывания ReAct-логики.
Это хорошая архитектура: агент не должен знать детали quantized inference.
ExLlamaV3 имеет интеграцию с Hugging Face Transformers.
Это логично, потому что EXL3 сохраняет HF-подобную структуру tensors.
GGUF, напротив, сознательно является отдельным runtime-oriented representation.
Один файл:
model.gguf
очень удобен.
Его легко:
GGUF стал практически lingua franca локальных LLM.
EXL3 ecosystem более специализирован.
Directory с:
config.json
tokenizer
safetensors
лучше соответствует тому, как исходные модели публикуются разработчиками.
Это уменьшает семантический разрыв между original и quantized model и потенциально облегчает поддержку сложных новых architectures.
llama.cpp исторически очень хорошо использует memory mapping:
GGUF
→ mmap
→ pages ОС
и частично выполняет модель из system RAM.
Это одна из причин, почему GGUF настолько удобен для больших моделей и CPU offload.
GPU-centric runtime вроде ExLlamaV3 больше ориентирован на explicit loading tensors в GPU memory.
Представим:
model = 40 GB
VRAM = 24 GB
RAM = 64 GB
llama.cpp может сделать:
часть → GPU
остальное → CPU
и запустить модель.
Скорость снизится, но модель доступна.
EXL3 чаще пытается решить проблему иначе:
квантизовать сильнее
→ всё-таки вместить модель в VRAM
Это два разных подхода.
Один из главных practical trade-off:
A:
Q4
+
часть weights на CPU
против:
B:
EXL3 3.2 bpw
+
100% weights на GPU
B часто будет намного быстрее.
Но A может сохранить больше model fidelity.
Для AI-agent конечный результат надо измерять по успешности задач.
Для MoE CPU offload может быть менее болезненным, если offloaded experts редко активируются.
Современные runtimes начинают использовать это специально:
часть experts → CPU
часть → GPU
Но routing непредсказуем, и PCIe traffic может стать bottleneck.
И ExLlamaV3, и другие engines активно развивают архитектурно-специфичный MoE offload.
На август 2026 года ExLlamaV3 развивается очень быстро. Актуальная release-линия уже 1.4.x, обновления выходят часто.
Это значит:
плюс:
быстро появляются architectures и performance improvements
минус:
rolling release
config/API может меняться
возможны regressions
TabbyAPI прямо позиционирует себя как проект для локального или небольшого числа пользователей, а не как production serving platform для крупного внешнего SaaS.
У vLLM другой главный сценарий:
server throughput
много concurrent users
datacenter GPUs
production serving
ExLlamaV3:
consumer hardware
локальный пользователь
эффективные quantized models
TabbyAPI добавляет batching и server features, но оптимизационная цель остаётся другой.
Очень грубо:
llama.cpp
= запускается почти на всём
ExLlamaV3
= выжимаем consumer NVIDIA GPU
vLLM
= high-throughput production serving
Зоны пересекаются, но такая модель полезна.
Не совсем. EXL3 — специализированное quantized representation, а GGUF — более общий container с множеством tensor quant types.
Нет. Особенно на Ampere это надо benchmark'ить.
Нет. Современный GGUF ecosystem имеет K-quants, I-quants, importance-aware и Dynamic recipes.
Устаревшее утверждение. В V3 появились CPU offload mechanisms и CPU cache tier, но GPU остаётся главным сценарием.
Не обязательно. Advanced quantization может давать лучшее качество на бит.
Нужен CPU / Apple / AMD?
│
├─ да → llama.cpp
│
└─ нет, NVIDIA GPU
│
├─ модель заметно больше VRAM?
│ │
│ ├─ да → llama.cpp CPU offload
│ │ или EXL3 более низкий bpw
│ │
│ └─ нет
│
├─ GGUF Q4 хорошо влезает и быстрый?
│ └─ да → нет обязательной причины менять
│
└─ не хватает VRAM / нужен точный bpw /
хочется GPU-optimized stack
→ пробовать ExLlamaV3 + EXL3
Я бы пробовал три класса конфигураций:
Q4_K_M / Dynamic Q4
llama.cpp
Если всё помещается — отличный baseline.
3.2–4.0 bpw
ExLlamaV3
чтобы освободить место под context, cache или более большую модель.
Q3/Q4
+
CPU offload
если даже EXL3 не позволяет полностью вместить нужную модель.
Не синтетическую маленькую Llama, а модель, которую реально будет использовать агент.
Сделать:
A:
llama.cpp
GGUF ~4-bit
B:
ExLlamaV3
EXL3 ~4 bpw
C:
ExLlamaV3
EXL3 ~3.5 bpw
После чего одинаковые контексты:
32k
64k
100k+
и одинаковый набор agent tasks.
Возможны три результата.
GGUF быстрее и всё помещается
Остаёмся на llama.cpp.
EXL3 чуть медленнее,
но даёт заметно больше context
Для агента EXL3 может быть лучше.
EXL3 позволяет полностью GPU-resident более большую модель,
а GGUF требует CPU offload
Тогда EXL3 может победить очень сильно.
Не надо выбирать формат по идеологии.
Выбирается полная operating point системы:
model intelligence
×
quantization fidelity
×
context
×
KV precision
×
VRAM
×
prefill speed
×
decode speed
×
agent success rate
Именно это определяет реальную эффективность локального AI-agent.
ExLlamaV3
= специализированный GPU inference runtime
EXL3
= QTIP-inspired advanced quantization
с гибким target bitrate
TabbyAPI
= OpenAI-compatible server для ExLlamaV3
А:
llama.cpp
= универсальный inference runtime
GGUF
= универсальный container
Q4_K_M / IQ4_XS / ...
= quant schemes внутри GGUF
Главное различие:
llama.cpp
оптимизирует универсальность
ExLlamaV3
оптимизирует GPU-resident quantized inference
EXL3 особенно интересен, когда VRAM почти хватает и несколько дополнительных гигабайт экономии позволяют убрать CPU offload, увеличить context или взять более сильную модель.
Но на Ampere GPU вроде RTX 3060 нельзя предполагать, что EXL3 автоматически будет быстрее Q4_K_M: более сложная реконструкция весов может стоить заметных вычислений.
Поэтому лучший инженерный подход:
держать llama.cpp как универсальный baseline, а ExLlamaV3 использовать как специализированный GPU-инструмент и сравнивать их на реальной модели, реальном контексте и реальных agent-задачах.
Официальный репозиторий ExLlamaV3:
https://github.com/turboderp-org/exllamav3
Документация EXL3:
https://github.com/turboderp-org/exllamav3/blob/master/doc/exl3.md
Документация по EXL3 conversion:
https://github.com/turboderp-org/exllamav3/blob/master/doc/convert.md
Releases ExLlamaV3:
https://github.com/turboderp-org/exllamav3/releases
Официальный TabbyAPI:
https://github.com/theroyallab/tabbyAPI
llama.cpp:
https://github.com/ggml-org/llama.cpp
Документация llama.cpp quantization:
https://github.com/ggml-org/llama.cpp/blob/master/tools/quantize/README.md
QTIP:
https://github.com/Cornell-RelaxML/qtip