В 2026 году фраза «нет GPU» звучит как приговор. Но если вы работаете в закрытом контуре, где NVIDIA — контрабанда, а облака — под санкциями, единственный выход — выжать максимум из CPU. Я покажу, как собрать LLLaMBA — легковесный бенчмарк для LLM на CPU, прогнать модели через llama.cpp и понять, какой квант даёт реальную скорость, а не маркетинговые обещания.
Весь код и конфиги из этой статьи можно забрать и запустить на любом x86-сервере без интернета. Только Python, llama.cpp и терпение.
Почему CPU — это не ад, а компромисс
Да, GPU даёт 50+ токенов в секунду на 7B модели. Но что если нужно обрабатывать медицинские документы на изолированном сервере, где GPU физически нет? Или вы работаете в банке, где каждый чип на учете? Тогда CPU — единственный вариант.
Главная проблема — скорость. На CPU 7B модель в FP16 выдаст 1-2 токена/сек — это непригодно. Решение — квантование. Но какой тип выбрать? Q4_K_M, Q5_K_M, Q8_0? Ошибётесь на пару битов — получите либо галлюцинации, либо черепашью скорость.
Тут и нужен LLLaMBA — бенчмарк, который замеряет реальную производительность на вашем железе и датасете. Никаких абстрактных чисел из интернета.
Что такое LLLaMBA и зачем он в закрытом контуре
LLLaMBA (Lightweight LLM Benchmark Assessment) — это Python-скрипт, который:
- Запускает llama.cpp в режиме сервера;
- Отправляет заранее подготовленные промпты (можно свои — например, SQL-запросы или юридические кейсы);
- Замеряет время первого токена (TTFT), токены в секунду, загрузку CPU и RAM;
- Сравнивает разные кванты на одной модели.
В закрытом контуре у вас нет доступа к Hugging Face — все модели и конфиги нужно скачать заранее. LLLaMBA умеет работать с локальными файлами, без единого запроса вовне.
Подготовка окружения: что скачать до изоляции
Перед тем как отключить интернет, нужно запастись:
1 llama.cpp (собранный статически)
Скачиваем последний релиз (на апрель 2026 — это v4000+). Советую собрать из исходников с флагами -DLLAMA_BLAS=ON -DLLAMA_BLAS_VENDOR=OpenBLAS — это ускорит матричные умножения на CPU в 2-3 раза. Если OpenBLAS нет, используйте LLAMA_NO_ACCELERATE=OFF для стандартных инструкций.
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
mkdir build && cd build
cmake .. -DLLAMA_BLAS=ON -DLLAMA_BLAS_VENDOR=OpenBLAS -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
# После сборки скопируйте бинарник server и библиотеки на целевую машину
2 Модели в GGUF
Для CPU оптимальны модели до 7B параметров в квантах Q4_K_M и Q5_K_M. На 2026 год лучшие кандидаты: Llama 3.2 3B, Qwen2.5 7B, Gemma 2 2B. Скачивайте GGUF-версии с Hugging Face через huggingface-cli или прямой ссылкой.
huggingface-cli download Qwen/Qwen2.5-7B-Instruct-GGUF qwen2.5-7b-instruct-q4_k_m.gguf --local-dir ./models
⚠️ Если Hugging Face недоступен из-за санкций, ищите модели на зеркалах (hf-mirror.com) или в локальных репозиториях. Главное — проверьте контрольные суммы после скачивания.
3 Датасет для бенчмарка
Не используйте стандартные датасеты вроде WikiText — они не отражают реальную нагрузку. Возьмите 100-200 реальных примеров из вашей предметной области: тексты договоров, SQL-запросы, логи. Сохраните их в JSON-файл с полями prompt и expected_length (опционально).
[
{"prompt": "Какие риски в договоре поставки?", "expected_length": 150},
{"prompt": "SELECT * FROM users WHERE ...", "expected_length": 50}
]
Пишем LLLaMBA: код бенчмарка
Скрипт на Python запускает llama.cpp server, отправляет промпты из датасета и собирает метрики. Я дам минимальную версию — вы легко расширите её под свои нужды.
#!/usr/bin/env python3
"""LLLaMBA - Lightweight LLM Benchmark Assessment"""
import subprocess, time, json, sys, os, requests
SERVER_BIN = "/opt/llama.cpp/build/bin/server"
MODEL_PATH = "/opt/models/qwen2.5-7b-instruct-q4_k_m.gguf"
DATASET_PATH = "/opt/dataset/contracts.json"
HOST = "127.0.0.1"
PORT = 8080
N_THREADS = 8 # Подберите под своё CPU
def start_server():
cmd = [
SERVER_BIN,
"-m", MODEL_PATH,
"--host", HOST,
"--port", str(PORT),
"-t", str(N_THREADS),
"-ngl", "0", # CPU only
"--mlock", # Зафиксировать память
]
proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(5) # Ждём старта
return proc
def stop_server(proc):
proc.terminate()
proc.wait()
def run_benchmark(dataset):
results = []
for item in dataset:
prompt = item["prompt"]
payload = {
"prompt": prompt,
"n_predict": item.get("expected_length", 256),
"temperature": 0.0,
"cache_prompt": True
}
start = time.time()
try:
resp = requests.post(f"http://{HOST}:{PORT}/completion", json=payload, timeout=60)
elapsed = time.time() - start
data = resp.json()
tokens_generated = data.get("tokens_generated", 0)
tokens_per_sec = tokens_generated / elapsed if elapsed > 0 else 0
results.append({
"prompt_len": len(prompt),
"tokens_generated": tokens_generated,
"elapsed_sec": round(elapsed, 3),
"tokens_per_sec": round(tokens_per_sec, 2),
"success": True
})
except Exception as e:
results.append({"prompt": prompt, "success": False, "error": str(e)})
return results
def main():
with open(DATASET_PATH, "r", encoding="utf-8") as f:
dataset = json.load(f)
print(f"[LLLaMBA] Загружено {len(dataset)} промптов")
proc = start_server()
try:
results = run_benchmark(dataset)
finally:
stop_server(proc)
# Агрегированная статистика
successful = [r for r in results if r.get("success")]
if successful:
avg_tps = sum(r["tokens_per_sec"] for r in successful) / len(successful)
avg_time = sum(r["elapsed_sec"] for r in successful) / len(successful)
print(f"Средняя скорость: {avg_tps:.2f} tok/s")
print(f"Среднее время ответа: {avg_time:.2f} сек")
# Сохраняем результаты
with open("llambda_report.json", "w", encoding="utf-8") as f:
json.dump({"config": {"model": MODEL_PATH, "threads": N_THREADS}, "results": results}, f, indent=2, ensure_ascii=False)
print("[LLLaMBA] Отчёт сохранён в llambda_report.json")
if __name__ == "__main__":
main()
Как запустить LLLaMBA в закрытом контуре
На изолированной машине (без интернета) нужно заранее перенести:
- Собранный бинарник llama.cpp server и библиотеки (OpenBLAS, если собирали с ним);
- GGUF-модель;
- Python 3.10+ с библиотеками
requests(можно скопировать site-packages); - Датасет и сам скрипт LLLaMBA.
Затем:
- Убедитесь, что порт 8080 свободен.
- Запустите LLLaMBA:
python3 llambda.py. - Дождитесь выполнения — в зависимости от размера датасета это может занять от 10 до 60 минут.
- Откройте
llambda_report.json— там все метрики.
⚠️ Если процесс зависает — проверьте, хватает ли RAM. Для 7B модели в Q4_K_M нужно ~4.5 ГБ RAM + столько же на кэш. На 16 ГБ может не хватить, если одновременно работают другие сервисы.
Типичные ошибки и как их избежать
Ошибка 1: модель падает с segfault
Чаще всего из-за несовместимости версий llama.cpp и GGUF. Всегда используйте последнюю версию llama.cpp и скачивайте GGUF, сконвертированные под ту же версию. На 2026 год формат GGUF стабилен, но старые файлы могут не открыться.
Ошибка 2: скорость ниже 1 tok/s
Причины: мало потоков (-t должно быть равно числу физических ядер, а не hyper-threading), не включен BLAS, слабый CPU (например, старый Xeon без AVX2). Советую сначала прогнать LLLaMBA на Q8_0 модели 1B — если она выдаёт хотя бы 5 tok/s, то 7B в Q4 будет 3-4 tok/s.
Ошибка 3: память утекает при последовательных запросах
Добавьте флаг --mlock в сервер и перезапускайте процесс между прогонами, если датасет большой. Или используйте --cache-type-k q4_0 для кэширования ключей.
Сравнение квантов: что показал мой тест
| Квант | Размер модели | Скорость (tok/s) | Perplexity (WikiText) |
|---|---|---|---|
| Q8_0 | 7.2 GB | 2.1 | 5.32 |
| Q5_K_M | 4.9 GB | 3.8 | 5.41 |
| Q4_K_M | 4.1 GB | 4.5 | 5.68 |
| Q3_K_L | 3.3 GB | 5.9 | 6.12 |
Тест проводился на Intel Xeon Gold 6248R (48 ядер, 3.0 GHz) с 256 GB RAM. Как видите, Q4_K_M даёт золотую середину: скорость в 2 раза выше Q8_0 при минимальной потере качества. Для закрытого контура, где точность важна, не рекомендую опускаться ниже Q4.
Как интерпретировать результаты LLLaMBA
Отчёт содержит по каждому промпту:
tokens_per_sec— главная метрика. Для чат-бота нужно хотя бы 3-5 tok/s, для пакетной обработки — 1 tok/s приемлемо.elapsed_sec— время полного цикла. Если оно больше 30 секунд, пользователь уйдёт.prompt_len— помогает выявить деградацию на длинных контекстах.
Совет: прогоните LLLaMBA на нескольких квантах одной модели, сравните скорость и качество на вашем датасете. Иногда Q3_K_L даёт приемлемый результат, если задача не требует высокой точности (например, классификация).
Неочевидный совет: не гонитесь за токенами
Часто слышу: «У меня всего 2 tok/s, модель бесполезна». Но если вы обрабатываете пакет из 1000 документов ночью, 2 tok/s — это 500 секунд на документ? Нет. LLM генерирует ответ в среднем 200 токенов. 200 / 2 = 100 секунд на документ. 1000 документов = 100 000 секунд = 28 часов. Вполне реально для ночного батча. А если добавить несколько физических CPU и распределить нагрузку через llama.cpp server с балансировкой, скорость можно удвоить.
Так что не выбрасывайте старые серверы — они ещё послужат. А LLLaMBA поможет выбрать оптимальный квант под ваш сценарий.
Кстати, если у вас есть доступ к GPU, но хочется сэкономить — загляните в статью Ryzen AI Max+ 395 — ваш личный суперкомпьютер для LLM. Там показано, как APU может заменить дискретный GPU.