OpenAI 호환 서버

OpenAI 호환 서버 (OpenAI-Compatible Server)

vLLM을 실제 API 서버로 띄우는 가장 대표적인 방법이 바로 OpenAI 호환 서버예요. OpenAI의 Completions API와 Chat API 등을 그대로 구현해서, 기존 OpenAI 클라이언트로 vLLM 모델을 호출할 수 있어요. 이 페이지에서 서버를 띄우고 호출하는 전 과정을 살펴볼게요.

출처: vLLM 공식 문서 — serving/online_serving/openai_compatible_server

vLLM은 OpenAI의 Completions API, Chat API 등을 구현하는 HTTP 서버를 제공해요. 이 기능으로 모델을 서빙하고 HTTP 클라이언트로 상호작용할 수 있죠.

API 키 인증은 모든 엔드포인트를 보호하지 않아요. --api-key 옵션(또는 VLLM_API_KEY 환경 변수)은 /v1, /v2, /inference 경로 접두사 아래의 요청만 인증해요. 같은 HTTP 서버의 다른 엔드포인트는 인증되지 않아요. 특히 /invocations/v1 엔드포인트와 같은 추론 기능을 노출해요. vLLM을 보호하는 데 --api-key만 믿지 마세요. 보호·비보호 엔드포인트의 전체 목록과 권장 강화(예: 리버스 프록시 뒤 배포)는 API Key 인증 한계를 참고하세요.

지원되는 API (Supported APIs)

현재 지원하는 OpenAI API는 다음과 같아요.

Completions API

터미널에서 vLLM을 설치한 뒤, vllm serve 명령으로 서버를 시작할 수 있어요. (Docker 이미지도 쓸 수 있어요.)

vllm serve NousResearch/Meta-Llama-3-8B-Instruct \
  --dtype auto \
  --api-key token-abc123

서버를 호출하려면 HTTP 클라이언트를 쓰는 스크립트를 만들고, 모델에 보낼 메시지를 넣고 실행하면 돼요. 아래는 공식 OpenAI 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)

: vLLM은 OpenAI가 지원하지 않는 일부 파라미터도 지원해요 (예: top_k). 이런 파라미터는 OpenAI 클라이언트의 extra_body 파라미터로 넘길 수 있어요. 즉 top_k에 대해 extra_body={"top_k": 50}처럼요.

중요: 기본적으로 서버는 Hugging Face 모델 저장소의 generation_config.json이 있으면 이를 적용해요. 즉 일부 샘플링 파라미터의 기본값이 모델 제작자가 권장하는 값으로 덮어써질 수 있어요. 이를 비활성화하려면 서버 시작 시 --generation-config vllm을 전달하세요.

추가 파라미터 (Extra Parameters)

vLLM은 OpenAI API에 없는 파라미터 세트를 지원해요. 이를 쓰려면 OpenAI 클라이언트에서 extra parameters로 넘기거나, HTTP를 직접 호출한다면 JSON 페이로드에 직접 병합하면 돼요.

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"]},
    },
)

추가 HTTP 헤더 (Extra HTTP Headers)

X-Request-Id HTTP 요청 헤더는 --enable-request-id-headers로 활성화할 수 있어요.

completion = client.chat.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    messages=[
        {"role": "user", "content": "Classify this sentiment: vLLM is wonderful!"},
    ],
    extra_headers={
        "x-request-id": "sentiment-classification-00001",
    },
)
print(completion._request_id)

completion = client.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    prompt="A robot may not injure a human being",
    extra_headers={
        "x-request-id": "completion-test",
    },
)
print(completion._request_id)

Completions, Chat Completions, Responses API는 X-Vllm-Priority 요청 헤더도 지원해요. 값은 정수여야 하고 JSON 요청 본문의 priority 값을 덮어써요. 0이 아닌 우선순위는 서버가 우선순위 스케줄링을 사용해야 해요.

completion = client.chat.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    messages=[{"role": "user", "content": "Hello!"}],
    extra_headers={"X-Vllm-Priority": "-10"},
)

API 참조 (API Reference)

Completions API

vLLM의 Completions API는 OpenAI의 Completions API와 호환돼요. 공식 OpenAI Python 클라이언트로 상호작용할 수 있어요.

코드 예시: examples/basic/online_serving/openai_completion_client.py

추가 파라미터 (Extra parameters)

다음 샘플링 파라미터를 지원해요.

    use_beam_search: bool = False
    top_k: int | None = None
    min_p: float | None = None
    repetition_penalty: float | None = None
    length_penalty: float = 1.0
    stop_token_ids: list[int] | None = []
    include_stop_str_in_output: bool = False
    ignore_eos: bool = False
    min_tokens: int = 0
    skip_special_tokens: bool = True
    spaces_between_special_tokens: bool = True
    truncate_prompt_tokens: Annotated[int, Field(ge=-1, le=_INT64_MAX)] | None = None
    truncation_side: Literal["left", "right"] | None = Field(
        default=None,
        description=(
            "Which side to truncate from when truncate_prompt_tokens is active. "
            "'right' keeps the first N tokens. "
            "'left' keeps the last N tokens."
        ),
    )
    allowed_token_ids: list[int] | None = None
    prompt_logprobs: int | None = None
    logprob_token_ids: list[int] | None = Field(
        default=None,
        description=(
            "Specific vocab token IDs to return logprobs for at each generated "
            "position, in addition to the sampled token. More efficient than "
            "requesting the full vocab when only a small fixed label set is "
            "needed (e.g. multilabel scoring where each label corresponds to a "
            "known vocab id). When set, this explicit token selection takes "
            "precedence over the natural top-k selected by `logprobs`. "
            "Requires `logprobs` to be set."
        ),
    )
    bad_words: list[str] = Field(default_factory=list)

다음 추가 파라미터도 지원해요.

    prompt_embeds: bytes | list[bytes] | None = None
    add_special_tokens: bool = Field(
        default=True,
        description=(
            "If true (the default), special tokens (e.g. BOS) will be added to "
            "the prompt."
        ),
    )
    response_format: AnyResponseFormat | None = Field(
        default=None,
        description=(
            "Similar to chat completion, this parameter specifies the format "
            "of output. Only {'type': 'json_object'}, {'type': 'json_schema'}"
            ", {'type': 'structural_tag'}, or {'type': 'text' } is supported."
        ),
    )

더 알아보기 (Learn more)