Гайды

llama.cpp server: свой OpenAI-совместимый эндпоинт

Одна команда поднимает локальный эндпоинт, к которому подключается любой клиент, ожидающий API OpenAI. Пример запроса и таблица полей, которые действительно поддерживаются.

Большинство программ, умеющих работать с языковыми моделями, разговаривают с ними на одном диалекте — том, что задал API OpenAI. Это удобное совпадение: если поднять у себя сервер, говорящий на том же диалекте, такие программы подключатся к локальной модели, не подозревая подмены.

Именно это делает llama-server — бинарник из состава llama.cpp. Одна команда, и у вас есть эндпоинт, к которому подключается почти всё.

Не нужен он в двух случаях: если вы работаете с моделью только из терминала, и если вам достаточно Ollama, которая тоже поднимает локальный 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, — это ваш инструмент.

#Можно ли обслуживать несколько моделей одновременно?

Один процесс обслуживает одну модель. Несколько моделей — несколько процессов на разных портах, при желании за общим обратным прокси. Памяти при этом потребуется на все сразу.

#Безопасно ли открыть сервер в интернет?

Прямо — нет. Даже с ключом это сервис без ограничения частоты запросов и без защиты от перебора. Если доступ нужен извне, используйте туннель или обратный прокси с полноценной авторизацией и шифрованием.

#Поддерживает ли сервер эмбеддинги?

В сборках с соответствующей поддержкой есть отдельный эндпоинт для эмбеддингов, и запускать под него имеет смысл отдельную модель — специализированную, а не ту же самую, что отвечает в чате.

#Как переключаться между локальной моделью и облачной?

На уровне клиента: меняется базовый адрес и ключ. Многие приложения позволяют держать несколько профилей и переключаться между ними — практика описана в материале о том, как переключаться между провайдерами.

#Нужен ли отдельный сервер, если модель используется одним приложением?

Не обязательно, но удобно: сервер живёт независимо от приложения, модель не перезагружается при его перезапуске, и второе приложение можно подключить к той же модели без второй копии весов в памяти.

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт