# llama.cpp: несколько моделей в одном сервере через router

Источник: https://modelium.tech/zhurnal/llama-cpp-router-neskolko-modeley/

В llama.cpp v0.5.0 `llama-server` без выбранного файла модели работает как router: он показывает доступные модели и отправляет запрос нужному экземпляру по полю `model`. Чтобы наглядно проверить переключение, положите два проверенных GGUF-файла в каталог и задайте `--models-max 1`: после последовательных запросов к двум моделям сверяйте статусы в `/models` и логи. Это не запуск двух моделей одновременно и не доказательство, что вся память сразу вернулась операционной системе.

**Границы проверки.** Ниже — процедура по документации стабильной `v0.5.0` от 23 сентября 2026 года с закреплённой ревизией исходников. Modelium не запускал бинарник или модели и не измерял скорость, RAM/VRAM либо безопасность. Router работает с несколькими *экземплярами модели на одном сервере*, а не распределяет вычисления между компьютерами: для RPC есть [отдельный экспериментальный разбор](/zhurnal/llama-cpp-rpc-neskolko-kompyuterov/). [s1](#src-s1) [s5](#src-s5) [s6](#src-s6)

## Когда нужен router, а когда обычный сервер

Обычный `llama-server -m /путь/к/model.gguf` обслуживает выбранный GGUF. Router запускается без `-m`: основной процесс предоставляет список доступных моделей, поднимает нужный экземпляр и пересылает запрос в него. Для POST к `/v1/chat/completions` выбор делается по JSON-полю `model`; для некоторых GET-эндпоинтов — через параметр `?model=...`. Ключ в том, чтобы брать *точный ID* из `/models`, а не угадывать имя файла в API. [s1](#src-s1) [s4](#src-s4)

Эта схема полезна, когда одной локальной точке API нужно попеременно обслуживать, например, два проверенных текстовых GGUF для разных задач. Она не превращает один компьютер в кластер и не делает несовместимую модель работоспособной. Если достаточно одного файла и нет задачи переключения, начните с [обычного гайда llama.cpp](/zhurnal/llama-cpp/). Если нужен второй физический компьютер, router не заменяет RPC. [s1](#src-s1) [s4](#src-s4)

## Что подготовить для двух моделей

Нужны `git`, CMake и компилятор для исходной сборки, `curl` и `jq` для диагностических примеров, место под два совместимых текстовых GGUF-файла и ресурсы для запуска *хотя бы одного* из них. Совместимость, происхождение, лицензию и условия каждого файла проверяйте по первоисточнику модели. Здесь нет универсального минимума RAM/VRAM: вес GGUF не равен всему потреблению памяти, которое зависит также от выбранного контекста и KV-кэша. Modelium не проверял конкретное железо. [s3](#src-s3) [s4](#src-s4)

В примере два ваших файла лежат в `$HOME/models`, по одному GGUF в корне каталога. Если модель состоит из нескольких частей либо требует мультимодальный projector, документация размещает относящиеся к ней файлы в отдельном подкаталоге. Не используйте здесь случайно скачанные веса из чужого репозитория; политика безопасности рекомендует проверять происхождение и изолировать недоверенные модели. [s1](#src-s1) [s5](#src-s5)

## Как запустить router локально

Соберите стабильную ревизию, на которую опирается материал. Команды CMake следуют официальному CPU-пути; если нужен GPU, его backend, toolkit и драйвер требуют отдельной проверки. Никакого GPU-ускорения эти строки сами по себе не обещают. [s3](#src-s3)

git clone https://github.com/ggml-org/llama.cpp.gitcd llama.cppgit checkout 7fe450e19305b828c199d602c23a8337aaa1f03bcmake -B buildcmake --build build --config Release

Создайте каталог и *самостоятельно* положите туда два доверенных текстовых GGUF; это не команда на загрузку весов. Сначала убедитесь, что каждая модель по отдельности даёт ответ через обычный `llama-server -m`, и только затем сравнивайте переключение. В данном руководстве имена моделей и их объём намеренно не выдуманы. [s1](#src-s1) [s4](#src-s4)

mkdir -p "$HOME/models"./build/bin/llama-server --models-dir "$HOME/models" --models-max 1 --host 127.0.0.1 --port 8080

Команду сервера держите в отдельном терминале. `--models-max 1` ограничивает число одновременно работающих экземпляров для наглядной проверки вытеснения; штатное значение в этой ревизии — 4, `0` снимает ограничение. Автозагрузка по обращению включена по умолчанию. Она не означает, что две тяжёлые модели одновременно поместятся в ваше устройство: для этого опыта достаточно доступной памяти для каждой модели по отдельности, а загрузка следующей может потребовать времени. [s1](#src-s1) [s2](#src-s2)

Не заменяйте `127.0.0.1` на публичный адрес ради удалённого клиента. Документация указывает loopback по умолчанию, а политика безопасности исключает router из поддерживаемых сценариев для недоверенных сетей. Даже наличие `--api-key` само по себе не делает такой контур безопасным. [s1](#src-s1) [s5](#src-s5)

## Как увидеть ID и выбрать модель в запросе

В другом терминале запросите список. Должно быть как минимум две записи; их `id` и `status.value` смотрите в выводе, а не в названии файла на диске. Если список пуст, проверьте содержимое каталога, формат GGUF и логи router; при добавлении файлов документация рекомендует перезапустить сервер или обновить список через `/models?reload=1`. [s1](#src-s1) [s4](#src-s4)

curl -fsS http://127.0.0.1:8080/models | jq -r '.data[] | [.id, .status.value] | @tsv'

Для следующей проверки вручную скопируйте **два разных ID из этого списка** в переменные `MODEL_A` и `MODEL_B`. Ниже это маркеры для ваших реальных ID, а не заявка на существование моделей с такими именами. `jq -n` создаёт JSON корректно даже если ID содержит кавычки или пробелы. Промпт для учебного теста без чувствительных данных; содержимое ответа зависит от выбранных моделей. [s1](#src-s1) [s5](#src-s5)

MODEL_A='вставьте-первый-id-из-models'MODEL_B='вставьте-второй-id-из-models'jq -n --arg m "$MODEL_A" '{model:$m,messages:[{role:"user",content:"Ответь одним словом: тест"}],stream:false}' \  | curl -fsS http://127.0.0.1:8080/v1/chat/completions -H 'Content-Type: application/json' -d @- \  | jq '{model,choices,error}'curl -fsS http://127.0.0.1:8080/models | jq -r '.data[] | [.id, .status.value] | @tsv'

Повторите команду, заменив `"$MODEL_A"` на `"$MODEL_B"`, затем ещё раз запросите `/models`. Проверяемый признак при лимите в один слот: после завершённого ответа второй модели её статус становится `loaded`, а первая переходит в `unloaded` (с учётом времени асинхронной смены). Читайте также лог `llama-server`: код планировщика вытесняет **не занятую другим запросом** модель с самым давним временем последнего использования. Если запрос A ещё идёт, scheduler ждёт освобождения слота, а не убивает активную генерацию ради B. Это ожидаемое поведение по исходникам, **не** результат прогона Modelium. [s1](#src-s1) [s2](#src-s2)

После B вновь запросите A и сравните статусы/логи. Тогда увидите именно переключение A → B → A, а не просто два ID в списке. Загрузка после вытеснения может давать задержку первого ответа; скорость и расход памяти оцените на собственном железе, не по размерам файлов. При необходимости явного управления документация описывает `POST /models/load` и `POST /models/unload`; автозагрузку можно отключить флагом `--no-models-autoload`, но тогда клиент сам отвечает за загрузку. [s1](#src-s1) [s2](#src-s2)

## Если сервер не переключается

- **Одна модель в списке.** Проверьте, что в `--models-dir` находятся именно доступные GGUF, второй файл не скрыт неверной структурой каталога, и вызовите `/models?reload=1` или перезапустите router. Для multipart или multimodal GGUF нужен каталог на модель. [s1](#src-s1)

- **Ошибка загрузки второй.** Посмотрите `status.failed` и `exit_code` в `/models`, затем логи процесса. Файл, успешно видимый в списке, ещё не доказывает корректную загрузку или достаточность памяти. Вернитесь к отдельному запуску каждой модели и [выбору GGUF](/zhurnal/gguf-i-kvantovanie/). [s1](#src-s1) [s4](#src-s4)

- **Обе модели значатся **`**loaded**`**.** Убедитесь, что действительно запущен этот процесс с `--models-max 1`, а не оставленный сервер с лимитом по умолчанию 4; сверяйте адрес и порт. Статус `loaded` описывает экземпляры, а не байты, возвращённые ОС. [s1](#src-s1) [s2](#src-s2)

- **Второй запрос ждёт.** При занятом единственном экземпляре scheduler не выбирает его для вытеснения. Дождитесь конца первого запроса, затем повторите проверку; не повышайте лимит вслепую без замера доступной памяти. [s2](#src-s2)

- **Есть ответ, но нет уверенности в выборе.** Проверьте `model` в отправленном JSON, поле `model` в ответе и статусы `/models`; осмысленность текста не доказывает, что использован нужный файл. [s1](#src-s1)

Для завершения опыта остановите сервер в его терминале и не передавайте туда рабочие документы до отдельного анализа угроз. Основной следующий шаг — [убедиться, что выбранная модель устойчиво работает в обычном локальном `llama.cpp`](/zhurnal/llama-cpp/), а потом повторить тест A → B → A с собственными файлами и сохранёнными логами. [s1](#src-s1) [s5](#src-s5)

## Источники

1. [llama.cpp v0.5.0 — server README, router и API](https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/tools/server/README.md) — получено 2026-09-28
2. [llama.cpp v0.5.0 — server-models.cpp, LRU scheduler](https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/tools/server/server-models.cpp) — получено 2026-09-28
3. [llama.cpp v0.5.0 — build guide](https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/docs/build.md) — получено 2026-09-28
4. [llama.cpp v0.5.0 — working with models](https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/docs/models.md) — получено 2026-09-28
5. [llama.cpp v0.5.0 — security policy](https://github.com/ggml-org/llama.cpp/blob/7fe450e19305b828c199d602c23a8337aaa1f03b/SECURITY.md) — получено 2026-09-28
6. [llama.cpp — стабильный релиз v0.5.0](https://github.com/ggml-org/llama.cpp/releases/tag/v0.5.0) — получено 2026-09-28
