MAATRIX / Блог / llama.cpp на сервере: частые ошибки и решения

llama.cpp на сервере: частые ошибки и решения

llama.cpp на сервере: частые ошибки и решения

MAATRIX

llama.cpp собирается из исходников, переименовывает бинарники между релизами и молча делит контекст на слоты — поэтому половина ошибок llama.cpp это не поломка, а расхождение между вашей сборкой и инструкцией, найденной в интернете. Ниже шесть слоёв, на которых всё ломается: сборка, загрузка модели, память, скорость, сервер и железо. С точными строками ошибок и командами проверки.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Сначала выясните, что у вас за сборка и как читать её лог

Первая же команда из старого мануала обычно не работает:

$ ./main -m /opt/models/qwen2.5-7b-instruct-q4_k_m.gguf -p "Привет"
bash: ./main: No such file or directory

Файл модели тут ни при чём. В сентябре 2024 года проект переименовал исполняемые файлы и перенёс их в подкаталог сборки: main стал llama-cli, serverllama-server, quantizellama-quantize, benchmarkllama-bench. Лежат они в build/bin/, а не в корне репозитория. Любая инструкция с ./main или ./server написана до переименования — остальные её советы, скорее всего, тоже устарели.

Второе — номер сборки:

$ ./build/bin/llama-server --version
version: 6412 (a3f9c1d2)
built with cc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 for x86_64-linux-gnu

Первое число — сквозной номер сборки, тот самый b6412 в тегах на GitHub. Версий вида «1.2.3» у llama.cpp нет: релизов по несколько в день, и разница в пару сотен сборок — это другие имена флагов и другой набор архитектур.

Третье — научитесь читать лог старта. Ключевые строки по порядку: llama_model_loader: loaded meta data with 30 key-value pairs and 292 tensors (файл прочитан), print_info: file format = GGUF V3, load_tensors: CPU model buffer size = 4685.30 MiB (сколько заняли веса), llama_context: n_ctx = 4096 (какое окно вам выдали на самом деле) и в конце main: server is listening on http://127.0.0.1:8080. Последней строки нет — ищите снизу вверх первую строку с error:: всё, что напечатано после неё, уже последствия.

Сборка: CURL, «Killed» в компиляторе и Illegal instruction

Сборки через make в корне репозитория больше нет: Makefile пометили устаревшим, затем удалили. Попытка собрать по старому мануалу даёт:

$ make -j 8
make: *** No targets specified and no makefile found.  Stop.

Рабочий путь — только CMake. На чистой Ubuntu 24.04 полный набор такой:

apt update
apt install -y build-essential cmake git libcurl4-openssl-dev
git clone https://github.com/ggml-org/llama.cpp /opt/llama.cpp
cmake -S /opt/llama.cpp -B /opt/llama.cpp/build -DCMAKE_BUILD_TYPE=Release
cmake --build /opt/llama.cpp/build --config Release -j 2

Адрес важен: проект переехал из ggerganov/llama.cpp в ggml-org; старая ссылка редиректится, но в скриптах держите новую.

Пропущенный libcurl. Самая частая ошибка сборки: загрузка моделей с Hugging Face по флагу -hf встроена в common и включена по умолчанию.

-- Could NOT find CURL (missing: CURL_LIBRARY CURL_INCLUDE_DIR)
CMake Error at common/CMakeLists.txt (message):
  Could NOT find CURL.  Hint: to disable this feature, set -DLLAMA_CURL=OFF

Хинт рабочий, но отключать не надо: без libcurl теряется -hf. На AlmaLinux и Rocky пакет называется libcurl-devel.

Killed внутри компилятора. Выглядит как баг проекта, а на деле это OOM killer:

c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
make[2]: *** [ggml/src/CMakeFiles/ggml-cpu.dir/build.make:90: ...ggml-cpu.cpp.o] Error 1

Каждый процесс g++ на тяжёлых файлах ggml съедает полтора-два гигабайта, а -j $(nproc) запускает их по числу ядер: на VPS с 2 ГБ четыре компилятора не помещаются. Подтверждение — dmesg -T | grep -i 'out of memory'. Лечится -j 2 или временным swap-файлом:

fallocate -l 4G /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile

Swap для сборки нормален, под саму модель — вреден, об этом ниже. После сборки снимите: swapoff /swapfile.

Старый дистрибутив. На Ubuntu 20.04 в репозиториях лежат CMake 3.16 и GCC 9 — современный llama.cpp на них не собирается. Берите Ubuntu 24.04 (CMake 3.28, GCC 13) или Debian 12 (CMake 3.25, GCC 12).

Illegal instruction (core dumped). Собралось, а при запуске процесс падает без единой строки объяснения. Опция GGML_NATIVE включена по умолчанию и добавляет -march=native: бинарник получает инструкции того процессора, на котором компилировался, и переезд на узел с другим CPU даёт падение на первой же AVX-512-инструкции. Что поддерживает машина:

lscpu | grep -o -E 'avx512[a-z0-9_]*|avx2|f16c|fma' | sort -u

Переносимая сборка задаётся явно: -DGGML_NATIVE=OFF -DGGML_AVX2=ON -DGGML_FMA=ON -DGGML_F16C=ON — на несколько процентов медленнее, зато переживает переезд.

libllama.so: cannot open shared object file. Библиотеки собираются динамическими, и в build/bin рядом с llama-server лежат libllama.so, libggml.so, libggml-base.so и libggml-cpu.so. Копируете один бинарник в /usr/local/bin — получаете:

/usr/local/bin/llama-server: error while loading shared libraries: libllama.so:
cannot open shared object file: No such file or directory

Три выхода: статическая сборка (-DBUILD_SHARED_LIBS=OFF), копирование каталога build/bin целиком либо echo /opt/llama.cpp/build/bin > /etc/ld.so.conf.d/llama.conf && ldconfig. Нюанс новых сборок: бэкенды ggml подгружаются динамически, и libggml-cpu*.so обязана лежать рядом с бинарником — без неё считать нечем.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Модель не грузится: LFS-заглушка, шарды и unknown architecture

Прежде чем разбирать флаги, проверьте сам файл. GGUF начинается с четырёх байт GGUF:

ls -lh /opt/models/model.gguf
head -c 4 /opt/models/model.gguf | xxd
# 00000000: 4747 5546                                GGUF

Заглушка Git LFS. Если вместо магии видно текст version https://git-lfs.github.com/spec/v1, а размер файла 130 байт вместо пяти гигабайт, репозиторий клонировали без git-lfs и скачали указатель. Ошибка при этом невнятная: llama_model_load: error loading model: llama_model_loader: failed to load model from /opt/models/model.gguf. Лечится apt install git-lfs && git lfs pull.

Оборванная загрузка. Файл нужного вида, но не докачан. Диагноз однозначный:

llama_model_loader: tensor 'blk.27.ffn_down.weight' data is not within the file bounds,
model is corrupted or incomplete

Не чините — качайте заново с curl -C - или wget -c и сверяйте размер.

Шарды. Модели крупнее примерно 48 ГБ выкладывают частями: Qwen2.5-72B-Instruct-Q4_K_M-00001-of-00002.gguf и так далее. В -m передают первый шард — остальные llama.cpp найдёт сам по шаблону имени, если файлы в одном каталоге. Скормите второй — получите жалобы на отсутствующие тензоры. Склеить:

./build/bin/llama-gguf-split --merge Qwen2.5-72B-Q4_K_M-00001-of-00002.gguf Qwen2.5-72B.gguf

Неизвестная архитектура. Классика при свежей модели и старой сборке:

llama_model_load: error loading model: error loading model architecture:
unknown model architecture: 'qwen3moe'
llama_model_load_from_file_impl: failed to load model

Файл не битый: поддержка каждой архитектуры добавляется отдельным патчем, и GGUF, выложенный вчера, требует сборки не старше вчерашней. Лечение — git pull и пересборка, минут десять на четырёх ядрах. Зеркальный случай — модель 2023 года в .bin или GGML v3 на свежей сборке: ругань будет на unknown (magic, version) combination. Старые форматы выброшены.

Скачивание прямо из llama.cpp. Если CURL на месте, модель можно не искать руками:

./build/bin/llama-server -hf bartowski/Qwen2.5-7B-Instruct-GGUF:Q4_K_M --port 8080

Файл ложится в ~/.cache/llama.cpp. Отказ common_download_file: curl_easy_perform() failed почти всегда означает не проблему llama.cpp, а недоступность Hugging Face с адреса сервера — типовая история для российских IP.

Память: OOM, арифметика KV-кэша и ловушка `-np`

Веса — только половина расхода. Модель на 7–8 млрд параметров в Q4_K_M занимает около пяти гигабайтов: на нашем стенде qwen2.5:7b держит в памяти 5,1 ГБ, mistral:7b — 5,0 ГБ, llama3.1:8b — 5,6 ГБ, qwen2.5:3b — 2,2 ГБ. Вторая половина — KV-кэш: 2 × n_layer × n_kv_head × head_dim × байт_на_значение на каждый токен окна. Для Llama 3.1 8B это 2 × 32 × 8 × 128 × 2 = 131 072 байта, ровно 128 КБ на токен.

Окно -cKV-кэш (f16)Итого с весами 5 ГБ
4 0960,5 ГБ~5,5 ГБ
8 1921,0 ГБ~6 ГБ
32 7684,0 ГБ~9 ГБ
131 07216,0 ГБ~21 ГБ

Отсюда главный совет: никогда не ставьте -c 0. Ноль означает «взять окно, на котором модель обучалась», у современных моделей это 131 072 токена — и сервер честно попытается выделить разом шестнадцать гигабайтов. По умолчанию llama-server берёт 4096.

Нехватка памяти проявляется тремя способами. Если аллокатор успел отработать штатно:

ggml_backend_cpu_buffer_type_alloc_buffer: failed to allocate buffer of size 17179869184
llama_kv_cache_init: failed to allocate buffer for kv cache
llama_new_context_with_model: failed to create context with model '/opt/models/model.gguf'

Если не успел — процесс исчезает без единой строки в своём логе, и искать надо в ядре:

$ dmesg -T | grep -i 'killed process'
[Fri Aug 28 11:42:07 2026] Out of memory: Killed process 1874 (llama-server)
total-vm:12034512kB, anon-rss:7812340kB, UID:1001

Третий способ самый коварный: памяти хватило за счёт mmap, и всё «работает», просто очень медленно — об этом следующий раздел.

Ловушка -np. Флаг -c задаёт общий контекст, который делится между слотами. Запуск llama-server -c 8192 -np 4 выдаёт каждому клиенту вчетверо меньше, и это видно в логе старта:

slot         init: id  0 | task -1 | new slot n_ctx_slot = 2048

Дальше пользователь присылает промпт на три тысячи токенов и получает HTTP 400:

{"error":{"code":400,"message":"the request exceeds the available context size, try increasing the context size or enable context shift","type":"exceed_context_size_error"}}

Правило: -c = нужное окно на клиента × число слотов. Хотите 8k на четверых — ставьте -c 32768 и держите под это 4 ГБ кэша.

Как сэкономить. Квантование кэша --cache-type-k q8_0 --cache-type-v q8_0 уменьшает его примерно вдвое. Две оговорки: квантованный V-кэш требует flash attention (-fa on в новых сборках, просто -fa в старых), а уровень q4_0 заметно портит длинный контекст.

--mlock. Прибивает веса к памяти и запрещает вытеснение. Требует лимита: без него в логе будет warning: failed to mlock 4096-byte buffer ... Cannot allocate memory и подсказка Try increasing RLIMIT_MEMLOCK. В юните systemd это строка LimitMEMLOCK=infinity.

«Модель загрузилась, но отвечает по слову в минуту»

Отдельный класс жалоб, и виноват в нём чаще всего не процессор.

mmap. По умолчанию llama.cpp не читает GGUF в память, а отображает его: процесс стартует мгновенно, RSS в top скромный — веса живут страницами в файловом кэше. Пока памяти больше, чем весит модель, это лучший режим; как только меньше — каждый токен обходит весь файл, и страницы читаются с диска по кругу. Признаки: процесс подолгу в состоянии D, в vmstat 1 колонка wa за пятьдесят, а bi в десятках тысяч блоков в секунду.

Диагностика — запуск с --no-mmap: модель читается в память целиком на старте и либо честно загружается, либо её убивает OOM killer на первых секундах. Быстрый понятный отказ вместо медленной загадочной работы; на сервере --no-mmap стоит держать постоянно.

Swap. Если модель не помещается, а swap включён, вместо чистого отказа вы получите перемалывание диска. Крутить vm.swappiness бесполезно: под LLM своп — не запас, а тормоз.

Потоки: -t против -tb. -t — потоки генерации, -tb — потоки обработки промпта, и путать их дорого: генерация упирается в пропускную способность памяти, обработка промпта — в арифметику процессора.

Замер на нашем стенде: 16 vCPU (8 физических ядер AMD EPYC 9554 плюс гипертреды, DDR5), qwen2.5:7b в Q4_K_M, контекст 4096, движок llama.cpp в составе Ollama 0.33.1. Три прогона, в таблице медиана; промпт мерился холодным, без кэша префикса:

ПотоковГенерация, ток/сОбработка промпта, ток/с
25,712,6
47,631,0
87,661,7
167,468,0
320,3510,9

Генерация выходит на полку уже на четырёх потоках: дальше упор в память, и ни восемь, ни шестнадцать ничего не добавляют. Обработка промпта, наоборот, растёт до восьми потоков впятеро. Вывод для этой машины — -t 4 -tb 8: генерация ничего не теряет, а длинные промпты идут вдвое быстрее, чем при -t 4 -tb 4.

Последняя строка отдельно: 32 потока на 16 vCPU дают обвал в двадцать раз — это неработоспособность. Внутри ggml каждый слой заканчивается барьером синхронизации, и фронт ждёт самый медленный поток; когда потоков вдвое больше, чем ядер, они вытесняют друг друга. Не задавайте -t больше числа доступных ядер.

Другие модели на том же стенде при 16 потоках: llama3.1:8b — 12,8 ток/с, mistral:7b — 12,1, gemma2:9b — 8,8, qwen2.5:3b — 34,1. «7B на CPU» — это не цифра, а диапазон.

llama-server: порт, API, шаблон чата и systemd

Типовой запуск со всеми обсуждавшимися флагами:

/opt/llama.cpp/build/bin/llama-server \
  -m /opt/models/qwen2.5-7b-instruct-q4_k_m.gguf \
  --host 127.0.0.1 --port 8080 \
  -c 16384 -np 2 -t 4 -tb 8 --no-mmap \
  --api-key "$LLAMA_API_KEY" --alias qwen2.5-7b

Про безопасность прямо. По умолчанию llama-server слушает 127.0.0.1:8080 и не требует никакой авторизации. Человек, у которого сервер не отвечает снаружи, меняет хост на 0.0.0.0 — и получает открытый эндпоинт генерации, который находят сканерами за часы. Правильно: оставить 127.0.0.1, наружу выпускать через Nginx с TLS, задать --api-key, порт закрыть — ufw allow 22/tcp, ufw deny 8080/tcp. Не поднимается — смотрите ss -tlnp | grep 8080: чаще всего порт занят предыдущим экземпляром.

API — не такой, как у Ollama. Вторая по частоте причина жалоб «клиент не видит модель». llama-server отдаёт нативный /completion, служебные /health, /props, /slots и OpenAI-совместимый набор: /v1/chat/completions, /v1/models, /v1/embeddings. Эндпоинтов /api/chat и /api/tags у него нет — это API Ollama, и клиент, настроенный на «Ollama URL», получит честный 404. Меняя Ollama на llama.cpp под тем же веб-интерфейсом, указывайте OpenAI-совместимый адрес http://127.0.0.1:8080/v1 и ключ из --api-key.

Проверка живости и реально применившихся параметров:

curl -s http://127.0.0.1:8080/health
# {"status":"ok"}
curl -s http://127.0.0.1:8080/props | jq '.default_generation_settings.n_ctx, .model_path'

Деталь для мониторинга: пока модель грузится, /health отвечает кодом 503 и телом {"error":{"code":503,"message":"Loading model","type":"unavailable_error"}}. Сторожевой скрипт, перезапускающий сервис по любому не-200, будет убивать сервер на сороковой секунде загрузки. Считайте 503 нормой в первую минуту.

Шаблон чата. llama.cpp берёт Jinja-шаблон из метаданных GGUF. Нет его или написан экзотично — сервер откатывается на ChatML, и модель игнорирует системный промпт или дописывает реплики за пользователя. Что применилось, видно в curl -s http://127.0.0.1:8080/props | jq -r .chat_template. Флаг --jinja включает полноценный движок шаблонов и нужен для вызова инструментов, --chat-template-file задаёт шаблон принудительно.

Юнит systemd, в котором учтены грабли из второго и четвёртого разделов:

[Unit]
Description=llama.cpp server
After=network-online.target

[Service]
User=llama
WorkingDirectory=/opt/llama.cpp
Environment=LD_LIBRARY_PATH=/opt/llama.cpp/build/bin
EnvironmentFile=/etc/llama/llama.env
ExecStart=/opt/llama.cpp/build/bin/llama-server -m /opt/models/qwen2.5-7b-instruct-q4_k_m.gguf --host 127.0.0.1 --port 8080 -c 16384 -np 2 -t 4 -tb 8 --no-mmap
Restart=on-failure
RestartSec=15
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target

LD_LIBRARY_PATH здесь — способ не собирать статически и не ловить libllama.so. RestartSec=15 не косметика: без паузы сервер, убитый по OOM на этапе загрузки, будет перезапускаться в цикле и молотить диск. В Nginx обязательны proxy_buffering off; и proxy_read_timeout 600s; — иначе потоковая выдача приедет одним куском в конце или оборвётся на середине.

Какой сервер под llama.cpp брать в MAATRIX

Сразу честно: llama.cpp в каталоге apps.maatrix.io нет — это исходный проект, который каждый собирает под свои флаги. Сервер приходит чистым, с Ubuntu 24.04 или Debian 12, и вы ставите его по второму разделу статьи, минут за пятнадцать. Нужна готовая сборка — в каталоге лежат родственные сервисы: Ollama (тот же движок llama.cpp внутри), AnythingLLM, LiteLLM, Dify, Qdrant. Они ставятся автоматически при заказе, доступы появляются в кабинете.

Честный минимум: 4 физических ядра с AVX2, 8 ГБ RAM, 40 ГБ NVMe. Помещается 7–8B в Q4_K_M: около 5 ГБ весов, 2 ГБ на контекст 16k, остальное системе, обязательно с --no-mmap. Ограничения прямо: вторую модель рядом не поднять, окно 32k не влезет, а скорость генерации будет однозначной — на нашем стенде qwen2.5:7b давала 7,6 токена в секунду.

Комфортный вариант: 8 физических ядер, 16–32 ГБ RAM, 80–160 ГБ NVMe. Свободно идёт 14B в Q4, либо 8B с окном 32k и четырьмя слотами, либо модель плюс веб-интерфейс и векторная база рядом. Про диск не забывайте: один файл 70B в Q4 — это 40+ ГБ.

Чего покупать не надо — количество vCPU: по таблице из пятого раздела шестнадцать потоков не быстрее восьми, а тридцать два медленнее в двадцать раз. Деньги вложите в объём и скорость памяти — она определяет, какая модель поместится.

Локация — Великобритания, Лондон. Локальный инференс выбирают ради того, чтобы переписка, документы и код не уходили в чужое облако, — лондонская площадка держит их в европейском правовом периметре, рядом с GDPR. До ЕС 10–25 мс, до Москвы 45–60 мс: при генерации в единицы токенов в секунду пинг не узкое место. Практическая выгода в другом — с британского адреса Hugging Face и GitHub открываются без ухищрений, и пятигигабайтный GGUF не обрывается на середине. Если аудитория целиком российская и есть требования 152-ФЗ — берите RU-локацию. Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT.

И честный потолок. Всё описанное — про CPU. Нужно больше 20–30 токенов в секунду или десяток одновременных пользователей — потоками не лечится: нужен GPU с VRAM не меньше размера модели и сборка с -DGGML_CUDA=ON, только тогда появляется смысл у -ngl 99. На CPU-сборке -ngl не выдаёт ошибку, а молча игнорируется: «поставил -ngl 99, а быстрее не стало» почти всегда означает сборку без CUDA — в логе тогда только CPU model buffer size.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

./main -m model.gguf пишет No such file or directory, хотя файл модели на месте.

Не хватает не модели, а бинарника: main переименован в llama-cli, server — в llama-server, и лежат они в build/bin/. Запускайте ./build/bin/llama-cli -m model.gguf -p "...". Инструкции старше сентября 2024 года используют старые имена, так что остальные их команды тоже стоит перепроверить.

Сборка падает на c++: fatal error: Killed signal terminated program cc1plus. Это баг llama.cpp?

Нет, это OOM killer. Каждый процесс g++ на файлах ggml берёт полтора-два гигабайта, а -j $(nproc) запускает их по числу ядер. Собирайте с -j 2 либо добавьте временный swap на 4 ГБ и снимите его после сборки. Подтверждение — dmesg -T | grep -i 'out of memory'.

Поставил -c 131072, как заявлено у модели, и сервер не стартует.

Окно оплачивается KV-кэшем: у Llama 3.1 8B это 128 КБ на токен, то есть 16 ГБ на 128k сверх 5 ГБ весов. Ставьте реальное нужное окно, при нехватке добавьте --cache-type-k q8_0 --cache-type-v q8_0 вместе с -fa on. И помните, что -c делится между слотами: с -np 4 каждому клиенту достанется четверть.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.