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 (
/v1/completions)- 텍스트 생성 모델에만 적용.
- 참고:
suffix파라미터는 지원하지 않아요.
- Chat Completions API (
/v1/chat/completions)- chat template이 있는 텍스트 생성 모델에만 적용.
- 참고:
user파라미터는 무시돼요. - 참고:
parallel_tool_calls를false로 설정하면 요청당 도구 호출 0~1개를 반환해요.true(기본)로 설정하면 여러 도구 호출을 반환할 수 있어요.true여도 여러 호출 반환이 보장되지는 않아요(모델 의존적).
- Chat Completions batch API (
/v1/chat/completions/batch) - Responses API (
/v1/responses,/v1/responses/{response_id},/v1/responses/{response_id}/cancel)- 텍스트 생성 모델에만 적용.
- Embeddings API (
/v1/embeddings)- 임베딩 모델에만 적용.
- Transcriptions API (
/v1/audio/transcriptions) - Translation API (
/v1/audio/translations)
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."
),
)