LLM внутри периметра: первые эксперименты с GPU-серверами в закрытом контуре
Запускаем открытые языковые модели на GPU внутри корпоративной сети: оцениваем железо, изолируем от интернета и смотрим, что реально работает без облака.
Llama 2 опубликована Meta (18 июля 2023) - волна интереса к локальному деплою открытых LLM в закрытом контуре
С начала года сообщество открытых языковых моделей работает в режиме форсажа. Meta выложила Llama в феврале, за ней пошла волна дообученных вариантов - Alpaca, Vicuna, WizardLM. Каждые несколько недель на Hugging Face появляется очередная «лучшая открытая модель», и, судя по активности в профильных чатах, инженерные команды уже не просто наблюдают - они начинают ставить это дело на железо.
У нас появился повод поторопиться: два клиента из сегмента с требованиями к изоляции прямо спросили, можно ли развернуть что-то вроде LLM-ассистента без отправки данных в облако. Вопрос разумный - мы сами ещё в ноябре 2022 писали про галлюцинации и риск утечек через внешние API. И если в начале года ответ был «подождите, Open Source ещё не того уровня», то сейчас ситуация поменялась достаточно, чтобы запустить нормальный пилот.
Что мы хотели проверить
Задача звучала просто: взять GPU-сервер из существующей инфраструктуры, развернуть на нём открытую модель среднего размера и посмотреть, насколько это вообще жизнеспособно без интернета. Никаких амбиций типа «заменить ChatGPT» - просто честная оценка того, что работает, а что нет при таких ограничениях.
Три вопроса, которые интересовали в первую очередь:
- Аппаратный минимум. Сколько GPU-памяти нужно, чтобы модель не просто запустилась, а отвечала за разумное время.
- Изоляция. Как вообще выглядит установка без pip install из интернета, без Hugging Face и без докера, который тянет слои из-за рубежа.
- Качество на реальных задачах. Что конкретно можно просить у 7B или 13B параметров без тонкой настройки.
Аппаратная реальность
Сервер, с которого мы начали - машина с одной NVIDIA A100 40 GB. По меркам корпоративного парка это уже что-то, а не обычная рабочая станция.
Результаты по моделям оказались предсказуемы, но всё равно полезно зафиксировать:
- 7B в float16 - умещается в 14 GB, на A100 летит. Это рабочий вариант даже на картах поменьше - V100 32 GB или две A30.
- 13B в float16 - нужно ~26 GB, на одиночной A100 40 GB влезает с запасом. Скорость приемлемая для диалогового режима.
- 13B в 4-bit (GPTQ) - ~8-9 GB, что открывает возможность использовать потребительские карты вроде RTX 3090 или 4090. Качество падает, но не обрывается.
- 30B и выше - без нескольких топовых карт в NVLink или тензорном параллелизме это уже история для другого пилота.
Квантование через GPTQ оказалось значительно практичнее, чем мы ожидали. Просадка по качеству на типовых задачах умеренная, а выигрыш по VRAM существенный. Если парк GPU не А100, это не компромисс - это нормальный рабочий режим.
Отдельная тема - CPU offloading через llama.cpp. Запустить 7B на машине без GPU реально, но скорость генерации на чистом CPU делает использование мучительным. Как инструмент проверки «что вообще работает» - годится. Как рабочий инструмент для пользователей - нет.
Изоляция: сложнее, чем кажется
Вот тут начались сюрпризы. «Закрытый контур» в реальности означает примерно следующее: нет pip, нет apt с внешними репозиториями, нет Docker Hub, Hugging Face заблокирован или просто недоступен. При этом внутренний nexus или harbor есть не везде - кто-то держит реестр, кто-то нет.
Типичные точки боли, которые мы прошли:
Загрузка весов. Модели весят от 4 до 28 GB в зависимости от размера и квантования. Нужен отдельный процесс: скачать на машину с доступом, упаковать, перенести. Звучит просто, на практике - вопрос согласований, места и скорости передачи по внутренней сети.
Python-зависимости. transformers, accelerate, bitsandbytes, sentencepiece - и у каждой свои транзитивные зависимости. Мы пошли по пути сборки wheel-пакетов на изолированной машине с тем же дистрибутивом и переноса архива. Заняло полдня, но это разовая операция.
CUDA. Версия CUDA должна совпадать с PyTorch и с драйвером на сервере. Вот здесь мы потеряли время: первый билд собрали под CUDA 11.8, а на сервере стоял драйвер, поддерживающий только до 11.7. Банальная вещь, но в изолированном контуре каждый такой промах - отдельный цикл согласований.
llama.cpp в этом смысле заметно легче: C++ без тяжёлых Python-зависимостей, компилируется на месте, бинарник переносится. Для команд с серьёзными ограничениями на внешние пакеты это может быть более реалистичным путём, чем полный трансформерный стек.
Что получается на выходе
После нескольких дней возни у нас есть работающий инференс на изолированном сервере. Vicuna 13B на русскоязычных запросах выдаёт приличные ответы на общие технические вопросы - помочь написать SQL, объяснить stacktrace, сгенерировать заготовку Ansible-роли. На русском работает ощутимо хуже, чем на английском: модель обучалась преимущественно на английских данных, и это чувствуется.
Галлюцинации никуда не делись. В изолированном контуре модель не становится точнее - она такой же генератор вероятностного текста, что и облачный ChatGPT. Разница только в том, что данные не уходят наружу.
Задержка ответа на 13B при одном GPU - несколько секунд на короткий запрос, больше на длинный контекст. Для инструмента, которым пользуются асинхронно, это нормально. Для реального диалогового ассистента в потоке - уже ощутимо.
Где мы сейчас
Пилот показал, что технически это работает. Не идеально, но работает - и это важный результат, потому что полгода назад ответ был бы «не работает совсем».
В начале года мы ставили задачу найти два-три рабочих сценария для LLM-инструментов. Изолированный деплой в эти сценарии пока не попадает как готовый продукт - слишком много ручной работы при установке и обновлении. Но как доказательство жизнеспособности для клиентов с параноидальными требованиями к периметру - уже есть что показать.
Дальше интересно смотреть на то, как сообщество движется в сторону упрощения деплоя. Ollama, например, существенно снизила порог входа - но вопрос о том, как это собирать и переносить без интернета, остаётся открытым. Следим.
- ChatGPT анонсирован: что это значит для ИТ-команд прямо сейчас · 5 декабря 2022
- Старт 2023: три приоритета и зачем мы их фиксируем · 10 января 2023