GPU-блок и поток токенов локальной LLM на сервере клиента RTX 4090 24 GB привет как дела ? контракт подписан сегодня 17:30 qwen 32B Q4_K_M 58 ток/сек Локальный LLM RTX 4090 + llama.cpp + Qwen 32B = 3,1× быстрее Ollama ITfresh · кейс торговой компании 28 РМ · экономия 92 000 ₽/мес на OpenAI API
Стенд Qwen 2.5 32B Q4_K_M на RTX 4090 — после переезда с Ollama на llama.cpp скорость выросла с 19 до 58 ток/сек.
· 18 мин чтения · Семёнов Е.С., руководитель ITfresh

Локальный LLM на сервере клиента: Ollama vs llama.cpp, выигрыш в 3 раза

К нам обратилась торговая компания на 28 рабочих мест из ЦАО — продают промышленную химию, есть юрист, два менеджера-аналитика и финдир, который привык в ChatGPT кидать договоры с контрагентами. Им запретил это делать новый аудитор по 152-ФЗ — слишком жирные персональные данные летят к американцам. Мы за пять рабочих дней собрали им свой собственный «ChatGPT» на сервере в офисе, и в процессе переключения с Ollama на llama.cpp разогнали его в 3,1 раза. Этот кейс — пошаговый отчёт о том, как мы это сделали и где наступали на грабли.

С чем пришёл клиент и почему запретили облачный AI

Финансовый директор два года жил в мире ChatGPT Plus за 20 долларов в месяц. Бросал туда договоры, проекты писем контрагентам, варианты скриптов для 1С. Юрист увидел это случайно через плечо, скрутил в трубочку и пошёл к гендиру с распечаткой 152-ФЗ. Договор содержал ФИО, паспорта учредителей контрагента, банковские реквизиты — это полноценные персональные данные третьих лиц, которые мы не имеем права передавать в иностранную систему без отдельного согласия каждого субъекта.

Дальше последовал короткий разговор и решение: «AI нам нужен, но только свой». Аудитор по 152-ФЗ сказал чёткое: «Если вы можете показать мне сервер в этом здании, на котором обрабатываются эти запросы, и доказать, что наружу из него ничего не уходит — я подпишу заключение». Финдир позвонил мне.

До этого момента я уже разворачивал локальные LLM трижды: для юрфирмы 35 РМ, для медцентра в районе Курского вокзала и для проектного бюро на Чистых Прудах. Поэтому план работ нарисовал в первой же встрече: одна неделя, GPU-станция в их же серверной, веб-интерфейс на внутреннем порту, никакого outbound в интернет с этой машины.

Подбор железа: почему RTX 4090, а не A100 и не «облако»

Любая статья про локальные LLM в интернете начинается с фразы «вам понадобится H100 за восемь миллионов рублей». Это враньё для энтерпрайза. Малому и среднему бизнесу нужен баланс «модель толковая — железо в смете — окупаемость год».

Что я взял у этого клиента

Платформа — Supermicro SYS-740GP-TNRT в корпусе 4U. CPU — один Xeon Gold 6354 (18 ядер, 3,0 GHz). Память — 128 GB DDR4 ECC. NVMe — Samsung PM9A3 1.92 TB под систему и веса моделей. GPU — Nvidia GeForce RTX 4090 24 GB (Founders Edition). Блок питания — 1600 W титанового класса. Корпус позволяет поставить вторую такую же карту, если масштабируемся.

Сумма: 612 000 ₽ за платформу с памятью и дисками + 268 000 ₽ за GPU + 18 000 ₽ за ИБП APC Smart-UPS 1500 + НДС. Итого около 950 тысяч под ключ с настройкой. Окупаемость по чистой замене подписки на ChatGPT/Claude/GigaChat для команды из 14 человек — около 11 месяцев.

Почему не A100 и не RTX 6000 Ada

Скажу прямо: A100 80 GB сейчас на вторичке стоит 1,4-1,8 миллиона. RTX 6000 Ada 48 GB — 750-900 тысяч. Они нужны, если вам надо в одну карту запихнуть Llama 70B или Qwen 72B без квантования, либо обслуживать сотни параллельных запросов. У клиента из этого кейса в обед одновременно сидят максимум четыре человека с LLM — 4090 хватает с двукратным запасом по памяти.

Почему не облако GPU вроде Yandex DataSphere

Аргумент простой: цель проекта — увести данные из чужих рук. Yandex DataSphere — это юридически тот же «облачный API», просто в РФ. Аудитор сказал бы: «А кто гарантирует, что Yandex не сделает резервную копию модели вашего запроса для отладки?» Свой железный сервер закрывает этот вопрос за один аргумент.

Первая итерация: Ollama, 19 токенов в секунду и разочарование

Первые три дня я сделал «как все»: Ubuntu Server 24.04, драйвер Nvidia 555, Docker, контейнер с Ollama, веб-интерфейс Open WebUI. Десять команд, два часа работы, всё взлетает. Финдир заходит в браузер по адресу http://llm.local:8080, видит знакомый чат и улыбается.

Но улыбка длилась три минуты. На запросе «вычитай этот договор и предложи правки в раздел 5» Ollama выдал поток ответа со скоростью 19 токенов в секунду. На двухэкранном договоре генерация ответа заняла 1 минуту 47 секунд. Финдир сказал то, что говорят все клиенты в такой ситуации: «А ChatGPT отвечает за 8 секунд».

Что внутри Ollama притормаживает

Ollama — это обёртка над llama.cpp, написанная на Go, с менеджером моделей и сетевым API. По умолчанию она запускает движок с консервативными параметрами:

Я докрутил Ollama насколько можно: переменные окружения, кастомный Modelfile, увеличил контекст до 8192. Получил 26 ток/сек. Лучше, но всё равно не торт.

Переход на llama.cpp напрямую: 58 токенов в секунду

На третий день вечером я снёс Ollama и поставил голый llama.cpp. Скомпилировал из исходников с CUDA-поддержкой, чтобы не тащить чужие сборки и точно знать, какие флаги активны.

# Ставим зависимости
apt-get install -y build-essential cmake git pkg-config \
    libcurl4-openssl-dev nvidia-cuda-toolkit

# Клонируем и собираем с CUDA
git clone https://github.com/ggerganov/llama.cpp.git /opt/llama.cpp
cd /opt/llama.cpp
cmake -B build -DGGML_CUDA=ON -DLLAMA_CURL=ON
cmake --build build --config Release -j 18

# Проверяем, что собралось
./build/bin/llama-cli --version
./build/bin/llama-server --help | head -40

Дальше — модель. Я взял Qwen 2.5 32B Instruct в кванте Q4_K_M от unsloth, на тот момент это был лучший русскоязычный open-source вариант для технических и юридических задач. Размер файла — 19,8 GB, отлично укладывается в 24 GB видеопамяти RTX 4090 вместе с KV-cache.

# Скачиваем веса прямо из HuggingFace через llama-cli
mkdir -p /var/lib/llm/models
cd /var/lib/llm/models

# Q4_K_M от unsloth — 19,8 GB
wget https://huggingface.co/unsloth/Qwen2.5-32B-Instruct-GGUF/resolve/main/Qwen2.5-32B-Instruct-Q4_K_M.gguf

# Контрольная сумма обязательно
sha256sum Qwen2.5-32B-Instruct-Q4_K_M.gguf

Теперь самое интересное — запуск llama-server с правильными параметрами. Это та формула, которая мне дала 58 ток/сек:

/opt/llama.cpp/build/bin/llama-server \
  --model /var/lib/llm/models/Qwen2.5-32B-Instruct-Q4_K_M.gguf \
  --host 0.0.0.0 \
  --port 8081 \
  --ctx-size 16384 \
  --n-gpu-layers 65 \
  --batch-size 2048 \
  --ubatch-size 512 \
  --flash-attn \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --threads 12 \
  --threads-batch 18 \
  --parallel 4 \
  --cont-batching \
  --metrics \
  --log-format json \
  --api-key 7c4a0f...очень_длинный_ключ

Что делает каждый флаг

--n-gpu-layers 65 — выгрузить все 65 слоёв Qwen 2.5 32B в видеопамять, включая embedding. Если поставить 64 — один слой останется на CPU и скорость упадёт втрое.

--flash-attn — Flash Attention v2, экономит память KV-cache и ускоряет генерацию на 25-35% на Ada Lovelace.

--cache-type-k q8_0 --cache-type-v q8_0 — квантование KV-cache в 8 бит. Сама модель в Q4, кэш в Q8 — оптимум по памяти и точности. С таким кэшем у меня в 24 GB лезет контекст до 24K токенов с запасом.

--parallel 4 и --cont-batching — четыре одновременных запроса батчатся непрерывно, без ожидания. Это критично для офиса с несколькими пользователями.

После старта проверяю замер:

# Тест скорости
curl -X POST http://127.0.0.1:8081/v1/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer 7c4a0f..." \
  -d '{
    "model": "qwen-32b",
    "prompt": "Перепиши пункт договора простым языком: ...",
    "max_tokens": 800,
    "temperature": 0.3
  }' | jq '.usage, .timings'

Ответ: predicted_per_second: 58.4. Тот самый трёхкратный выигрыш по сравнению с Ollama на той же модели. Прогон договора, который раньше ждал 1:47, теперь идёт 34 секунды. Финдир прислал в Telegram три «огонь»-эмодзи и попросил «то же самое для бухгалтера».

Обвязка вокруг llama.cpp: веб-интерфейс, авторизация, журнал

Чистый llama-server даёт OpenAI-совместимый HTTP API, но людям нужен интерфейс. Я поставил перед ним Open WebUI в Docker, чтобы юристу и финдиру было привычно, как ChatGPT.

# Docker Compose файл /etc/llm/docker-compose.yml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: webui
    network_mode: host
    environment:
      - OPENAI_API_BASE_URL=http://127.0.0.1:8081/v1
      - OPENAI_API_KEY=7c4a0f...
      - WEBUI_AUTH=true
      - DEFAULT_MODELS=qwen-32b
      - DEFAULT_USER_ROLE=user
      - ENABLE_SIGNUP=false
      - ENABLE_OPENAI_API=true
      - ENABLE_OLLAMA_API=false
      - WEBUI_NAME=ITfresh AI
      - WEBUI_URL=https://llm.client-corp.local
    volumes:
      - /var/lib/open-webui:/app/backend/data
    restart: always

Авторизация через Active Directory

У клиента уже был AD на Windows Server 2022, который мы развернули им же годом раньше. Прикручиваю LDAP-аутентификацию в Open WebUI:

# Дополнительные переменные в docker-compose
- ENABLE_LDAP=true
- LDAP_SERVER_LABEL=corp
- LDAP_SERVER_HOST=dc01.corp.client.local
- LDAP_SERVER_PORT=389
- LDAP_USE_TLS=false
- LDAP_APP_DN=CN=svc-llm,OU=ServiceAccounts,DC=corp,DC=client,DC=local
- LDAP_APP_PASSWORD=...
- LDAP_SEARCH_BASE=OU=Sotrudniki,DC=corp,DC=client,DC=local
- LDAP_SEARCH_FILTER=(&(sAMAccountName={username})(memberOf=CN=GG_AI_Users,OU=Groups,DC=corp,DC=client,DC=local))

Доступ получают только участники группы GG_AI_Users — её наполняет администратор клиента, мы туда не лезем. Это позволяет финдиру в любой момент отозвать у уволенного сотрудника доступ к корпоративной LLM той же командой, которой он отзывает доступ к 1С.

Аудит и журналирование

Аудитор просил «доказательство, что наружу ничего не уходит». На уровне сети я закрыл outbound на этом сервере iptables-правилом — наружу можно только в локальную сеть и в зеркало пакетов Ubuntu, всё остальное ловит DROP.

# /etc/iptables/rules.v4 — выписка
-A OUTPUT -d 192.168.0.0/16 -j ACCEPT
-A OUTPUT -d 10.0.0.0/8 -j ACCEPT
-A OUTPUT -d 91.189.91.0/24 -p tcp --dport 80 -j ACCEPT
-A OUTPUT -d 91.189.91.0/24 -p tcp --dport 443 -j ACCEPT
-A OUTPUT -p udp --dport 53 -d 192.168.20.10 -j ACCEPT
-A OUTPUT -p udp --dport 53 -d 192.168.20.11 -j ACCEPT
-A OUTPUT -p udp --dport 123 -j ACCEPT
-A OUTPUT -j REJECT --reject-with icmp-host-prohibited

На уровне приложения llama-server пишет логи в JSON-формате в /var/log/llm/, плюс Open WebUI хранит все диалоги в SQLite. Я настроил Filebeat → Wazuh-аггрегатор у клиента, чтобы каждый запрос с user-id попадал в централизованный журнал. Если когда-то всплывёт вопрос «а что такого попадало в LLM», можно будет показать.

Тонкости квантования: почему Q4_K_M, а не Q5 или Q8

Эта тема всех путает. Объясню как клиенту: квантование — это сжатие весов модели с потерей точности. Чем сильнее жмёшь, тем меньше места и быстрее работает, но дурнеет ответ.

Что я тестировал

На том же сервере я погонял три кванта Qwen 2.5 32B на 30 одинаковых запросах:

Вывод по моему опыту: для офиса 30-50 человек на одной RTX 4090 — Q4_K_M это золотое сечение. Если у вас две карты или RTX 6000 Ada — берите Q5 или Q6. Если денег хватило только на 4070 Ti Super 16 GB — придётся жить на Q3 или брать модель меньше: Qwen 2.5 14B Q5_K_M туда лезет.

Imatrix-квантованные веса от unsloth

Я принципиально использую кванты от unsloth, а не «обычные» от bartowski или TheBloke. У unsloth кванты сделаны через imatrix-калибровку на лучшем датасете, и в результате Q4_K_M от unsloth даёт качество как Q5 от других сборщиков. Реальная разница на юридических текстах — два-три балла из ста по моему слепому A/B-тесту с финдиром.

Сравнение скорости: цифры со стенда

Честные замеры на сервере клиента, RTX 4090, Qwen 2.5 32B, один и тот же промпт-договор на 4500 токенов входа и 800 токенов выхода:

Ollama 0.5.4, Q4_K_M, дефолт                  19 ток/сек,  ответ 58 сек
Ollama 0.5.4, Q4_K_M, тюнинг env-vars         26 ток/сек,  ответ 41 сек
llama.cpp build 4127, Q4_K_M, голый           48 ток/сек,  ответ 22 сек
llama.cpp build 4127, Q4_K_M, +flash-attn     58 ток/сек,  ответ 18 сек
llama.cpp build 4127, Q4_K_M, +cache q8_0     58 ток/сек,  ответ 18 сек, контекст 16K
vLLM 0.6.4, AWQ, GPTQ                         52 ток/сек,  ответ 20 сек, +1 час настройки

vLLM я тоже пробовал, но он капризнее, требует AWQ/GPTQ-квантованные веса (которых нет от unsloth) и в моём окружении дал на 10% медленнее. Для серверной фермы из четырёх GPU vLLM объективно лучше за счёт PagedAttention, но для одного GPU — llama.cpp проще и быстрее.

Что мы получили в итоге

Через пять рабочих дней у клиента стоит сервер в их же серверной (этаж минус один, в районе Курского вокзала), который доступен по адресу https://llm.client-corp.local через корпоративный SSL-сертификат от внутреннего CA. Заходят 14 сотрудников с компьютеров в домене, авторизуются доменными учётками, никакой регистрации.

Аудитор приехал через две недели с проверкой — мы показали серверную, диаграмму потоков данных, выписку iptables-правил, журнал из Wazuh за прошедшие 14 дней. Подписал заключение «обработка персональных данных не вышла за периметр».

Финансово: клиент платил за ChatGPT Plus + GigaChat + ещё API-доступы суммарно около 92 000 ₽ в месяц. Теперь — 0 ₽ переменных расходов, плюс электричество на сервер ~1 800 ₽/мес. Окупаемость железа — 11 месяцев. Дальше каждый месяц чистая экономия.

По производительности: 14 пользователей пользуются комфортно, в пиковые часы (10:00-12:00 и 14:00-17:00) одновременно сидят 4-5 человек, очередь не возникает за счёт --parallel 4 --cont-batching. Если станет тесно — у меня в плане докупить вторую RTX 4090 за 270 тысяч и перейти на tensor parallelism через vLLM.

Грабли, на которые я наступил

Свежий драйвер Nvidia 565 ронял CUDA

Первый день я поставил самую свежую версию драйвера на тот момент — 565. Через десять минут работы llama-server вылетал с ошибкой CUDA error: out of memory при заведомо свободной памяти. Откатился на 555.42 — стабильно как часы. Урок: на проде не ставлю последний драйвер, беру предыдущий major-релиз.

Open WebUI пытался ходить во внешний интернет

По умолчанию Open WebUI пингует api.openai.com и hub HuggingFace для проверки обновлений. У меня iptables всё резал, и интерфейс открывался 40 секунд. Решение: переменная окружения HF_HUB_OFFLINE=1 и WEBUI_AUTH_DOMAIN=disable.

Длинные контексты — KV-cache в нативном FP16 не вмещался

Без флага --cache-type-k q8_0 при контексте 16K карта забивалась под пробку и рестартила процесс. Квантование KV-cache в Q8 уменьшает занимаемую память почти вдвое без видимой потери качества — это главный трюк для длинных диалогов.

Финдир добавил в группу всех бухгалтеров — пошли тормоза

На вторую неделю клиент сам добавил в GG_AI_Users всю бухгалтерию (восемь человек) и два менеджера. Утром пришло восемь параллельных запросов, llama-server поставил их в очередь по 4. Я докрутил --parallel 8, но скорость на одного просела до 22 ток/сек. Договорились с клиентом, что когда народу станет 25+ — берём вторую карту.

FAQ: что чаще всего спрашивают клиенты

Сколько стоит развернуть локальный LLM для офиса 30 человек?

Если у заказчика уже есть подходящий сервер с GPU — около 80-120 тысяч рублей за неделю инженерных работ под ключ. Если железо нужно покупать с нуля, основная статья — видеокарта: одна RTX 4090 24 GB обходится в 240-280 тысяч рублей, плюс серверная платформа на Xeon с 64 GB RAM и NVMe — ещё 350-400 тысяч. Итого комплект под Qwen 2.5 32B Q4 — 600-700 тысяч рублей разово, против 90-120 тысяч в месяц на API OpenAI/Anthropic при сопоставимой нагрузке.

Какую модель выбрать: Qwen, Llama, GPT-OSS или что-то ещё?

На начало мая 2026 для русскоязычных задач я ставлю Qwen 2.5 32B Instruct в кванте Q4_K_M — лучший баланс размера, скорости и качества. На английских технических задачах вровень идёт Llama 3.3 70B, но она не лезет в 24 GB видеопамяти и требует CPU-offload, что роняет скорость в 4-5 раз. GPT-OSS 20B от OpenAI хорошая, но у неё слабее русский. Qwen 3 ещё сырой, ждём стабильных весов в кванте.

Чем llama.cpp лучше Ollama, если Ollama проще?

Ollama — это обёртка над llama.cpp с сетевым API и удобным менеджером моделей, но она по умолчанию использует консервативные параметры запуска и теряет на скорости. На RTX 4090 у клиента у меня llama.cpp выдавал 58 токенов/сек, Ollama — 19. Разница в три раза при той же модели и тех же весах. Если у вас Mac Studio для прототипа — Ollama нормально, на проде с правильно подобранными параметрами всегда llama.cpp напрямую.

Безопасно ли держать LLM на своём сервере вместо облачного API?

Это вообще главная причина, по которой клиенты к нам приходят. Юристам и бухгалтерам нельзя кидать в OpenAI/GigaChat договоры с персональными данными контрагентов — это утечка по 152-ФЗ. Локальный LLM работает без интернета, веса лежат на NVMe сервера, ни один токен не покидает корпоративную сеть. Аудитор приходит — показываем сетевую диаграмму с blocked outbound на 443 у GPU-ноды, и вопросов нет.

Какая нагрузка реально вытягивается одной RTX 4090 на офис?

На Qwen 2.5 32B Q4_K_M с llama.cpp одна RTX 4090 спокойно держит 4-6 одновременных диалогов с временем ответа до 8 секунд на сложный запрос. Для офиса 28-35 человек, где LLM используют 12-15 сотрудников эпизодически в течение дня, этого хватает с большим запасом. Если нужны 20+ параллельных запросов в реальном времени или Llama 70B — берите две карты в SLI или RTX 6000 Ada с 48 GB.

Итог

Локальный LLM в 2026 году — не научная фантастика и не «нужен дата-центр». Это одна неделя работы инженера, одна RTX 4090, грамотные параметры llama.cpp и веб-интерфейс на доменной авторизации. Малому бизнесу это закрывает требования 152-ФЗ и убирает 90 000 ₽/мес подписок на чужие облака. Главное — не запускать через Ollama в дефолте, а собрать llama.cpp из исходников и подобрать кванты под свою карту.

Похожая задача в вашей компании?

Расскажите, что у вас сейчас — пришлю план работ и оценку в течение рабочего дня.

Написать в Telegram  или  +7 903 729-62-41

Семёнов Е.С., руководитель ITfresh