Documents
Home>Documents>AI>Inference

vLLM 완전 입문 — 설치부터 OpenAI 호환 API 서빙까지 한 번에

13 min readMay 29, 2026May 29, 2026

vLLM은 PagedAttention 알고리즘을 기반으로 GPU 메모리를 효율적으로 관리하는 LLM 추론 서버다. vllm serve 한 줄로 OpenAI 호환 REST API를 즉시 노출할 수 있어, 기존 OpenAI SDK 기반 코드를 그대로 두고 엔드포인트만 바꿔 로컬 LLM 서빙으로 전환할 수 있다. 이 글은 설치부터 첫 응답 수신까지의 흐름을 단계별로 정리한 것이다.


vLLM이란 무엇인가 — 왜 쓰는가

vLLM의 핵심은 PagedAttention(Kwon et al., 2023)이다. 운영체제의 가상 메모리·페이징 개념을 KV 캐시 관리에 도입한 알고리즘으로, 기존 LLM 서빙 시스템이 KV 캐시의 60~80%를 낭비하는 문제를 해결한다. PagedAttention은 이 낭비를 4% 미만으로 줄이고, 동일한 GPU에서 HuggingFace Transformers 대비 최대 24배 높은 처리량을 달성한다.

다음 상황에서 vLLM이 적합하다.

  • 동시 요청이 많은 API 서버: 여러 사용자의 요청을 배치로 처리해 GPU 활용률을 극대화한다.
  • 기존 OpenAI API 기반 코드베이스: base_url만 바꾸면 클라이언트 코드 변경이 없다.
  • RAG 파이프라인: 임베딩 생성과 텍스트 생성을 동일한 서버에서 처리해 인프라를 단순화할 수 있다.
  • 단일 서버에서 채팅·임베딩·리랭킹 모델 혼합 서빙: 멀티태스크 구성이 가능하다.

설치 환경 준비 (CUDA, Python, pip/Docker)

최소 요건

  • Python 3.10–3.13
  • Linux (Windows는 WSL2 권장)
  • NVIDIA GPU compute capability 7.5 이상 (T4, RTX 20xx, A100, L4, H100 등)

pip 설치

기본 설치는 CUDA 12.9 대상으로 사전 빌드된 휠을 사용한다.

pip install vllm

다른 CUDA 버전을 사용하는 경우 --extra-index-url로 해당 버전 휠을 지정한다.

CUDA 버전pip 명령어
12.9 (기본)pip install vllm
12.8pip install vllm --extra-index-url https://download.pytorch.org/whl/cu128
13.0pip install vllm --extra-index-url https://download.pytorch.org/whl/cu130

Docker 이미지

Docker 환경에서는 공식 이미지를 사용하는 것이 가장 간단하다. vllm/vllm-openai:latest는 NVIDIA CUDA 기반이다.

docker run --runtime nvidia --gpus all \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    -p 8000:8000 \
    vllm/vllm-openai:latest \
    --model Qwen/Qwen3-4B

AMD ROCm 환경이라면 vllm/vllm-openai-rocm:latest로 교체한다.

모델 크기별 최소 GPU 메모리 요건

BF16 기준으로 파라미터 수 × 2바이트가 가중치 크기이며, KV 캐시까지 감안하면 실제로는 아래 수치 이상이 필요하다.

모델 파라미터최소 VRAM (BF16 기준)GPU 예시
~4B10 GBRTX 3090, A10
~8B18 GBA100 40GB, L40
~14B30 GBA100 80GB
~32B70 GBH100, H200
~70B단일 GPU 불가 (멀티 GPU)H100 × 2 이상

첫 번째 모델 서빙 — vllm serve 기본 사용법

Qwen3-4B를 예시로 서버를 올리는 기본 명령어다.

vllm serve Qwen/Qwen3-4B \
  --dtype bfloat16 \
  --max-model-len 32768 \
  --port 8000

정상 기동되면 로그 마지막에 다음 줄이 나온다.

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

핵심 인자

--dtype

모델 가중치의 데이터 타입이다. 최신 GPU (A100, H100, H200) 에서는 bfloat16이 기본 추천값이다. T4처럼 bfloat16을 지원하지 않는 구형 GPU는 float16을 사용한다. auto로 설정하면 vLLM이 GPU에 맞춰 자동으로 선택한다.

--max-model-len

처리 가능한 최대 토큰 길이다. 이 값이 클수록 KV 캐시 예약량이 늘어 VRAM 사용량이 증가한다. 모델이 지원하는 최댓값 이하로, 실제 사용 패턴에 맞게 낮추면 메모리를 아낄 수 있다. Qwen3-4B는 최대 128K를 지원하지만 실무에서 32K면 대부분의 태스크에 충분하다.

--gpu-memory-utilization

GPU VRAM 중 vLLM이 사용할 비율이다. 기본값 0.9. 같은 GPU에 여러 프로세스를 올릴 때는 이 값을 낮춰 VRAM을 나눠 쓴다.

--served-model-name

API 요청 시 사용할 모델 이름 별칭이다. 지정하지 않으면 모델 경로가 그대로 이름이 된다. 로컬 경로로 서빙할 때 클라이언트에서 간결한 이름으로 호출하고 싶을 때 유용하다.

vllm serve /data/models/Qwen3-4B \
  --served-model-name qwen3-4b \
  --dtype bfloat16 \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.9

멀티 GPU 환경에서는 --tensor-parallel-size를 GPU 수로 지정한다. GPU 2장이면 --tensor-parallel-size 2를 추가한다.


OpenAI 호환 API 클라이언트 호출

vLLM 서버는 /v1/chat/completions 엔드포인트를 OpenAI API와 동일한 형식으로 제공한다. 세 가지 방식으로 호출하는 예시를 정리했다.

curl

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-4B",
    "messages": [
      {"role": "user", "content": "vLLM을 한 문장으로 설명해줘"}
    ]
  }'

OpenAI Python SDK

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="dummy"  # 기본 설정에서 인증이 없으므로 임의 값을 사용한다
)

response = client.chat.completions.create(
    model="Qwen/Qwen3-4B",
    messages=[{"role": "user", "content": "vLLM을 한 문장으로 설명해줘"}]
)
print(response.choices[0].message.content)

LangChain OpenAI 래퍼

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="Qwen/Qwen3-4B",
    openai_api_base="http://localhost:8000/v1",
    openai_api_key="dummy"
)

response = llm.invoke("vLLM을 한 문장으로 설명해줘")
print(response.content)

세 방식 모두 서버 주소와 모델 이름만 맞추면 바로 동작한다. 기존 OpenAI API를 쓰던 코드라면 base_url(또는 openai_api_base) 한 줄만 교체하면 된다.


임베딩 모델 함께 서빙하기

vLLM은 채팅 LLM 외에 임베딩 모델도 동일한 vllm serve 명령어로 서빙한다. 임베딩 전용 모델은 vLLM이 자동으로 감지하지만, LLM을 임베딩 용도로 사용하는 경우 --task embed 옵션을 명시한다.

vllm serve intfloat/multilingual-e5-large-instruct \
  --task embed \
  --port 8001

서버가 올라오면 /v1/embeddings 엔드포인트로 벡터를 얻을 수 있다.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8001/v1", api_key="dummy")

response = client.embeddings.create(
    model="intfloat/multilingual-e5-large-instruct",
    input=["RAG 파이프라인 첫 번째 문장", "비교할 두 번째 문장"]
)

print(response.data[0].embedding[:5])  # 첫 번째 문장의 임베딩 앞 5개 차원

LangChain에서 임베딩 서버를 연결하는 방법도 동일하다.

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(
    model="intfloat/multilingual-e5-large-instruct",
    openai_api_base="http://localhost:8001/v1",
    openai_api_key="dummy"
)

vector = embeddings.embed_query("검색할 문장을 넣는다")

채팅 LLM과 임베딩 모델을 같은 서버에서 운용할 때는 포트를 다르게 잡고, 두 프로세스의 --gpu-memory-utilization 합이 1.0을 넘지 않도록 설정한다. 예를 들어 LLM에 0.75, 임베딩 모델에 0.15로 나누면 GPU당 총 0.90 사용이 된다.


자주 하는 실수와 트러블슈팅

1. OOM (Out of Memory)

torch.cuda.OutOfMemoryError: CUDA out of memory.

원인은 크게 두 가지다. 첫째, --max-model-len이 너무 높아 KV 캐시 예약량이 가중치 공간까지 침범하는 경우다. 둘째, 여러 모델을 한 GPU에 올릴 때 --gpu-memory-utilization 합이 1.0을 초과하는 경우다.

해결 순서:

  1. --max-model-len을 낮춘다 (131072 → 32768 등).
  2. --gpu-memory-utilization을 낮춘다 (0.9 → 0.8).
  3. --enforce-eager를 추가해 CUDA 그래프 메모리 예산을 줄인다.

2. chat_template 누락 에러

jinja2.exceptions.TemplateError: chat_template is not defined

모델의 tokenizer_config.jsonchat_template이 없을 때 발생한다. --chat-template으로 Jinja2 템플릿 파일 경로를 명시하거나, HuggingFace에서 최신 토크나이저 설정을 다시 내려받는다.

vllm serve my-model \
  --chat-template /path/to/chat_template.jinja

3. tokenizer 불일치

ValueError: The model's tokenizer does not match the model's vocabulary.

모델 가중치와 토크나이저 버전이 다를 때 발생한다. --tokenizer 인자로 올바른 토크나이저 경로를 별도로 지정하거나, 모델과 토크나이저를 같은 체크포인트에서 내려받는다.

4. HuggingFace gated model 접근 실패

OSError: You are trying to access a gated repo.

Llama, Gemma 같은 일부 모델은 HuggingFace 라이선스 동의와 API 토큰이 필요하다. 환경 변수로 토큰을 설정한다.

export HF_TOKEN=hf_xxxxxxxxxxxxx
vllm serve meta-llama/Llama-3.1-8B-Instruct

5. 포트 충돌

OSError: [Errno 98] Address already in use

같은 포트에 다른 프로세스가 이미 올라와 있다. lsof -i :8000으로 점유 프로세스를 확인하고 종료하거나, --port 인자로 다른 포트를 지정한다.


다음 단계 — 멀티모델·양자화·프로덕션 서빙 시리즈 안내

기본 서빙 흐름이 익숙해지면 다음 주제로 넘어갈 수 있다.

인자 심화: vLLM 0.21.0 서빙 가이드 — 모델 유형별 vllm serve 인자 정리에서 thinking 모델, tool calling 활성화, OCR·멀티모달 모델 등 유형별 서빙 구성과 인자 조합을 다뤘다.

멀티모델 배포: vLLM 0.21.0 서빙 가이드 2편 — H200 두 장에 세 모델 동시 올리기에서 LLM + 임베딩 + OCR 모델을 같은 서버에 올릴 때의 VRAM 예산 계획, CUDA_VISIBLE_DEVICES 분리 전략, CUDA Graph 트러블슈팅을 정리했다.

이후 시리즈에서 다룰 예정인 주제는 다음과 같다.

  • AWQ, GPTQ, INT4 양자화로 GPU 메모리 요건 줄이기
  • 로드밸런서·Prometheus 모니터링을 포함한 프로덕션 서빙 구성
  • 파이프라인 병렬(pipeline parallelism)과 텐서 병렬을 함께 사용하는 멀티 GPU 배치
Tags
vLLMInferenceLLMGPUPythonDocker서빙RAG