Зачем нужен OpenAI-compatible сервер
Большинство приложений, агентов и библиотек уже умеют работать с OpenAI API: они формируют запросы к
/v1/chat/completions, передают model, messages, temperature и ожидают стандартный JSON-ответ. vLLM реализует тот же HTTP-интерфейс локально, поэтому переключение с облачного провайдера на собственную модель сводится к замене base_url и api_key — без переписывания бизнес-логики.Это полезно, когда нужно:
- Убрать зависимость от внешнего API и снизить latency.
- Запустить модель с открытыми весами (Llama, Qwen, Mistral, Gemma и 200+ других архитектур) на собственном GPU.
- Сохранить совместимость с фреймворками вроде LangChain, LlamaIndex, CrewAI или любым кодом, который использует
openaiPython-пакет.
Запуск сервера
Минимальная команда:
Bash:
vllm serve NousResearch/Meta-Llama-3-8B-Instruct \
--dtype auto \
--api-key token-abc123
Сервер поднимется на
http://localhost:8000 и будет готов принимать запросы. Флаг --dtype auto позволяет vLLM выбрать оптимальную точность на основе конфигурации модели. --api-key задаёт токен для аутентификации (подробнее об ограничениях ниже).Полезные флаги при запуске:
| Флаг | Назначение |
|---|---|
--port 8080 | Сменить порт (по умолчанию 8000) |
--host 0.0.0.0 | Слушать все интерфейсы, а не только localhost |
--tensor-parallel-size 2 | Распределить модель на несколько GPU |
--max-model-len 4096 | Ограничить максимальную длину контекста |
--gpu-memory-utilization 0.9 | Доля GPU-памяти под KV cache |
--chat-template ./tpl.jinja | Указать чат-шаблон вручную |
--generation-config vllm | Игнорировать generation_config.json из репозитория модели |
--served-model-name my-model | Задать короткое имя модели для поля model в запросах |
Последний флаг удобен: вместо длинного HuggingFace-идентификатора в запросах можно писать
"model": "my-model".Подключение через OpenAI Python-клиент
Официальный пакет
openai работает с vLLM без модификаций — достаточно указать base_url:
Python:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="token-abc123",
)
completion = client.chat.completions.create(
model="NousResearch/Meta-Llama-3-8B-Instruct",
messages=[
{"role": "user", "content": "Hello!"},
],
)
print(completion.choices[0].message)
Если при запуске сервера задан
--served-model-name my-model, то в поле model передаётся именно это имя.Для Completions API (без чат-шаблона) используется другой метод:
Python:
completion = client.completions.create(
model="NousResearch/Meta-Llama-3-8B-Instruct",
prompt="A robot may not injure a human being",
)
print(completion.choices[0].text)
Поддерживаемые эндпоинты
vLLM реализует не только Chat Completions. Полный список OpenAI-совместимых маршрутов:
| Эндпоинт | Тип модели |
|---|---|
/v1/completions | Text generation |
/v1/chat/completions | Text generation с чат-шаблоном |
/v1/chat/completions/batch | Пакетная обработка чатов |
/v1/responses | Responses API |
/v1/embeddings | Embedding-модели |
/v1/audio/transcriptions | ASR-модели |
/v1/audio/translations | ASR-модели |
Кроме того, доступны кастомные эндпоинты:
/tokenize, /detokenize, /pooling, /score, /rerank (совместим с Jina AI и Cohere), /classify.Дополнительные параметры через extra_body
vLLM поддерживает ряд параметров, которых нет в оригинальном OpenAI API. Они передаются через
extra_body:
Python:
completion = client.chat.completions.create(
model="NousResearch/Meta-Llama-3-8B-Instruct",
messages=[
{"role": "user", "content": "Classify this sentiment: vLLM is wonderful!"},
],
extra_body={"top_k": 50},
)
Среди доступных расширенных параметров для Chat Completions и Completions API:
top_k— ограничение словаря при сэмплировании.
min_p— порог вероятности для отсечения токенов.
repetition_penalty— штраф за повторения.
min_tokens— минимальное число генерируемых токенов.
ignore_eos— продолжать генерацию после EOS-токена.
stop_token_ids— список ID токенов, останавливающих генерацию.
prompt_logprobs— вернуть логвероятности для токенов промпта.
structured_outputs— принудительный формат вывода (см. ниже).
priority— приоритет запроса при priority scheduling.
repetition_detection— автоматическое прерывание при зацикливании модели.
Для Completions API дополнительно доступен
thinking_token_budget — лимит токенов для reasoning-моделей (нестрогое целое число задаёт лимит, -1 означает без ограничений).Structured outputs
vLLM умеет гарантировать формат ответа с помощью xgrammar или guidance. Пример ограничения выбора:
Python:
completion = client.chat.completions.create(
model="NousResearch/Meta-Llama-3-8B-Instruct",
messages=[
{"role": "user", "content": "Classify this sentiment: vLLM is wonderful!"},
],
extra_body={
"structured_outputs": {"choice": ["positive", "negative"]},
},
)
Также поддерживается
response_format с типами json_object, json_schema, structural_tag и text.Чат-шаблоны
Для работы
/v1/chat/completions модель должна содержать чат-шаблон (Jinja2) в конфигурации токенизатора. Большинство instruct-моделей на HuggingFace уже включают его. Если шаблон отсутствует, сервер вернёт ошибку на любой чат-запрос.Решение — передать шаблон вручную:
Bash:
vllm serve <model> --chat-template ./path-to-chat-template.jinja
Сообщество vLLM поддерживает набор готовых шаблонов в директории
examples репозитория.Некоторые модели (например,
meta-llama/Llama-Guard-3-1B) ожидают content в формате OpenAI-схемы (список объектов с type и text), а не строкой. vLLM определяет формат автоматически, но при необходимости его можно зафиксировать флагом --chat-template-content-format со значениями auto, string или openai.Поведение generation_config.json
По умолчанию vLLM применяет
generation_config.json из репозитория модели на HuggingFace. Это значит, что значения temperature, top_p и других параметров сэмплирования могут отличаться от дефолтов vLLM — они переопределяются рекомендациями автора модели.Если нужно игнорировать этот файл и использовать внутренние дефолты vLLM:
Bash:
vllm serve <model> --generation-config vllm
Аутентификация и её ограничения
Флаг
--api-key (или переменная окружения VLLM_API_KEY) защищает только эндпоинты с префиксами /v1, /v2 и /inference. Остальные маршруты того же HTTP-сервера — в частности /invocations, который предоставляет те же возможности инференса — не аутентифицируются.Полагаться исключительно на
--api-key для защиты продакшен-сервера нельзя. Рекомендуемый подход — размещать vLLM за reverse proxy (nginx, Caddy, Envoy), который контролирует доступ на сетевом уровне.Заголовки запросов
При запуске с
--enable-request-id-headers сервер начинает обрабатывать заголовок X-Request-Id:
Python:
completion = client.chat.completions.create(
model="NousResearch/Meta-Llama-3-8B-Instruct",
messages=[{"role": "user", "content": "Hello!"}],
extra_headers={"x-request-id": "req-001"},
)
print(completion._request_id)
Это удобно для трейсинга в распределённых системах. Однако при высоком QPS обработка заголовков может влиять на производительность; в таких сценариях лучше реализовывать correlation ID на уровне роутера (например, через Istio).
Также поддерживается заголовок
X-Vllm-Priority для управления приоритетом запросов при priority scheduling. Значение должно быть целым числом; ненулевые приоритеты требуют, чтобы сервер использовал priority scheduling.parallel_tool_calls в Chat Completions
Параметр
parallel_tool_calls управляет количеством tool calls в ответе. По умолчанию он установлен в true, что позволяет модели вернуть несколько tool calls за один запрос. Установка в false гарантирует, что сервер вернёт не более одного tool call.При этом даже при
parallel_tool_calls=true нет гарантии, что модель вернёт больше одного вызова — это зависит от самой модели и её способности генерировать параллельные tool calls.Типичные ошибки при подключении
Модель не отвечает на чат-запросы. Причина — отсутствие чат-шаблона. Проверьте, что модель является instruct/chat-вариантом, или передайте шаблон через
--chat-template.model в запросе не совпадает с ожидаемым. Если сервер запущен без --served-model-name, в поле model нужно передавать полный идентификатор с HuggingFace (например, NousResearch/Meta-Llama-3-8B-Instruct).Параметр
suffix в Completions API. Не поддерживается — запрос вернёт ошибку.Параметр
user в Chat Completions. Игнорируется сервером.image_url.detail в мультимодальных запросах. Не поддерживается.Проверка работоспособности
Быстрый способ убедиться, что сервер отвечает:
Bash:
curl http://localhost:8000/v1/models \
-H "Authorization: Bearer token-abc123"
Ответ содержит список доступных моделей. После этого можно отправить тестовый чат-запрос через
curl или Python-клиент и проверить, что choices[0].message.content непустой.Для интерактивной отладки доступен Swagger UI на
/docs (требует интернет-соединения для загрузки фронтенда; в air-gapped средах используйте --enable-offline-docs).
