Перенос локальной LLM на другой сервер вместе с базой знаний
Локальный ИИ-стек — это не файл модели. Это модель плюс векторная база с эмбеддингами документов, плюс промпт-шаблоны и параметры RAG-пайплайна, плюс конкретная версия inference-рантайма, под которую всё это настраивалось. Если при переезде на другой сервер перенести только веса модели, а остальное поднять «как получится», ответы бота на собственных документах после переезда часто становятся хуже — и не всегда сразу понятно, почему.
Содержание
Что переносится, а что достраивается заново
Соблазн — просто скопировать папку с моделью и запустить сначала. Он обманчив: сама модель без RAG-пайплайна не знает ваших документов, а RAG-пайплайн без правильно перенесённой векторной базы либо не найдёт нужные фрагменты, либо найдёт не те. Итоговое поведение системы складывается из четырёх частей, и переносить их нужно согласованно:
- Веса модели — обычно самая тяжёлая по объёму часть. GGUF-файл модели на 7-8B параметров в квантовании Q4 весит порядка 4-5 ГБ, модель на 70B — уже 35-40 ГБ. Это не считая эмбеддинг-модели и, если используется, reranker-а.
- Векторная база с эмбеддингами — Qdrant, Chroma, Milvus или что у вас развёрнуто. В ней хранятся не только векторы, но и построенный поверх них индекс приближённого поиска (ANN).
- Конфигурация и параметры инференса — промпт-шаблоны (system prompt, шаблон сборки контекста), параметры генерации (temperature, top_p, max_tokens), параметры RAG (top-k при retrieval, размер и перекрытие чанков, порог релевантности).
- Версия inference-рантайма — Ollama, vLLM, llama.cpp или что вы используете, вместе с версией драйверов GPU, если инференс идёт на видеокарте.
Если хотя бы один пункт «поехал» — например, на новом сервере другая версия vLLM с иным поведением токенизатора — ответы будут отличаться, и вы это заметите не на тестах, а на реальных запросах пользователей.
Готовим новый сервер заранее
Ключевая ошибка — начинать перенос данных на сервер, где стек ещё не настроен. Правильный порядок обратный: сначала на новом сервере поднимается идентичное окружение, и только когда оно готово и проверено — переезжают данные.
Что нужно поднять заранее:
- ОС и ядро той же версии (Ubuntu 24.04, если так было на старом сервере — не «последняя доступная»).
- Тот же inference-рантайм и та же версия. Для Ollama —
ollama --versionна старом сервере и точное совпадение на новом. Для vLLM — версия пакета изpip show vllm, а лучше зафиксированная вrequirements.txt. - Драйверы GPU и версия CUDA — если инференс на видеокарте, разница в минорной версии CUDA иногда меняет численное поведение на границе точности (обычно незаметно, но лучше не проверять это на проде).
- СУБД векторной базы той же версии —
docker images | grep qdrantпокажет тег образа, который использовался. - Тот же движок эмбеддингов для дообработки новых документов после переезда (если вы продолжите индексировать новые файлы).
Практический совет: если на старом сервере всё развёрнуто в Docker Compose — заберите сам docker-compose.yml и .env целиком, не пересоздавайте конфиг по памяти. Это тот случай, когда «переписать заново по памяти» почти гарантированно теряет один параметр, который через месяц аукнется странным поведением.
# на старом сервере — фиксируем версии
ollama --version
docker inspect qdrant | grep -i '"Image"'
pip show vllm | grep Version
nvidia-smi --query-gpu=driver_version --format=csv
Сверьте эти же команды на новом сервере до переноса данных, а не после.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть ИИ на сервереПеренос весов модели
Если модель запущена через Ollama, веса и манифесты лежат в /usr/share/ollama/.ollama/models (или в ~/.ollama/models, в зависимости от установки). Самый предсказуемый способ — забрать эту директорию целиком, а не пересобирать модель через ollama pull заново: повторное скачивание того же тега не гарантирует побитовую идентичность файла, если в реестре модель обновилась.
# со старого сервера на новый, с докачкой при обрыве
rsync -avz --progress /usr/share/ollama/.ollama/models/ \
user@new-server:/usr/share/ollama/.ollama/models/
Для GGUF-файлов, используемых напрямую в vLLM или llama.cpp — то же самое: rsync с --progress и возможностью докачки, а не scp, который при обрыве соединения на середине 40-гигабайтного файла начинает заново. Десятки гигабайт по нестабильному каналу — это часы, а не минуты, закладывайте время заранее и не переносите модель «в последний момент перед переключением».
После копирования обязательно сверьте контрольную сумму — с моделью в полсотни гигабайт визуально «файл на месте» ничего не говорит о его целостности:
sha256sum /path/to/model.gguf # на старом сервере
sha256sum /path/to/model.gguf # на новом сервере — сравнить вручную
Перенос векторной базы с эмбеддингами
Здесь важно разделить два разных сценария. Если вы меняете саму СУБД (например, с Chroma на Qdrant) — это отдельная задача с пересчётом эмбеддингов и переиндексацией, и она сильно объёмнее переноса на другой сервер той же базы. Ниже — именно про второй случай: тот же Qdrant (или другая ваша СУБД), просто на другом железе.
Для Qdrant самый чистый способ — snapshot конкретной коллекции, а не сырое копирование файлов с работающей базой:
# создать snapshot коллекции
curl -X POST 'http://localhost:6333/collections/docs/snapshots'
# скопировать snapshot на новый сервер
scp /qdrant/snapshots/docs/*.snapshot user@new-server:/qdrant/snapshots/docs/
# восстановить на новом сервере
curl -X PUT 'http://localhost:6333/collections/docs/snapshots/recover' \
-H 'Content-Type: application/json' \
-d '{"location": "file:///qdrant/snapshots/docs/docs-snapshot.snapshot"}'
Если снапшоты не настроены и база небольшая, можно остановить сервис и скопировать директорию с данными напрямую — но именно остановить, не копировать «на живую»: файлы индекса могут дописываться во время копирования, и вы получите повреждённую копию, которая при этом откроется без явной ошибки.
Отдельно — про схему коллекции и метаданные (payload). Если в вашем RAG-пайплайне в payload хранятся источник документа, номер страницы, дата индексации — они переносятся вместе со snapshot-ом автоматически, но если у вас отдельный слой метаданных в другой БД (Postgres, SQLite) — не забудьте перенести и его, иначе ссылки на источники в ответах бота начнут указывать в никуда.
Конфигурация и параметры, которые легко забыть
Веса модели и векторную базу переносят почти всегда — это очевидно большие и важные части. А вот конфигурацию часто воссоздают по памяти, и именно тут теряются детали, которые незаметно меняют качество ответов:
| Параметр | Где искать на старом сервере | Почему важен |
|---|---|---|
| System prompt / шаблон сборки контекста | код приложения или конфиг AnythingLLM/своего пайплайна | меняет тон и структуру ответа |
| top-k при retrieval | конфиг RAG-пайплайна | сколько чанков подмешивается в контекст |
| chunk size / overlap | скрипт индексации | как документ был нарезан при индексации |
| temperature, top_p, max_tokens | параметры вызова модели | детерминированность и длина ответа |
| порог релевантности (similarity threshold) | конфиг retrieval | отсекает ли система нерелевантные чанки |
| embedding-модель и её версия | конфиг индексации | должна совпадать с той, которой строился индекс |
Последний пункт — частая ловушка: если для новых документов на новом сервере вы случайно возьмёте другую версию embedding-модели (даже минорное обновление той же модели), новые векторы окажутся в другом пространстве, чем старые в перенесённой базе, и поиск по смешанному индексу станет непредсказуемым. Модель эмбеддингов должна быть зафиксирована так же строго, как и модель генерации.
Тестирование на новом сервере до переключения трафика
Это тот шаг, который чаще всего пропускают под давлением сроков — а он и есть главная защита от «тихой» деградации качества. Если при первоначальной настройке RAG-системы у вас был набор тестовых запросов (а он должен был быть, если её настраивали осознанно) — прогоните ровно тот же набор на новом сервере и сравните ответы с эталонными построчно.
# простой скрипт прогона тестового набора и сохранения ответов
while IFS= read -r query; do
echo "=== $query ===" >> results_new.txt
curl -s http://localhost:8000/v1/chat/completions \
-d "{\"messages\":[{\"role\":\"user\",\"content\":\"$query\"}]}" \
>> results_new.txt
done < test_queries.txt
diff results_old.txt results_new.txt
Точное текстовое совпадение при генеративной модели — не самоцель (небольшая вариативность формулировок нормальна), но структура ответа, использованные источники и фактическая корректность должны совпадать. Если на одни и те же вопросы система начала подтягивать другие документы или отвечать заметно короче/длиннее — где-то разошлась конфигурация retrieval, а не «модели просто так работают».
Отдельно стоит специфичная и не всегда очевидная проблема: если векторная база использует индекс приближённого поиска (HNSW у Qdrant, IVF у других СУБД), после переноса файл индекса может «доехать» физически целым, но с повреждённой внутренней структурой — из-за неудачного момента копирования или несовпадения версии формата индекса между старой и новой версией СУБД. Внешне это не выглядит как ошибка: коллекция открывается, запросы отрабатывают, просто выдают не совсем те результаты, что раньше, или не все релевантные документы. Поэтому «база скопировалась» — это не то же самое, что «поиск работает так же». Проверяйте не факт наличия данных, а конкретные результаты поиска на контрольных запросах, желательно сравнивая топ-5 найденных чанков (а не только финальный ответ модели, который может смазать разницу).
Переключение трафика и путь отката
Только после того как тестовый набор дал совпадающие по качеству ответы, имеет смысл переключать реальный трафик. Делать это лучше не одномоментной заменой DNS-записи с TTL в час, а с возможностью быстро откатиться:
- Держите старый сервер работающим ещё 1-2 дня после переключения — не выключайте и не удаляйте данные сразу.
- Если трафик идёт через reverse proxy — переключайте upstream в его конфиге (это секунды), а не DNS (это часы из-за кэширования резолверов).
- Логируйте на новом сервере первые запросы реальных пользователей отдельно, чтобы можно было быстро найти запрос, на который ответ оказался хуже, чем ожидалось.
- Только когда новый сервер отработал под реальной нагрузкой хотя бы несколько дней без нареканий — можно демонтировать старый.
Если у вас есть отдельный узел для инференса под GPU, важно заранее убедиться, что сервер под инференс LLM с нужной видеокартой уже развёрнут и прогрет до момента переключения, а не поднимается в спешке в день переезда.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть ИИ на сервереНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли перенести модель через ollama pull заново на новом сервере вместо копирования файлов?
Можно, если вам не важна побитовая идентичность файла и тег в реестре не менялся с момента первого скачивания. Но это лишний трафик и время, а гарантии совпадения меньше, чем при прямом копировании директории с моделью.
Нужно ли выключать сервис векторной базы перед переносом файлов?
Если вы копируете «на живую» без snapshot-механизма — да, обязательно. Копирование файлов данных работающей СУБД без остановки или встроенного snapshot почти гарантированно даёт повреждённую копию.
Что делать, если после переноса ответы бота стали чуть другими, но не хуже?
Небольшая вариативность формулировок при той же температуре генерации — это нормально для LLM, если она не детерминирована явно (например, temperature > 0). Тревожный признак — не другая формулировка, а другой набор источников или фактическая ошибка там, где раньше её не было.
Сколько времени закладывать на перенос модели весом 40+ ГБ?
Зависит целиком от канала между серверами: закладывайте с запасом, тестируйте скорость передачи заранее небольшим файлом и не назначайте окно переключения трафика до того, как перенос данных фактически завершён и проверена контрольная сумма.
Обязательно ли совпадение версии inference-рантайма на старом и новом сервере?
Строго обязательно для воспроизводимого поведения. Разные версии одного и того же рантайма иногда меняют детали токенизации, обработку системного промпта или дефолтные параметры сэмплирования — незаметно для разработчика, но заметно в ответах.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →