OpenAI-compatible API в vLLM: как подключать локальную модель к существующим приложениям

Зачем нужен 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 или любым кодом, который использует openai Python-пакет.

Запуск сервера​


Минимальная команда:

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/completionsText generation
/v1/chat/completionsText generation с чат-шаблоном
/v1/chat/completions/batchПакетная обработка чатов
/v1/responsesResponses API
/v1/embeddingsEmbedding-модели
/v1/audio/transcriptionsASR-модели
/v1/audio/translationsASR-модели

Кроме того, доступны кастомные эндпоинты: /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).

Источники​


 
Назад
Верх Низ