LLM 엔지니어링16장 · vLLM 서빙 벤치마킹과 RAG 최적화3 / 22← 이전목차다음 →MetaContents

16장. vLLM 서빙 벤치마킹과 RAG 최적화

서빙 엔진이 하는 일

식당에서 요리사 혼자 주문을 하나씩 받아 요리하면, 손님이 많아질수록 줄이 길어집니다. 주방을 잘 돌리는 식당은 주문을 모아 화구를 빈틈없이 쓰고, 다 된 접시는 바로 내보내고 다음 주문을 올립니다. 서빙 엔진은 이런 주방장입니다. 모델(요리법)은 같아도 주방을 돌리는 솜씨에 따라 같은 시간에 내보내는 접시 수가 크게 달라집니다.

transformers 의 generate, Ollama, vLLM 세 가지를 쓰임새와 강점으로 나란히 놓은 비교 그림

그림의 세 카드는 지금까지 쓴 두 가지와 이 장에서 새로 보는 vLLM 입니다. 왼쪽 transformers 의 generate 는 학습과 실험에 좋고, 가운데 Ollama 는 한 사람이 PC 에서 편하게 쓰기에 좋고, 오른쪽 vLLM 은 많은 사용자가 동시에 부르는 서버에 맞춥니다. 여기서 요리사가 모델, 주방을 돌리는 방식이 서빙 엔진입니다.

서빙 엔진 견주기

엔진잘하는 것이 과목에서
transformers generate모델을 고치며 실험, 학습3, 5, 15장
Ollama(llama.cpp)PC 에서 양자화 모델을 쉽게, CPU 와 GPU 를 나눠서6장부터
vLLM동시 요청이 많은 GPU 서버, 높은 처리량이 장(안내 코드)
TGI, SGLangvLLM 과 비슷한 서버용 엔진이름만

같은 코드로 엔진 바꾸기

Ollama 와 vLLM 은 모두 OpenAI 호환 주소(/v1/chat/completions)를 엽니다. 그래서 6장의 openai 코드에서 주소와 모델 이름만 바꾸면 엔진을 갈아 끼울 수 있습니다.

Python
# 엔진마다 다른 것은 주소와 모델 이름뿐이다
engines = {
    "Ollama": {"base_url": "http://127.0.0.1:11434/v1", "model": "qwen2.5:3b"},
    "vLLM": {"base_url": "http://127.0.0.1:8000/v1", "model": "Qwen/Qwen2.5-3B-Instruct"},
}
# 요청 본문은 둘 다 같은 꼴이다
body = {"messages": [{"role": "user", "content": "연차는 며칠인가요?"}], "max_tokens": 80, "temperature": 0}
for name, e in engines.items():
    print(f"{name:7s} POST {e['base_url']}/chat/completions  model={e['model']}  본문 칸={list(body)}")

코드에 나오는 함수

코드쉬운 뜻
base_urlbase(바탕)와 URL(Uniform Resource Locator, 인터넷 주소)을 붙인 말이다. 요청을 보낼 서버의 기본 주소다
11434, 8000포트(port, 항구) 번호다. 한 PC 안에서 어느 프로그램에게 보낼지 가리킨다. Ollama 는 11434, vLLM 은 8000 을 흔히 쓴다
/chat/completionscompletion(완성, 마저 채움)에서 온 이름이다. 대화를 보내면 다음 답을 채워 주는 OpenAI 꼴의 주소다
"messages"대화 기록을 담는 칸이다. 말 하나는 role(역할, 누가 말했나)과 content(내용)로 적는다
"max_tokens": 80답을 최대 80토큰까지만 쓰게 한다. 출력 길이를 묶어 시간을 맞춘다
"temperature": 0temperature(온도)를 0 으로 두면 가장 그럴듯한 토큰만 골라 매번 같은 답이 나온다(3장)
list(body)사전의 열쇠만 목록으로 꺼낸다. 본문에 어떤 칸이 있는지 보여 준다

이 코드가 뜻하는 것

배달 앱으로 같은 메뉴를 시킨다고 생각해 봅니다. 주문서의 꼴(메뉴, 수량, 요청 사항)은 어느 가게에 보내든 같고, 바뀌는 것은 받는 가게의 주소뿐입니다. 여기서 주문서가 요청 본문 body 이고, 가게 주소가 base_url 입니다.

줄하는 일쉽게 말하면
engines = {...}엔진마다 주소와 모델 이름을 적어 둔다가게 두 곳의 주소록
body = {...}두 엔진에 똑같이 보낼 요청 본문을 만든다한 장으로 쓴 주문서
for name, e in engines.items()엔진을 하나씩 돌며 보낼 곳을 출력한다같은 주문서를 가게마다 어디로 보낼지 적어 본다

출력 두 줄에서 본문 칸=['messages', 'max_tokens', 'temperature'] 는 똑같고 주소와 모델 이름만 다릅니다. 이 코드는 출력만 하고 실제로 요청을 보내지는 않습니다. 비유와 다른 점은, 엔진마다 같은 모델이라도 답이 조금씩 다를 수 있다는 것입니다.

주의할 점

  • 엔진마다 같은 모델이라도 기본 설정(양자화, 최대 길이, 샘플링 기본값)이 달라 답이 조금씩 다릅니다. 엔진을 바꾸면 품질도 다시 잽니다.
  • 사용자가 한 명이면 vLLM 의 장점이 잘 드러나지 않습니다. 엔진은 동시 사용자 수와 GPU 에 맞춰 고릅니다.
← 이전 절16장 · 용어 짚고 가기다음 절 →16장 · 프리필과 디코드