Большинство программ, умеющих работать с языковыми моделями, разговаривают с ними на одном диалекте — том, что задал API OpenAI. Это удобное совпадение: если поднять у себя сервер, говорящий на том же диалекте, такие программы подключатся к локальной модели, не подозревая подмены.
Именно это делает llama-server — бинарник из состава llama.cpp. Одна команда, и у вас есть эндпоинт, к которому подключается почти всё.
Не нужен он в двух случаях: если вы работаете с моделью только из терминала, и если вам достаточно Ollama, которая тоже поднимает локальный API и делает это без сборки.
#Что понадобится
- Собранная llama.cpp. Порядок сборки под разные бэкенды — в гайде по llama.cpp без магии.
- Файл модели в формате GGUF.
- Понимание, что такое OpenAI-совместимый API. Если термин новый, начните со справки о том, что это такое.
#Шаг 1. Запустить сервер
./build/bin/llama-server -m models/qwen2.5-7b-instruct-q4_k_m.gguf -ngl 99 -c 8192 --host 127.0.0.1 --port 8080 --api-key mysecret
Разбор: -m — путь к модели, -ngl 99 — все слои на видеокарту, -c 8192 — контекст, --host и --port — где слушать, --api-key — ключ, который клиент обязан предъявить.
Ключ здесь не формальность. Без него любой, кто дотянется до порта, получит доступ к вашей модели. Значение 127.0.0.1 в --host ограничивает доступ самой машиной; менять его на 0.0.0.0 стоит, только выставив ключ и понимая, кто ещё есть в вашей сети.
Полезные дополнительные флаги: --alias qwen задаёт имя, под которым модель видна клиентам (иначе они увидят путь к файлу), -np 2 поднимает два параллельных слота, -fa включает Flash Attention.
#Шаг 2. Проверить запросом
Список моделей:
curl http://127.0.0.1:8080/v1/models -H "Authorization: Bearer mysecret"
Полноценный запрос в чат:
curl -s http://127.0.0.1:8080/v1/chat/completions -H "Content-Type: application/json" -H "Authorization: Bearer mysecret" -d '{"model":"qwen","messages":[{"role":"system","content":"Отвечай по-русски кратко."},{"role":"user","content":"Что такое GGUF?"}],"temperature":0.3,"max_tokens":300}'
Ответ придёт в том же формате, что и от облачного провайдера: объект с массивом choices, внутри message с ролью и содержимым, плюс блок usage с числом токенов.
Если нужен потоковый вывод, добавьте "stream": true — сервер начнёт отдавать ответ по частям.
#Шаг 3. Понять, что поддерживается, а что нет
Совместимость не означает полное совпадение. Часть полей поддерживается, часть игнорируется, часть работает иначе. Таблица ниже описывает положение на момент написания; набор меняется от версии к версии, и --help вашей сборки точнее любой статьи.
| Поле запроса | Поддержка | Примечание |
|---|---|---|
model |
формально | сервер обслуживает одну модель, поле влияет мало |
messages |
✓ | преобразуется шаблоном чата модели |
temperature, top_p |
✓ | работают как ожидается |
max_tokens |
✓ | ограничение длины ответа |
stream |
✓ | потоковая отдача по частям |
stop |
✓ | стоп-последовательности |
seed |
✓ | воспроизводимость ответа |
presence_penalty, frequency_penalty |
✓ | штрафы за повторы |
response_format |
частично | структурированный вывод через грамматику |
tools / вызов функций |
частично | зависит от версии и шаблона модели |
n (несколько вариантов) |
ограниченно | не для всех режимов |
logprobs |
частично | набор полей отличается от облачного |
Что здесь смотреть: строки с пометкой «частично». Именно они ломают интеграции. Клиент, рассчитывающий на вызов инструментов или строгий JSON по схеме, может работать с облачным провайдером и не работать с локальным сервером — при том, что простые запросы проходят идеально.
Практический вывод: проверяйте интеграцию на том сценарии, который вам нужен, а не на «привет, как дела».
#Проверка результата
Проверка первая: сервер отвечает и модель на видеокарте. В логе запуска ищите строку о числе выгруженных слоёв. Ответ на /v1/models подтверждает, что эндпоинт живой.
Проверка вторая: клиент подключился. В настройках клиента указывается базовый адрес вида http://127.0.0.1:8080/v1 и ваш ключ. Так, например, подключается Persona: она умеет работать с любым OpenAI-совместимым эндпоинтом — порядок описан в материале о подключении ключа в Persona по шагам. Оговорка по существу: языковую модель здесь подключаете вы сами, и в конфигурации с локальным сервером переписка остаётся на вашей машине именно потому, что модель локальная; при указании ключа облачного провайдера текст запросов уходит этому провайдеру.
Проверка третья: журнал показывает приходящие запросы. Если клиент говорит «нет соединения», а в журнале сервера пусто — он стучится не туда. Если запросы видны, а клиент показывает ошибку — дело в формате, а не в сети.
#Что может пойти не так
Клиент подключается, но получает ошибку авторизации. Ключ передаётся заголовком Authorization: Bearer <ключ>. Некоторые клиенты требуют непустое значение, даже когда сервер запущен без ключа — впишите произвольную строку.
Модель отвечает бессвязно или дописывает реплики пользователя. Применяется неверный шаблон чата. Задайте его явно флагом --chat-template или проверьте, что лежит в метаданных файла модели.
Клиент не видит модель в списке. Задайте понятное имя флагом --alias: без него моделью считается путь к файлу, и часть клиентов на этом спотыкается.
Ответ обрывается. Проверьте max_tokens в запросе и контекст сервера. Если суммарная длина запроса и ответа превышает -c, сервер обрежет.
Сервер доступен из сети, хотя вы этого не хотели. Значение --host 0.0.0.0 открывает его на всех интерфейсах. Для локальной работы оставляйте 127.0.0.1.
Два клиента мешают друг другу. По умолчанию слот один, и запросы обрабатываются по очереди. Флаг -np добавляет слоты, но делит между ними контекст. Если пользователей действительно много, задача решается другим классом движка — разбор в материале о vLLM и пакетной обработке.
#Частые вопросы
#Чем llama-server отличается от API Ollama?
Ollama поднимает свой API поверх того же движка и добавляет управление моделями, автоподбор параметров и выгрузку по таймауту. llama-server даёт прямой контроль над всеми флагами запуска и обслуживает одну модель. Если вам нужен конкретный параметр, которого нет в Ollama, — это ваш инструмент.
#Можно ли обслуживать несколько моделей одновременно?
Один процесс обслуживает одну модель. Несколько моделей — несколько процессов на разных портах, при желании за общим обратным прокси. Памяти при этом потребуется на все сразу.
#Безопасно ли открыть сервер в интернет?
Прямо — нет. Даже с ключом это сервис без ограничения частоты запросов и без защиты от перебора. Если доступ нужен извне, используйте туннель или обратный прокси с полноценной авторизацией и шифрованием.
#Поддерживает ли сервер эмбеддинги?
В сборках с соответствующей поддержкой есть отдельный эндпоинт для эмбеддингов, и запускать под него имеет смысл отдельную модель — специализированную, а не ту же самую, что отвечает в чате.
#Как переключаться между локальной моделью и облачной?
На уровне клиента: меняется базовый адрес и ключ. Многие приложения позволяют держать несколько профилей и переключаться между ними — практика описана в материале о том, как переключаться между провайдерами.
#Нужен ли отдельный сервер, если модель используется одним приложением?
Не обязательно, но удобно: сервер живёт независимо от приложения, модель не перезагружается при его перезапуске, и второе приложение можно подключить к той же модели без второй копии весов в памяти.