- Установка или сборка проекта
- Скачивание моделей
- Формат GGUF и квантование
- Ключевые флаги запуска
- System Prompt (Системный промпт)
- Структурированный вывод (JSON/GBNF)
- llama-cli: консольный режим
- llama-server: API-сервис
- Диагностика и мониторинг
- Шаблоны команд
- Решение типичных проблем
- Полезные ссылки
llama.cpp — легковесный движок для инференса LLM, написанный на C++. Позволяет запускать модели в формате GGUF (стандартный формат квантованных моделей), используя CPU (инструкции AVX/AVX512) и GPU (CUDA, Metal, Vulkan). Поддерживаются модели семейств LLaMA, Mistral, Qwen2, Qwen2Moe, Phi3, Bloom, Falcon, StableLM, GPT2, Starcoder2, T5, Mamba, Nemotron, Qwen3, Vistral.
| Способ установки | Windows | Mac | Linux |
|---|---|---|---|
| Winget | ✅ | ||
| Homebrew | ✅ | ✅ |
winget install llama.cpp
Пакет автоматически обновляется с выходом новых версий llama.cpp.
brew install llama.cpp
Пакет автоматически обновляется с выходом новых версий llama.cpp.
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp| Платформа | Команда |
|---|---|
| NVIDIA (CUDA) | cmake -B build -DGGML_CUDA=ON && cmake --build build --config Release |
| CPU-only | cmake -B build && cmake --build build --config Release |
| Apple Silicon (Metal) | Ускорение включено по умолчанию при обычной сборке |
После сборки исполняемые файлы находятся в директории build/bin/.
NVIDIA (CUDA):
Убедитесь, что установлен CUDA Toolkit. Версия CUDA должна соответствовать вашей видеокарте. После сборки проверьте наличие строки ggml_cuda_init в логах при запуске — это подтверждает активацию GPU-ускорения.
Apple Silicon (Metal):
На macOS с процессорами M1/M2/M3/M4 ускорение Metal включается автоматически. При запуске в логах должна появиться строка ggml_metal_init, подтверждающая использование GPU. Unified Memory архитектура Apple Silicon позволяет загружать модели, размер которых превышает объём "видеопамяти", так как RAM и VRAM физически едины.
CPU-only: Подходит для серверов без GPU или для тестирования. Убедитесь, что ваш процессор поддерживает инструкции AVX2 или AVX512 для оптимальной производительности.
pip install huggingface_hub# Скачивание конкретного файла GGUF
huggingface-cli download <автор>/<репозиторий> <имя_файла.gguf> --local-dir ./models
# Пример: скачивание Qwen2.5-7B в квантовании Q4_K_M
huggingface-cli download Qwen/Qwen2.5-7B-Instruct-GGUF qwen2.5-7b-instruct-q4_k_m.gguf --local-dir ./models
# Скачивание всего репозитория (все квантования)
huggingface-cli download Qwen/Qwen2.5-7B-Instruct-GGUF --local-dir ./modelsПри поиске моделей на HuggingFace по тегу GGUF рекомендуется обращать внимание на авторов Bartowski и MaziyarPanahi — они известны качественными конвертациями с правильными метаданными и chat templates.
Типичное имя файла GGUF: model-name-7b-instruct-q4_k_m.gguf
- model-name — название модели (qwen2.5, llama3, mistral)
- 7b — размер модели в миллиардах параметров
- instruct — тип модели (instruct/chat для диалогов, base для дообучения)
- q4_k_m — тип квантования
Для ручного скачивания GGUF-файлов через браузер:
1. Переход к файлам модели
Откройте страницу репозитория (например, unsloth/Nemotron-3-Nano-30B-A3B-GGUF) и перейдите во вкладку Files and versions.
2. Выбор квантования
В списке файлов найдите нужный GGUF-файл. Имя файла содержит информацию о квантовании:
Q4_K_M— золотой стандарт, баланс качества и размераQ5_K_M— выше качество, больше размерQ8_0— максимальное качество среди квантованныхQ3_K_M,Q2_K— для ограниченной памяти
3. Скачивание файла
Нажмите на имя файла, затем кнопку Download (или иконку загрузки справа от имени файла). Для крупных моделей (10+ ГБ) рекомендуется использовать менеджер загрузок.
4. Размещение файла
Переместите скачанный .gguf файл в директорию с моделями:
# Пример структуры
./models/
└── Nemotron-3-Nano-30B-A3B-Q4_K_M.ggufКвантование — сжатие весов модели (из 16 бит в 4, 5 или 8 бит). Это ключевая технология, позволяющая запускать большие модели на потребительском железе.
| Тип | Описание | Применение | Потеря качества |
|---|---|---|---|
| Q8_0 | 8-битное квантование | Когда важна точность | Минимальная (~0.1%) |
| Q6_K | 6-битное квантование | Хороший баланс | Очень низкая (~0.3%) |
| Q5_K_M | 5-битное квантование | Баланс качества и размера | Низкая (~0.5%) |
| Q4_K_M | 4-битное, золотой стандарт | Рекомендуется для большинства | Приемлемая (~1%) |
| Q4_K_S | 4-битное, меньше размер | Экономия памяти | Заметная (~1.5%) |
| Q3_K_M | 3-битное квантование | Ограниченная память | Значительная (~2-3%) |
| Q2_K | 2-битное квантование | Экстремальная экономия | Существенная (~5-10%) |
| IQ4_XS | Улучшенное 4-битное | Очень слабое железо | Средняя (~1-2%) |
| IQ3_XXS | Улучшенное 3-битное | Минимальные требования | Высокая (~3-5%) |
pip install -r requirements.txt
python convert_hf_to_gguf.py models/mymodel/ --outfile model.gguf --outtype q8_0Для модели с B миллиардами параметров:
| Квантование | Формула | Пример (7B) | Пример (70B) |
|---|---|---|---|
| FP16 | B × 2.0 ГБ |
14 ГБ | 140 ГБ |
| Q8_0 | B × 1.0 ГБ |
7 ГБ | 70 ГБ |
| Q6_K | B × 0.85 ГБ |
6 ГБ | 60 ГБ |
| Q5_K_M | B × 0.75 ГБ |
5.3 ГБ | 53 ГБ |
| Q4_K_M | B × 0.7 ГБ |
4.9 ГБ | 49 ГБ |
| Q3_K_M | B × 0.55 ГБ |
3.9 ГБ | 39 ГБ |
| Q2_K | B × 0.4 ГБ |
2.8 ГБ | 28 ГБ |
Дополнительно для контекста (KV-кэш):
| Размер контекста | Дополнительная память |
|---|---|
| 2048 токенов | +0.25 ГБ |
| 4096 токенов | +0.5 ГБ |
| 8192 токенов | +1.0 ГБ |
| 16384 токенов | +2.0 ГБ |
| 32768 токенов | +4.0 ГБ |
| 65536 токенов | +8.0 ГБ |
| 131072 токенов | +16.0 ГБ |
Пример: модель 7B в Q4_K_M с контекстом 8192 займёт ~5.9 ГБ VRAM.
| Объём VRAM | Рекомендуемый размер модели | Квантование |
|---|---|---|
| 4 ГБ | 3B-7B | Q4_K_M или Q3_K_M |
| 6 ГБ | 7B | Q4_K_M или Q5_K_M |
| 8 ГБ | 7B-13B | Q4_K_M |
| 12 ГБ | 13B | Q5_K_M или Q6_K |
| 16 ГБ | 13B-24B | Q4_K_M |
| 24 ГБ | 24B-34B | Q4_K_M или Q5_K_M |
| 32 ГБ | 34B-70B | Q4_K_M |
| 48 ГБ | 70B | Q4_K_M или Q5_K_M |
| 64+ ГБ | 70B+ | Q5_K_M или Q6_K |
| Флаг | Полная форма | Описание | Рекомендация |
|---|---|---|---|
-m |
--model |
Путь к файлу модели | Обязательный |
-ngl |
--n-gpu-layers |
Количество слоёв на GPU | 99 — загрузить максимум |
-t |
--threads |
Ядер CPU для генерации | Физические ядра (не потоки!) |
-tb |
--threads-batch |
Ядер CPU для обработки промпта | Может быть выше -t |
-mg |
--main-gpu |
Индекс основной видеокарты | При нескольких GPU (0, 1, 2...) |
-sm |
--split-mode |
Режим разделения между GPU | none, layer, row |
-ts |
--tensor-split |
Распределение памяти между GPU | Пропорции через запятую |
Критически важно: указывайте количество физических ядер, а не логических потоков (Hyper-Threading / SMT).
# Пример: CPU с 8 ядрами / 16 потоков
-t 8 # Правильно: используем физические ядра
-t 16 # Неправильно: HT/SMT потоки замедляют инференсИспользование виртуальных потоков часто замедляет инференс из-за конкуренции за кэш процессора и задержек при переключении контекста.
| Параметр | Назначение | Рекомендуемое значение |
|---|---|---|
--threads (-t) |
Генерация токенов (последовательная работа) | Физические ядра CPU |
--threads-batch (-tb) |
Обработка prompt (параллельная работа) | Все ядра или больше |
Как определить количество физических ядер:
| ОС | Команда |
|---|---|
| Linux | lscpu | grep "Core(s) per socket" или nproc --all |
| macOS | sysctl -n hw.physicalcpu |
| Windows | wmic cpu get NumberOfCores |
Рекомендации по платформам:
| Платформа | -t (threads) |
-tb (threads-batch) |
|---|---|---|
| Apple M1 | 4 | 8 |
| Apple M1 Pro/Max | 6-8 | 10 |
| Apple M2 | 4 | 8 |
| Apple M2 Pro/Max | 6-8 | 12 |
| Apple M3 | 4 | 8 |
| Apple M3 Pro/Max | 4-6 | 12-14 |
| Apple M4 | 4 | 10 |
| Apple M4 Pro | 6-8 | 12-14 |
| Apple M4 Max | 8-10 | 14-16 |
| Apple M5 | 4-6 | 10-12 |
| Intel i7 (8 ядер) | 8 | 8 |
| Intel i9 (16 ядер) | 16 | 16 |
| AMD Ryzen 7 (8 ядер) | 8 | 8 |
| AMD Ryzen 9 (16 ядер) | 16 | 16 |
| Флаг | Полная форма | Описание | Значения |
|---|---|---|---|
-c |
--ctx-size |
Размер контекста (токены) | 2048, 4096, 8192, 16384, 32768, 65536, 131072 |
-b |
--batch-size |
Токенов за раз при чтении промпта | 512 оптимально, 128 для снижения нагрева |
-ub |
--ubatch-size |
Размер микро-батча | 512 для большинства, 128 для экономии памяти |
-fa |
--flash-attn |
Flash Attention (on/off/auto) | Обязательно для экономии VRAM |
Подробнее о размере контекста:
Контекст определяет, сколько текста модель может "помнить" в рамках одного разговора. Один токен ≈ 0.75 слова для английского языка и ≈ 0.5 слова для русского (кириллица кодируется менее эффективно).
| Контекст | Примерный объём текста | Применение |
|---|---|---|
| 2048 | ~1500 слов / ~2-3 страницы | Короткие диалоги |
| 4096 | ~3000 слов / ~5-6 страниц | Стандартные диалоги |
| 8192 | ~6000 слов / ~10-12 страниц | Длинные разговоры, анализ документов |
| 16384 | ~12000 слов / ~20-25 страниц | Работа с большими текстами |
| 32768 | ~24000 слов / ~40-50 страниц | Анализ книг, длинный код |
| 65536 | ~48000 слов / ~80-100 страниц | Очень большие документы |
| 131072 | ~96000 слов / ~150-200 страниц | Максимальные задачи |
Подробнее о batch-size:
Параметры -b и -ub влияют на то, как модель обрабатывает входной текст (prompt). Большие значения ускоряют обработку длинных промптов, но увеличивают пиковое потребление памяти и нагрев GPU.
| Значение | Эффект | Когда использовать |
|---|---|---|
512 |
Стандартная скорость, умеренный нагрев | По умолчанию |
256 |
Чуть медленнее, меньше нагрев | Ноутбуки, тихая работа |
128 |
Медленнее, минимальный нагрев | Apple Silicon (для снижения температуры) |
64 |
Самая медленная обработка, холодная работа | Критически важно избежать перегрева |
1024 |
Быстрее обработка, больше нагрев | Мощные десктопные GPU |
2048 |
Максимальная скорость обработки | Серверные GPU (A100, H100) |
Flash Attention — оптимизированный алгоритм вычисления механизма внимания, который значительно снижает потребление памяти и ускоряет работу с длинными контекстами.
--flash-attn on # Включить принудительно
--flash-attn off # Выключить
--flash-attn auto # Автоматический выбор (по умолчанию)Преимущества Flash Attention:
- Снижение потребления VRAM на 20-40% при больших контекстах
- Ускорение обработки длинных промптов
- Меньший нагрев GPU
- Возможность использовать больший контекст на том же железе
Когда выключать:
- При возникновении ошибок или артефактов в генерации (редко)
- На очень старых GPU без поддержки
Memory mapping — механизм ОС, который отображает файл модели в виртуальную память без полной загрузки в RAM. По умолчанию включено.
| Флаг | Описание |
|---|---|
--mmap |
Включить memory mapping (по умолчанию) |
--no-mmap |
Отключить mmap, загружать модель полностью в RAM |
--mlock |
Заблокировать модель в RAM, предотвращая swapping* |
| *Swapping — механизм операционной системы, при котором данные из оперативной памяти (RAM) выгружаются на диск (SSD/HDD), когда физической памяти не хватает. |
При работе с LLM это критично: если часть весов модели попадает в swap, каждое обращение к ним вызывает чтение с диска вместо RAM. Скорость падает в десятки раз — генерация токенов замедляется с миллисекунд до секунд.
Флаг --mlock в llama.cpp блокирует модель в RAM, запрещая системе выгружать её в swap. Это гарантирует стабильную производительность, но требует достаточного объёма физической памяти для всей модели.
Когда использовать --no-mmap:
- Нужна стабильная производительность без непредсказуемых задержек
- Работа с сетевыми или виртуальными файловыми системами
- Достаточно RAM для полной загрузки модели
Когда использовать --mlock:
- Хотите гарантировать, что модель не будет выгружена в swap
- Достаточно RAM и хотите максимальную стабильность отклика
- Особенно полезно на системах с большим объёмом RAM (64+ ГБ)
Комбинация --no-mmap --mlock:
Полная загрузка модели в RAM с блокировкой от выгрузки. Требует достаточного объёма памяти, но обеспечивает максимально стабильную производительность.
Особенность: при mmap утилиты мониторинга (htop) могут показывать заниженное потребление RAM, поскольку memory-mapped файлы учитываются как "cache".
| Флаг | Полная форма | Описание | Значения |
|---|---|---|---|
-n |
--n-predict |
Максимум токенов в ответе | 256, 512, 1024, 2048, 4096, -1, -2 |
Особые значения -n:
-n 256— очень короткие ответы-n 512— стандартное значение для коротких ответов-n 1024— средние ответы-n 2048— для развёрнутых ответов и генерации кода-n 4096— для очень длинных ответов, больших блоков кода-n 8192— максимально длинные ответы-n -1— генерация без ограничений (до заполнения контекста)-n -2— генерация до заполнения контекста с остановкой на EOS-токене
EOS-токен (End Of Sequence) — специальный токен, который модель генерирует, когда считает ответ завершённым. Это сигнал "я закончил говорить".
Разница между -n -1 и -n -2:
При -n -1 модель генерирует токены до полного заполнения контекстного окна, игнорируя EOS. Это может привести к "бреду" после логического завершения ответа — модель продолжит генерировать текст, даже если уже ответила на вопрос.
При -n -2 модель останавливается в двух случаях: либо при генерации EOS-токена (естественное завершение), либо при заполнении контекста. Это более разумное поведение — ответ заканчивается там, где модель сама решила остановиться.
Практический пример:
Вопрос: "Сколько будет 2+2?"
С -n -1: "4. Это базовая арифметика. Кстати, математика — наука о числах... [продолжает до конца контекста]"
С -n -2: "4." [остановка на EOS]
Для большинства задач -n -2 предпочтительнее, если не указано конкретное ограничение длины.
| Флаг | Полная форма | Описание | Диапазон | По умолчанию |
|---|---|---|---|---|
--temp |
--temperature |
Температура | 0.0–2.0 | 0.8 |
--top-k |
--top-k |
Топ-K токенов | 1–100 | 40 |
--top-p |
--top-p |
Nucleus sampling | 0.0–1.0 | 0.95 |
--min-p |
--min-p |
Минимальная вероятность | 0.0–1.0 | 0.05 |
--repeat-penalty |
--repeat-penalty |
Штраф за повторы | 1.0–2.0 | 1.1 |
--presence-penalty |
--presence-penalty |
Штраф за присутствие | 0.0–2.0 | 0.0 |
--frequency-penalty |
--frequency-penalty |
Штраф за частоту | 0.0–2.0 | 0.0 |
Подробнее о температуре:
| Температура | Эффект | Применение |
|---|---|---|
| 0.0 | Детерминированный вывод (всегда одинаковый) | Точные ответы, факты |
| 0.1–0.3 | Очень консервативный, предсказуемый | Код, математика, перевод |
| 0.4–0.6 | Умеренно творческий | Рерайт, суммаризация |
| 0.7–0.8 | Стандартный баланс | Обычные диалоги |
| 0.9–1.0 | Творческий | Креативное письмо, истории |
| 1.1–1.5 | Очень творческий, может быть нестабильным | Брейншторминг |
| 1.5–2.0 | Хаотичный, часто бессмысленный | Экспериментальные цели |
Подробнее о top-k и top-p:
- top-k: Из всех возможных следующих токенов выбирает только K наиболее вероятных.
top-k 40означает выбор из 40 лучших кандидатов. - top-p (nucleus sampling): Выбирает минимальное количество токенов, суммарная вероятность которых >= p.
top-p 0.95означает выбор из токенов, покрывающих 95% вероятностной массы.
Рекомендуемые комбинации:
| Задача | temp | top-k | top-p | repeat-penalty |
|---|---|---|---|---|
| Код | 0.1–0.2 | 40 | 0.9 | 1.1 |
| Математика | 0.0–0.1 | 40 | 0.9 | 1.0 |
| Перевод | 0.2–0.3 | 40 | 0.95 | 1.1 |
| Чат | 0.7–0.8 | 40 | 0.95 | 1.1 |
| Креатив | 0.9–1.0 | 50 | 0.95 | 1.15 |
| Ролевая игра | 0.8–1.0 | 60 | 0.98 | 1.2 |
| Флаг | Описание |
|---|---|
--seed |
Seed для воспроизводимости результатов (число) |
--keep |
Количество токенов промпта для сохранения при очистке контекста |
--escape |
Обрабатывать escape-последовательности (\n, \t и др.) |
--no-penalize-nl |
Не штрафовать за символы новой строки |
--prompt-cache |
Путь к файлу кэша промпта |
--prompt-cache-all |
Кэшировать весь промпт |
| Для каждой модели эти параметры могут варьироваться. | |
| Например, коллеги из команды Vikhr пишут, что для их модели Vistral рекомендуемые параметры температуры от 0,1 до 0,5. |
System prompt — это специальная инструкция, которая задаёт поведение, роль и ограничения модели на протяжении всего диалога. Системный промпт обрабатывается перед пользовательскими сообщениями и влияет на стиль, тон и содержание всех ответов.
| Флаг | Описание | Применение |
|---|---|---|
-p |
--prompt |
Начальный промпт (может включать системный) |
-f |
--file |
Файл с промптом |
-sp |
--system-prompt |
Системный промпт напрямую |
-spf |
--system-prompt-file |
Файл с системным промптом |
Через флаг -p (inline):
llama-cli -m model.gguf -ngl 99 -c 8192 -p "Ты — опытный программист на Python. Отвечай кратко и по делу." -i -ins --colorЧерез файл -f:
# Создаём файл system.txt:
# Ты — профессиональный переводчик. Переводи тексты с английского на русский,
# сохраняя стиль и тон оригинала.
llama-cli -m model.gguf -ngl 99 -c 8192 -f system.txt -i -ins --colorЧерез флаг --system-prompt:
llama-cli -m model.gguf -ngl 99 -c 8192 --system-prompt "Ты — дружелюбный ассистент." -i -ins --colorЧерез флаг --system-prompt-file:
# Создаём файл system_prompt.txt с инструкциями
llama-server -m model.gguf --port 8080 -ngl 99 -c 8192 --system-prompt-file system_prompt.txtЧерез API (в каждом запросе):
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8080/v1", api_key="sk-no-key-required")
response = client.chat.completions.create(
model="local-model",
messages=[
{
"role": "system",
"content": "Ты — эксперт по кибербезопасности. Отвечай технически точно, приводи примеры кода когда уместно."
},
{
"role": "user",
"content": "Как защититься от SQL-инъекций?"
}
],
max_tokens=1024
)cURL с системным промптом:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-model",
"messages": [
{"role": "system", "content": "Ты — краткий и точный ассистент. Отвечай максимум в 2-3 предложениях."},
{"role": "user", "content": "Что такое Docker?"}
],
"max_tokens": 256
}'Для программирования:
Ты — Senior Software Engineer с 15-летним опытом.
Правила:
- Пиши чистый, документированный код
- Следуй принципам SOLID и DRY
- Всегда объясняй сложные решения
- Предупреждай о потенциальных проблемах безопасности
- Используй современные best practices
Для анализа данных:
Ты — Data Scientist.
При анализе данных:
1. Сначала задавай уточняющие вопросы о данных
2. Предлагай несколько подходов к решению
3. Объясняй статистические методы простым языком
4. Всегда указывай на ограничения анализа
Для перевода:
Ты — профессиональный переводчик EN↔RU.
Правила перевода:
- Сохраняй стиль и тон оригинала
- Технические термины оставляй на английском с пояснением
- Идиомы адаптируй под целевую культуру
- При неоднозначности предлагай варианты
Для ролевой игры:
Ты — мудрый волшебник из средневекового фэнтези-мира.
- Говори архаичным, но понятным языком
- Отвечай загадками и метафорами
- Никогда не выходи из роли
- Ссылайся на магические законы и древние тексты
Для JSON-ответов:
Ты — API-ассистент.
ВАЖНО: Отвечай ТОЛЬКО валидным JSON без дополнительного текста.
Формат ответа: {"answer": "...", "confidence": 0.0-1.0, "sources": [...]}
| Аспект | Рекомендация |
|---|---|
| Длина | Оптимально 100-500 токенов. Слишком длинный промпт съедает контекст |
| Структура | Используйте списки и чёткие правила |
| Роль | Начните с определения роли ("Ты — ...") |
| Ограничения | Явно укажите, чего делать нельзя |
| Формат | Опишите желаемый формат ответов |
| Примеры | Для сложных задач добавьте few-shot примеры |
| Язык | Укажите язык ответов, если важно |
llama.cpp поддерживает принудительное ограничение формата вывода модели. Это критически важно для интеграции с приложениями или для построения автоматизаций, в которых нужен строго валидный JSON или другой структурированный формат.
| Метод | Описание | Надёжность | Сложность |
|---|---|---|---|
| JSON Schema | Определение структуры через JSON Schema | Высокая | Низкая |
| Grammar (GBNF) | Формальная грамматика в формате GBNF | Максимальная | Высокая |
| Response Format | Простое указание типа (json_object) | Средняя | Минимальная |
Флаги:
| Флаг | Описание |
|---|---|
--json-schema |
JSON Schema для ограничения вывода (inline) |
--json-schema-file |
Путь к файлу с JSON Schema |
Пример использования в llama-cli:
llama-cli -m model.gguf -ngl 99 -c 4096 \
-p "Извлеки информацию о человеке из текста: John Smith, 35 лет, инженер из Нью-Йорка" \
--json-schema '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"},"occupation":{"type":"string"},"city":{"type":"string"}},"required":["name","age"]}' \
-n 256Пример схемы (файл schema.json):
{
"type": "object",
"properties": {
"sentiment": {
"type": "string",
"enum": ["positive", "negative", "neutral"]
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"keywords": {
"type": "array",
"items": {"type": "string"},
"maxItems": 5
},
"summary": {
"type": "string",
"maxLength": 200
}
},
"required": ["sentiment", "confidence", "summary"]
}Запуск с файлом схемы:
llama-cli -m model.gguf -ngl 99 -p "Проанализируй отзыв: Отличный продукт!" --json-schema-file schema.json -n 256Python (OpenAI SDK):
from openai import OpenAI
import json
client = OpenAI(base_url="http://localhost:8080/v1", api_key="sk-no-key-required")
# Определяем схему
schema = {
"type": "object",
"properties": {
"product_name": {"type": "string"},
"rating": {"type": "integer", "minimum": 1, "maximum": 5},
"pros": {"type": "array", "items": {"type": "string"}},
"cons": {"type": "array", "items": {"type": "string"}},
"recommendation": {"type": "boolean"}
},
"required": ["product_name", "rating", "recommendation"]
}
response = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "Извлекай структурированную информацию из отзывов о товарах."},
{"role": "user", "content": "iPhone 15 Pro — отличный телефон! Камера супер, батарея держит весь день. Минус только цена. Рекомендую!"}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "product_review",
"strict": True,
"schema": schema
}
},
max_tokens=512
)
result = json.loads(response.choices[0].message.content)
print(json.dumps(result, indent=2, ensure_ascii=False))cURL с JSON Schema:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-model",
"messages": [
{"role": "system", "content": "Извлекай данные в JSON."},
{"role": "user", "content": "Москва — столица России, население около 12 миллионов."}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "city_info",
"strict": true,
"schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"},
"is_capital": {"type": "boolean"}
},
"required": ["city", "country"]
}
}
},
"max_tokens": 256
}'Для случаев, когда нужен просто валидный JSON без строгой схемы:
Python:
response = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "Отвечай только валидным JSON."},
{"role": "user", "content": "Перечисли 3 языка программирования с их годом создания."}
],
response_format={"type": "json_object"},
max_tokens=256
)cURL:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-model",
"messages": [
{"role": "system", "content": "Отвечай в формате JSON."},
{"role": "user", "content": "Какая сегодня погода? (придумай)"}
],
"response_format": {"type": "json_object"},
"max_tokens": 256
}'Grammar — более мощный инструмент, позволяющий описать любой формат вывода с помощью формальной грамматики в формате GBNF (GGML BNF).
Флаги:
| Флаг | Описание |
|---|---|
--grammar |
Грамматика GBNF (inline) |
--grammar-file |
Путь к файлу с грамматикой |
Пример простой грамматики (json.gbnf):
root ::= object
value ::= object | array | string | number | ("true" | "false" | "null") ws
object ::=
"{" ws (
string ":" ws value
("," ws string ":" ws value)*
)? "}" ws
array ::=
"[" ws (
value
("," ws value)*
)? "]" ws
string ::=
"\"" (
[^"\\\x7F\x00-\x1F] |
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
)* "\"" ws
number ::= ("-"? ([0-9] | [1-9] [0-9]*)) ("." [0-9]+)? ([eE] [-+]? [0-9]+)? ws
ws ::= ([ \t\n] ws)?
Запуск с грамматикой:
llama-cli -m model.gguf -ngl 99 -p "Создай JSON с информацией о книге" --grammar-file json.gbnf -n 256Грамматика для списка (list.gbnf):
root ::= "- " item ("\n- " item)*
item ::= [a-zA-Zа-яА-ЯёЁ0-9 ]+
Грамматика для да/нет ответов (yesno.gbnf):
root ::= "да" | "нет" | "Да" | "Нет" | "ДА" | "НЕТ"
Грамматика для email (email.gbnf):
root ::= local "@" domain
local ::= [a-zA-Z0-9._%+-]+
domain ::= [a-zA-Z0-9.-]+ "." [a-zA-Z]{2,}
Грамматика для структурированного ответа:
root ::= "ОТВЕТ: " answer "\nУВЕРЕННОСТЬ: " confidence "\nИСТОЧНИК: " source
answer ::= [a-zA-Zа-яА-ЯёЁ0-9 .,!?-]+
confidence ::= "высокая" | "средняя" | "низкая"
source ::= [a-zA-Zа-яА-ЯёЁ0-9 .,://-]+
Для извлечения сущностей (NER):
{
"type": "object",
"properties": {
"entities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"text": {"type": "string"},
"type": {
"type": "string",
"enum": ["PERSON", "ORGANIZATION", "LOCATION", "DATE", "MONEY", "PRODUCT"]
},
"start": {"type": "integer"},
"end": {"type": "integer"}
},
"required": ["text", "type"]
}
}
},
"required": ["entities"]
}Для классификации:
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["technology", "sports", "politics", "entertainment", "science", "business"]
},
"subcategory": {"type": "string"},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
"reasoning": {"type": "string", "maxLength": 500}
},
"required": ["category", "confidence"]
}Для генерации API-ответов:
{
"type": "object",
"properties": {
"success": {"type": "boolean"},
"data": {
"type": "object",
"properties": {
"id": {"type": "string"},
"created_at": {"type": "string", "format": "date-time"},
"result": {}
}
},
"error": {
"type": "object",
"properties": {
"code": {"type": "string"},
"message": {"type": "string"}
}
},
"meta": {
"type": "object",
"properties": {
"processing_time_ms": {"type": "integer"},
"model_version": {"type": "string"}
}
}
},
"required": ["success"]
}llama.cpp включает набор готовых грамматик в директории grammars/:
| Файл | Описание |
|---|---|
json.gbnf |
Валидный JSON |
json_arr.gbnf |
JSON-массив |
list.gbnf |
Маркированный список |
c.gbnf |
Код на C |
chess.gbnf |
Шахматная нотация |
arithmetic.gbnf |
Арифметические выражения |
| Сценарий | Рекомендуемый метод |
|---|---|
| Простой JSON-ответ | response_format: {"type": "json_object"} |
| Строгая структура данных | JSON Schema с strict: true |
| Нестандартный формат | Grammar (GBNF) |
| Извлечение сущностей | JSON Schema с enum для типов |
| Да/Нет ответы | Grammar |
| Числовые ответы | JSON Schema с min/max |
Советы:
- Используйте низкую температуру (
--temp 0.1-0.3) для структурированного вывода - Добавляйте примеры в системный промпт (few-shot)
- При использовании JSON Schema всегда указывайте
requiredполя - Тестируйте грамматики на простых примерах перед продакшном
llama-cli — интерактивный интерфейс командной строки для работы с моделью в режиме диалога или однократной генерации.
| Флаг | Полная форма | Описание |
|---|---|---|
-i |
--interactive |
Интерактивный режим |
-ins |
--instruct |
Режим инструкций (автоматически подставляет шаблоны диалога) |
--color |
Подсветка текста (синий — ввод, белый — ответ) | |
-p |
--prompt |
Начальный промпт |
-f |
--file |
Файл с промптом |
-sp |
--system-prompt |
Системный промпт |
--conv-template |
Шаблон диалога (mistral, llama2, llama3, chatml, gemma и др.) | |
-r |
--reverse-prompt |
Строка для возврата управления пользователю |
--in-prefix |
Префикс перед вводом пользователя | |
--in-suffix |
Суффикс после ввода пользователя | |
-cnv |
--conversation |
Режим разговора (упрощённый интерактивный) |
--multiline-input |
Многострочный ввод | |
--simple-io |
Простой ввод-вывод без спецсимволов | |
--json-schema |
JSON Schema для структурированного вывода | |
--grammar-file |
Файл с грамматикой GBNF |
Однократная генерация:
llama-cli -m model.gguf -p "Напиши стихотворение о весне" -n 256Интерактивный режим:
llama-cli -m model.gguf -iРежим инструкций (instruct):
llama-cli -m model.gguf -i -insРежим разговора (conversation):
llama-cli -m model.gguf -cnvБазовый запуск:
llama-cli -m models/model.gguf -ngl 99 -c 4096 -n 512Интерактивный с GPU и оптимизациями:
llama-cli -m models/model.gguf -ngl 99 -c 8192 -b 512 -t 8 -tb 12 -n 2048 --temp 0.7 --repeat-penalty 1.1 --flash-attn on --mlock --color -i -insС системным промптом:
llama-cli -m models/model.gguf -ngl 99 -c 8192 --system-prompt "Ты — опытный Python-разработчик." -i -ins --colorДля Apple Silicon (оптимизация температуры):
llama-cli -m models/model.gguf -ngl 99 -c 8192 -b 128 -ub 128 -t 4 -tb 12 -n 4096 --flash-attn on --mlock --no-mmap --color -i -insС JSON Schema:
llama-cli -m models/model.gguf -ngl 99 -c 4096 -p "Извлеки данные: Иван Петров, 30 лет" --json-schema '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"}}}' -n 128С грамматикой:
llama-cli -m models/model.gguf -ngl 99 -c 4096 -p "Ответь да или нет: Земля круглая?" --grammar-file yesno.gbnf -n 8| Клавиша | Действие |
|---|---|
Enter |
Отправить сообщение |
Ctrl+C |
Прервать генерацию |
Ctrl+D |
Выйти из программы |
Запуск llama-server превращает модель в постоянно работающий микросервис, совместимый с OpenAI API. Это позволяет использовать модель из любых приложений, поддерживающих OpenAI API.
| Флаг | Полная форма | Описание | По умолчанию |
|---|---|---|---|
--host |
Адрес для прослушивания | 127.0.0.1 |
|
--port |
Порт сервера | 8080 |
|
-np |
--n-parallel |
Количество параллельных запросов (слотов) | 1 |
-cb |
--cont-batching |
Непрерывный батчинг (подмешивание новых запросов) | Выключено |
--alias |
Имя модели для API | Имя файла | |
--embedding |
Режим эмбеддингов (для RAG) | Выключено | |
--reranking |
Режим ранжирования | Выключено | |
-spf |
--system-prompt-file |
Файл с системным промптом по умолчанию | — |
--chat-template |
Шаблон чата (jinja) | Из модели | |
--slots |
Показывать информацию о слотах | Выключено | |
--slot-save-path |
Путь для сохранения состояния слотов | — | |
--log-disable |
Отключить логи | — | |
--log-format |
Формат логов | text |
|
--metrics |
Включить эндпоинт метрик | Выключено | |
-to |
--timeout |
Таймаут соединения (секунды) | 0 (без лимита) |
--api-key |
API-ключ для авторизации | — | |
--api-key-file |
Файл с API-ключами | — | |
--ssl-key-file |
Путь к SSL-ключу | — | |
--ssl-cert-file |
Путь к SSL-сертификату | — |
Базовый сервер:
llama-server -m models/model.gguf --port 8080 -n 2048Сервер с системным промптом:
llama-server -m models/model.gguf --port 8080 -ngl 99 -c 8192 --system-prompt-file system.txtПродакшн-сервер с параллельными запросами:
llama-server -m models/model.gguf --host 0.0.0.0 --port 8080 -ngl 99 -c 8192 -t 8 -tb 12 -n 4096 --flash-attn on --mlock --cont-batching --n-parallel 4 --metricsСервер для Apple Silicon (минимальный нагрев):
llama-server -m models/model.gguf --port 8080 -ngl 99 -c 8192 -b 128 -ub 128 -t 4 -tb 12 -n 4096 --flash-attn on --mlock --no-mmapСервер для RAG (эмбеддинги):
llama-server -m models/embedding-model.gguf --embedding --port 8080 -ngl 99Сервер с авторизацией:
llama-server -m models/model.gguf --port 8080 -ngl 99 --api-key "your-secret-key"| URL | Метод | Назначение |
|---|---|---|
http://localhost:8080 |
GET | Встроенный Web UI |
http://localhost:8080/health |
GET | Проверка состояния сервера |
http://localhost:8080/v1/models |
GET | Список моделей |
http://localhost:8080/v1/chat/completions |
POST | OpenAI-совместимый Chat API |
http://localhost:8080/v1/completions |
POST | OpenAI-совместимый Completion API |
http://localhost:8080/v1/embeddings |
POST | Эмбеддинги (при --embedding) |
http://localhost:8080/tokenize |
POST | Токенизация текста |
http://localhost:8080/detokenize |
POST | Детокенизация |
http://localhost:8080/slots |
GET | Информация о слотах |
http://localhost:8080/metrics |
GET | Prometheus-метрики |
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8080/v1",
api_key="sk-no-key-required"
)
# Обычный запрос с системным промптом
response = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "Ты — эксперт по Python."},
{"role": "user", "content": "Как отсортировать список словарей по ключу?"}
],
max_tokens=1024,
temperature=0.7
)
print(response.choices[0].message.content)
# Стриминг
response = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "Ты — поэт."},
{"role": "user", "content": "Напиши хокку о программировании"}
],
max_tokens=256,
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)from openai import OpenAI
import json
client = OpenAI(base_url="http://localhost:8080/v1", api_key="sk-no-key-required")
response = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "Извлекай структурированные данные."},
{"role": "user", "content": "Apple Inc. основана в 1976 году Стивом Джобсом. Штаб-квартира в Купертино."}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "company_info",
"strict": True,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"founded": {"type": "integer"},
"founder": {"type": "string"},
"headquarters": {"type": "string"}
},
"required": ["name", "founded"]
}
}
},
max_tokens=256
)
data = json.loads(response.choices[0].message.content)
print(json.dumps(data, indent=2, ensure_ascii=False))Chat Completion с системным промптом:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-model",
"messages": [
{"role": "system", "content": "Отвечай кратко, в 1-2 предложениях."},
{"role": "user", "content": "Что такое машинное обучение?"}
],
"max_tokens": 128
}'С JSON Schema:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-model",
"messages": [
{"role": "user", "content": "Москва, население 12 млн, столица России"}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "city",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"population": {"type": "integer"},
"is_capital": {"type": "boolean"}
},
"required": ["name"]
}
}
}
}'Простой JSON mode:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-model",
"messages": [
{"role": "system", "content": "Отвечай в формате JSON."},
{"role": "user", "content": "Перечисли 3 цвета"}
],
"response_format": {"type": "json_object"}
}'При запуске llama-cli или llama-server в консоль выводится информация о системе и модели:
Инициализация бэкенда:
ggml_metal_init— инициализация Metal (macOS/Apple Silicon)ggml_cuda_init— инициализация CUDA (NVIDIA)ggml_vulkan_init— инициализация Vulkan (AMD/Intel/NVIDIA)
Информация о GPU:
GPU name— название видеокартыGPU family— семейство GPUhas unified memory— наличие объединённой памяти (Apple Silicon)recommendedMaxWorkingSetSize— рекомендуемый максимальный объём памяти
Информация о модели:
llm_load_tensors— загрузка тензоров моделиllama_model_loader— информация о структуре моделиn_ctx— размер контекстаn_batch— размер батча
llama_print_timings: load time = 1234.56 ms
llama_print_timings: sample time = 12.34 ms / 100 runs
llama_print_timings: prompt eval time = 234.56 ms / 50 tokens (213.10 tokens per second)
llama_print_timings: eval time = 5678.90 ms / 100 runs (17.61 tokens per second)
llama_print_timings: total time = 6000.00 ms / 150 tokens
| Метрика | Описание |
|---|---|
| load time | Время загрузки модели в память |
| sample time | Время сэмплирования токенов |
| prompt eval time | Время обработки входного промпта |
| prompt eval tokens/s | Скорость обработки промпта |
| eval time | Время генерации ответа |
| eval tokens/s | Скорость генерации (главный показатель) |
| Скорость (t/s) | Оценка | Комментарий |
|---|---|---|
| < 5 | Медленно | Некомфортно для диалога |
| 5–8 | Приемлемо | Читать можно |
| 8–15 | Комфортно | Нормальная скорость |
| 15–30 | Быстро | Отличная отзывчивость |
| 30+ | Очень быстро | Почти мгновенно |
llama-cli -m models/model.gguf -p "Привет!" -n 256llama-cli -m models/model.gguf -ngl 99 -c 8192 -t 8 -n 2048 --temp 0.7 --flash-attn on -i -ins --colorllama-cli -m models/model.gguf -ngl 99 -c 8192 --system-prompt "Ты — эксперт по Python." -i -ins --colorllama-cli -m models/model.gguf -ngl 99 -p "Извлеки: Иван, 25 лет" --json-schema '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"}}}' -n 128 --temp 0.1llama-server -m models/model.gguf --port 8080 -n 2048llama-server -m models/model.gguf --port 8080 -ngl 99 --system-prompt-file system.txtllama-server -m models/model.gguf --host 0.0.0.0 --port 8080 -ngl 99 -c 8192 -t 8 -tb 12 -n 4096 --flash-attn on --mlock --cont-batching --n-parallel 4 --metricsllama-server -m models/model.gguf --port 8080 -ngl 99 -c 8192 -b 128 -ub 128 -t 4 -tb 12 -n 4096 --flash-attn on --mlock --no-mmapllama-server -m models/embedding-model.gguf --embedding --port 8080 -ngl 99llama-cli -m models/codellama.gguf -ngl 99 -c 16384 --system-prompt "Ты — Senior Python Developer." --temp 0.2 --flash-attn on -i -ins --colorllama-cli -m models/model.gguf -ngl 99 -c 4096 --system-prompt "Извлекай данные из текста в JSON." --json-schema-file schema.json --temp 0.1 -i --colorДиагностика: Проверьте наличие ggml_metal_init или ggml_cuda_init в логах.
Решения:
- Добавьте
-ngl 99 - Пересоберите с поддержкой GPU
Решения:
- Уменьшите контекст:
-c 4096 - Используйте Q4_K_M вместо Q8_0
- Уменьшите
-ngl(частичная загрузка на GPU) - Включите
--flash-attn on
Решения:
-b 128 -ub 128-t 4--flash-attn on
Решения:
- Укажите
--conv-template - Используйте
-i -ins - Добавьте системный промпт с инструкциями
- Для JSON: используйте
--json-schemaилиresponse_format
Решения:
- Снизьте температуру:
--temp 0.1 - Используйте
--json-schemaсstrict: true - Добавьте примеры в системный промпт
- Репозиторий: https://github.com/ggerganov/llama.cpp
- Модели GGUF: https://huggingface.co/models?library=gguf
- Грамматики: https://github.com/ggerganov/llama.cpp/tree/master/grammars
- JSON Schema Spec: https://json-schema.org/
Руководство составлено на основе официальной документации llama.cpp и практического опыта использования.