서빙 엔진이
판단하기 시작했다.
지금까지 서빙은 "모델 하나를 빠르게 돌리는 일"이었습니다. 이 장에서는 요청의 의미를 읽고, 어떤 모델로 보낼지, 어떤 도구를 쥐여줄지, 어디서 실행할지까지 서빙 계층이 결정하기 시작합니다.
들어가며
책의 마지막 장은 정리가 아니라 지도입니다. 앞 장들이 GPU·KV 캐시·배칭·분산 서빙처럼 "모델을 빠르게 돌리는 법"에 집중했다면, 이 장은 그 위층으로 올라가 여섯 가지 흐름을 훑습니다.
처음 이 장을 읽으면 주제들이 서로 상관없어 보입니다. 시맨틱 라우팅, 프로파일링, 멀티모달, 엣지, Multi-LoRA, 강화학습 — 공통점이 뭘까요? 두 가지가 계속 반복됩니다. 병목은 늘 GPU가 아니라는 것, 그리고 서빙 엔진이 점점 더 많은 결정을 떠맡고 있다는 것입니다.
- LLM 서빙은 "모델 하나를 빠르게 실행하는 시스템"에서 요청의 의미를 이해하고 모델·도구·하드웨어·실행 위치를 고르는 지능형 추론 시스템으로 옮겨가고 있습니다.
- 병목은 자꾸 GPU 밖으로 이동합니다. 멀티모달에서는 CPU 전처리로, 프로파일링에서는 커널 사이의 유휴 간격으로, 엣지에서는 발열로 옮겨갑니다.
- 모든 기법에는 쓰면 안 되는 조건이 붙어 있습니다. Multi-LoRA는 어댑터별 트래픽이 많으면 오히려 손해고, 시맨틱 캐싱은 트래픽이 적으면 의미가 없습니다.
접는 상자(▸)는 안 열어도 됩니다. 안에는 설정 예시, 원문 출력, 세부 표가 들어 있습니다. 본문만 읽어도 흐름은 끊기지 않습니다.
그림은 만져보라고 넣었습니다. 슬라이더를 극단까지 밀면 각 기법이 언제 무너지는지가 보입니다. 노란 상자에 "해볼 것"이 적혀 있습니다.
이 페이지의 장 번호와 책의 장 번호는 다릅니다. 책을 가리킬 때는 "책 7장"처럼 앞에 '책'을 붙였습니다.
다루는 것
여섯 가지 흐름 — 시맨틱 캐싱과 라우팅(+ 그 구현체인 LiteLLM 게이트웨이), 성능 프로파일링 전략, 멀티모달(VLM) 서빙, 엣지 AI, Multi-LoRA 서빙, 그리고 강화학습 파이프라인에서의 서빙입니다. 마지막 8장에서는 스터디 전체에서 나온 최적화 기법을 한 표로 모아 언제 켜고 언제 끄는지 정리합니다.
다루지 않는 것
각 주제는 책 한 권 분량입니다. 여기서는 핵심 아이디어와 판단 기준까지만 갑니다. 임베딩 모델을 고르는 법, CUDA 커널 작성법, LoRA의 수학적 유도, RLHF의 알고리즘(PPO·GRPO 등)은 다루지 않습니다. 이미지·영상을 생성하는 모델(Midjourney, Sora, Veo 같은 확산 모델 기반)도 범위 밖입니다 — 자기회귀 텍스트 생성과 동작 방식이 다릅니다.
여섯 주제를 하나로 꿰는 질문이 있습니다. "서빙 엔진이 새로 떠맡은 결정은 무엇인가?"
시맨틱 라우터는 어떤 모델을 쓸지, Multi-LoRA는 어떤 어댑터를 쓸지,
엣지–클라우드 하이브리드는 어디서 실행할지, RLHF의 서빙 엔진은 같은 입력에 같은 출력을 보장할지를 결정합니다.
예전의 추론 전용 엔진에는 없던 요구사항들입니다.
첫 번째 흐름부터. 라우팅이 "부하 분산"에서 "의미 이해"로 올라갑니다.
01시맨틱 캐싱과 라우팅 — 말이 달라도 뜻이 같으면
한 줄 요약: 정확히 일치하는 문자열이 아니라, 의미가 가까운 요청을 알아보고 처리합니다.
prefix caching은 글자가 똑같아야 먹습니다. "시애틀에서 하와이까지 비행시간이 얼마나 걸리나요?"와 "시애틀에서 하와이까지 비행기로 몇 시간 걸리는지 알려줘"는 글자가 전혀 달라서 캐시가 하나도 안 맞습니다. 그런데 답은 같습니다.
여기에 LLM을 한 번 더 호출하는 건, 특히 외부 유료 LLM이라면 낭비입니다. 시맨틱 캐싱은 이 낭비를 없앱니다.
- embedding (임베딩)
- 문장을 숫자 여러 개의 목록으로 바꾼 것(예: 길이 768). 뜻이 비슷한 문장은 비슷한 숫자 목록이 됩니다.
- vector search (벡터 검색)
- 저장해 둔 임베딩 중 지금 것과 가장 가까운 것을 찾는 검색. "가깝다"는 보통 코사인 유사도로 잽니다.
- PII
- Personally Identifiable Information — 이름·주소·연락처·카드번호 같은 개인식별정보.
- NER
- Named Entity Recognition — 문장에서 사람 이름·기관·이메일 같은 개체를 찾아내는 작업. PII 마스킹에 씁니다.
- SLM
- Small Language Model — 80억~320억 파라미터 규모의 작고 태스크에 특화된 모델.
- MCP
- Model Context Protocol — 도구(tool)를 스키마·권한·메타데이터와 함께 등록해 두는 규약.
- endpoint-level routing
- 같은 모델의 복제본 사이가 아니라, 서로 다른 모델 엔드포인트 사이에서 고르는 라우팅.
비유 — 콜센터의 1차 상담원
큰 콜센터에는 전문가에게 바로 연결하지 않고 먼저 받는 사람이 있습니다. 이 사람이 하는 일은 세 가지입니다.
첫째, 자주 오는 질문이면 자기가 바로 답합니다(시맨틱 캐시). 둘째, 내용을 듣고 어느 부서로 보낼지 정합니다(모델 선택). 셋째, 통화 내용에서 주민번호 같은 걸 지우고 넘깁니다(PII 마스킹).
중요한 건 이 사람이 전문가가 아니어도 된다는 점입니다. 작고 빠른 인코더 모델이면 충분합니다.
작은 숫자로 한 번
임베딩 공간에서 캐시가 먹는 범위
↔ 드래그 + 슬라이더실제 임베딩은 768차원입니다. 여기서는 2차원으로 눌러 그린 모형이고, 유사도도 화면 거리로 계산한 값입니다.
그림 10-1. 엔드포인트 수준 라우팅 vs 복제본 수준 라우팅
라우터 아래에 두 개의 층이 있습니다. 위쪽은 어떤 모델 엔드포인트를 부를까(Model A냐 Model B냐), 아래쪽은 그 모델의 어떤 복제본을 부를까입니다.
책 7장에서 다룬 데이터 병렬 라우팅은 아래층 — 같은 모델의 복제본 사이 부하 분산이었습니다. 시맨틱 라우팅이 새로 맡은 것은 위층입니다.
시맨틱 라우터가 하는 네 가지
- 캐시 히트를 늘린다표현은 달라도 뜻이 같은 질문에 저장해 둔 답을 그대로 돌려줍니다. 외부 LLM 호출 비용과 지연시간이 사라집니다.
- 모델과 추론 기능을 고른다ModernBERT 같은 경량 인코더로 프롬프트가 얼마나 복잡한지 빠르게 판단합니다. 간단한 질문에 최고급 모델을 부를 이유가 없습니다.
- SLM으로 보낸다8B~32B 규모의 태스크 특화 모델이 거대 범용 모델과 대등하거나 더 나은 경우가 많습니다. 지연시간과 SLA 제어도 유리합니다.
- 도구를 걸러내고 정책을 집행한다MCP로 등록된 도구 전부를 모델에 넘기는 대신 관련된 것만 고릅니다. 프롬프트 부담·지연시간·오작동 위험이 함께 줄고, 보안·컴플라이언스 검사의 중앙 집행점이 됩니다.
그림 10-2. 시맨틱 라우터가 요청을 여러 LLM으로 보내는 시스템
번호 순서대로 읽습니다. (1) PII 모델로 개인정보를 지우고 → (2) 임베딩 모델로 벡터를 만들고 → (3) 벡터 DB에서 캐시된 응답을 찾고 → (4) 도구 목록도 벡터 검색으로 좁히고 → (5) 소형 분류기가 어떤 LLM을 부를지, 추론 기능을 켤지 정합니다.
(3)에서 아주 가까운 항목이 나오면 (5)까지 가지 않고 끝납니다.
요청 하나가 라우터를 통과하는 3단계
↔ 슬라이더 + 재생PII 마스킹이 맨 앞에 있는 이유 — 다운스트림의 로그·캐시·라우팅 기록에 개인정보가 절대 남지 않게 하려면 여기서 지워야 합니다.
PII 마스킹 — NER 모델의 출력과 치환
PII 모델은 보통 프라이버시 민감 개체에 대해 파인튜닝된 소형 인코더입니다. 출력은 위치와 라벨입니다.
[
{"start": 5, "end": 13, "label": "PERSON",
"text": "John Doe", "confidence": 0.97},
{"start": 66, "end": 81, "label": "EMAIL",
"text": "john@abc.com", "confidence": 0.95}
]
이 위치 정보로 원문에 돌아가 <NAME_1>, <EMAIL_1> 등으로 치환합니다.
실무에서는 정규식을 함께 써서 NER 모델을 보완하는 경우가 많습니다(카드번호·전화번호처럼 패턴이 명확한 것들).
이 단계는 라우터 안에서 할 수도 있고, 그 앞단 게이트웨이에서 할 수도 있습니다(2장의 LiteLLM이 그런 자리입니다).
도구 필터링 — 도구가 100개일 때
# 에이전트가 쓸 수 있는 tool이 100개라고 하면, # 모든 tool schema를 LLM에 보낼 때: Prompt Token ↑ Context ↑ Latency ↑ Cost ↑ 잘못된 Tool 선택 위험 ↑ # 벡터 검색으로 관련 있는 5~10개만 추려서 보내면 전부 반대로 움직인다.
MCP는 도구를 구조화된 스키마 · 권한 · 메타데이터와 함께 등록하는 규약입니다. 라우터가 그 목록에서 요청과 관련된 것만 골라 넘기면, 라우터는 자연스럽게 보안·정책·컴플라이언스의 집행 지점이 됩니다.
책 7장에서 라우팅은 모델 복제본 사이의 부하 분산이었습니다(prefix cache 상태나 KV 캐시 사용률을 보고 고르는). 이제는 서로 다른 모델 엔드포인트 사이에서 고릅니다 — 소형 내부 모델, 중형 도메인 모델, 외부 최첨단 추론 모델. "정확히 일치"에서 "의미 기반 매칭"으로, "복제본 수준"에서 "엔드포인트 수준"으로 두 단계가 함께 올라간 겁니다.
트래픽이 적어서 외부 LLM 호출 자체가 부담이 아닐 때는 시맨틱 캐시 인프라(임베딩 모델 + 벡터 DB + 운영)가 배보다 배꼽입니다. 또 임계값을 낮게 잡으면 비슷해 보이지만 다른 질문에 캐시된 답을 주게 됩니다 — 위 그림에서 직접 확인해 보세요.
참고 — vLLM Semantic Router
오픈소스 구현으로 vllm-project/semantic-router가 있습니다. 'Client → vLLM Semantic Router → vLLM 여러 대' 구성으로 라우팅·Failover·시맨틱 라우팅과 모니터링을 붙여보는 것이 이번 주 도전 과제 중 하나입니다.
- 정의 — 시맨틱 캐싱·라우팅은 임베딩과 벡터 검색으로 뜻이 같은 요청을 알아보고 처리하는 상위 계층입니다.
- 성질 — 3단 파이프라인(PII 마스킹 → 임베딩·벡터 검색 → 분류기)으로 동작하며, 2단계에서 캐시가 맞으면 LLM을 아예 호출하지 않습니다.
- 쓰임 — 캐시 히트 증가, 모델·추론 기능 선택, SLM 라우팅, 도구 필터링과 정책 집행. 단, 임계값 설정이 품질을 좌우합니다.
개념은 봤습니다. 실제로 이런 일을 하는 물건이 이미 있습니다.
02LiteLLM — 모델 앞에 서는 게이트웨이
한 줄 요약: 100개가 넘는 제공사를 하나의 API로 묶고, 그 자리에서 라우팅·폴백·마스킹·과금을 처리합니다.
1장에서 본 "라우터가 하는 일"들 — 마스킹, 캐싱, 모델 선택, 정책 집행 — 은 애플리케이션마다 짜면 안 되는 것들입니다. 한 군데 모아야 관리도 되고 감사도 됩니다.
LiteLLM은 그 한 군데를 맡는 AI 게이트웨이입니다. 앱은 OpenAI 형식 하나만 알면 됩니다.
- forward proxy / reverse proxy
- 앞의 것은 클라이언트 대신 요청을 보내주는 프록시, 뒤의 것은 서버 대신 요청을 받아주는 프록시입니다. LiteLLM Proxy는 뒤쪽에 가깝습니다.
- virtual key (가상 키)
- 실제 제공사 API 키 대신 팀·사용자에게 발급하는 게이트웨이 전용 키. 예산과 한도가 붙습니다.
- fallback / retry
- 모델이 실패하거나 한도에 걸리면 다른 배포로 넘기거나(fallback) 같은 그룹 안에서 다시 시도(retry)하는 것.
- model group (모델 그룹)
- 같은
model_name을 가진 배포들의 묶음. 이 안에서 부하 분산이 일어납니다. - rpm / tpm
- 분당 요청 수 / 분당 토큰 수. 라우팅 가중치와 한도의 단위입니다.
비유 — 회사 대표번호
회사에 부서마다 직통번호가 있어도, 바깥에는 대표번호 하나만 알립니다. 대표번호로 걸면 교환대가 받아서 사람을 확인하고(가상 키), 통화 횟수를 세고(rate limit), 담당 부서로 돌리고(라우팅), 그 부서가 통화 중이면 다른 담당자에게 넘깁니다(fallback).
부서가 바뀌어도 바깥에 알릴 필요가 없다는 게 가장 큰 이득입니다.
작은 숫자로 한 번
가중치 기반 라우팅(Weighted Pick)은 배포마다 적힌 rpm에 비례해서 트래픽을 나눕니다.
가중치 라우팅과 장애 시 폴백
↔ 슬라이더 + 버튼폴백은 모델 그룹 단위로 동작합니다. 같은 그룹 안에서 먼저 재시도하고, 그룹 전체가 안 되면 다른 그룹으로 넘어갑니다.
요청 하나의 생명주기
- 요청 도착클라이언트가 LiteLLM Proxy(게이트웨이)로 보냅니다. 형식은 OpenAI 호환입니다.
- 가상 키 검증Bearer 토큰이 유효한지, 예산 범위 안인지 확인합니다. 캐시(Redis/메모리)에 없으면 DB를 조회합니다.
- 속도 제한글로벌·키·사용자·팀 네 층의 rpm/tpm 한도를 검사합니다.
- 라우터로 전달
/chat/completions,/embeddings요청이 LiteLLM 라우터를 통과합니다. - 폴백과 재시도fallback으로 한 겹, retry로 또 한 겹 감싼 뒤 실제 제공사 API를 호출합니다.
- 응답 후 비동기 처리응답을 클라이언트에 보낸 뒤 로그 전송(Langfuse·MLflow 등), 사용량 갱신, DB 기록을 비동기로 수행합니다.
주요 기능과 라우팅 전략
통일된 API — 어느 제공사든 completion() 하나로 호출하고, 응답도 OpenAI 형식으로 통일됩니다.
from litellm import completion
response = completion(
model="gpt-4o", # 또는 "claude-sonnet-4", "gemini/gemini-pro" 등
messages=[{"role": "user", "content": "안녕하세요"}]
)
두 가지 사용 방식 — 코드에 임포트하는 SDK 방식과, 게이트웨이 서버로 띄우는 Proxy 방식(OpenAI 호환 엔드포인트 제공).
주요 기능 — fallback/retry, 로드 밸런싱, 비용 추적과 팀별 예산, 캐싱(Redis 연동 + 시맨틱 캐싱), 가드레일·PII 마스킹, 관찰성(Langfuse·Datadog·Prometheus).
| 라우팅 전략 | 고르는 기준 |
|---|---|
| Weighted Pick (기본·프로덕션 권장) | 배포에 적힌 rpm/tpm에 비례. 지연시간 오버헤드가 가장 작습니다. |
| Rate Limit Aware | 남은 한도가 많은 쪽으로. |
| Least Busy | 현재 처리 중인 요청이 적은 쪽으로. |
| Latency Based | 최근 응답이 빨랐던 쪽으로. |
| Cost Based | 토큰당 비용이 싼 쪽으로. |
Auto Routing — 1장의 시맨틱 라우팅이 여기 들어옵니다
기존 Semantic Auto Router는 router.json에 경로별 예시 발화(utterances)를 적어 두고,
들어온 메시지의 임베딩을 모든 경로의 모든 발화와 동시에 비교해 유사도가 가장 높은 경로로 보내는 방식이었습니다.
점수가 임계값을 넘지 못하면 기본 모델로 갑니다. (경로 순서는 결과에 영향을 주지 않습니다 — 첫 일치에서 멈추지 않고 전역 최고점을 고릅니다.)
{
"encoder_type": "openai",
"encoder_name": "text-embedding-3-large",
"routes": [
{ "name": "litellm-gpt-4.1",
"utterances": [ "코드 리뷰 해줘", "이 함수 버그 찾아줘", ... ],
"score_threshold": 0.7 }
]
}
이 방식은 deprecated이며, 시맨틱 키워드 매칭·복잡도 점수·적응형 라우팅을 하나로 합친
Auto Routing(auto_router/complexity_router)으로 대체되었습니다. 새 구성은 그쪽에서 시작하는 것이 좋습니다.
그 밖에 예산 기반 라우팅과 상태 점검 기반 라우팅도 있습니다.
이미지 URL 처리 — 게이트웨이가 조용히 해주는 일
일부 LLM API는 이미지 URL을 못 받고 base64 문자열만 받습니다. LiteLLM은 요청에서 URL을 감지해 대상 API가 URL을 지원하는지 확인하고, 지원하지 않으면 이미지를 대신 내려받아 base64로 바꿔서 보냅니다.
반복 호출의 지연시간을 줄이려고 변환된 이미지 최대 10개를 메모리에 캐시하고, 개별 다운로드 용량은 기본 50MB로 제한합니다(MAX_IMAGE_URL_DOWNLOAD_SIZE_MB로 변경).
이런 자잘한 호환성 처리를 앱마다 짜지 않아도 된다는 것이 게이트웨이를 두는 실질적인 이유입니다.
- 정의 — LiteLLM은 100개 이상 제공사를 OpenAI 형식 하나로 묶는 오픈소스 게이트웨이입니다. SDK 방식과 Proxy 방식이 있습니다.
- 성질 — 요청은 가상 키 검증 → 속도 제한 → 라우터(fallback → retry) → 제공사 호출 → 비동기 로깅 순으로 흐릅니다. 기본 라우팅은 rpm/tpm 가중치입니다.
- 쓰임 — 마스킹·캐싱·모델 선택·예산·관찰성을 한 자리에 모읍니다. 1장의 시맨틱 라우팅은 Auto Routing으로 여기에 들어와 있습니다.
위층 이야기는 여기까지. 이제 다시 아래로 내려가, 느린 이유를 찾는 방법을 봅니다.
03성능 프로파일링 — 증상에서 원인까지 내려가는 순서
한 줄 요약: 서빙 지표 → 오퍼레이터 → CUDA 커널. 층을 건너뛰면 길을 잃습니다.
프로파일러는 종류가 너무 많고, 각각 보여주는 층이 다릅니다. 아무거나 켜면 숫자는 잔뜩 나오는데 무엇을 고쳐야 하는지는 안 나옵니다.
대규모 서빙에서는 1퍼센트포인트 개선이 수백만 달러 인프라 비용으로 이어집니다. 마지막 몇 퍼센트포인트는 이제 선택적 사치가 아니라 운영상 필수입니다.
- operator (오퍼레이터)
- PyTorch가 보는 연산 한 덩어리 — matmul, attention, layernorm 같은 것들. 각 오퍼레이터는 하나 이상의 CUDA 커널로 펼쳐집니다.
- CUDA kernel
- GPU에서 실제로 도는 함수. 오퍼레이터보다 한 층 아래입니다.
- idle gap (유휴 간격)
- 커널과 커널 사이에 GPU가 아무것도 안 하고 있는 구간. 사용률이 높아 보여도 여기가 벌어져 있을 수 있습니다.
- CUDA stream
- GPU 작업의 줄. 여러 줄을 쓰면 데이터 복사와 연산을 겹칠 수 있습니다.
- occupancy / memory stall
- 커널이 GPU를 얼마나 채우는지, 그리고 메모리를 기다리느라 얼마나 멈춰 있는지.
- fused kernel (퓨즈드 커널)
- 여러 연산을 하나로 합친 커널. 중간 결과를 메모리에 쓰고 다시 읽는 낭비를 없앱니다.
비유 — 병원의 검사 순서
배가 아프다고 바로 개복 수술을 하지는 않습니다. 문진 → 혈액검사 → 초음파 → CT 순으로 범위를 좁혀 갑니다. 각 단계는 다음 단계를 어디에 쓸지 알려주는 역할을 합니다.
프로파일링도 같습니다. 서빙 지표로 이상을 감지하고, 프레임워크 프로파일러로 범인 오퍼레이터를 좁히고, 커널 프로파일러로 그 안을 봅니다. 순서를 건너뛰면 CT를 온몸에 찍는 꼴이 됩니다.
세 개의 층
| 층 | 보는 것 | 도구 |
|---|---|---|
| 서빙 레이어 | 처리량, TTFT, ITL, GPU·메모리 사용률. SLA/SLO를 맞추기 위한 조정. | 벤치마크, 대시보드 |
| 프레임워크 레이어 | matmul·attention·layernorm 같은 오퍼레이터별 실행 시간, CPU↔GPU 데이터 이동, 연산과 I/O가 겹치는지. | PyTorch Profiler (CPU 모드 / CUDA 모드) |
| 런타임 레이어 | 오퍼레이터가 펼쳐진 실제 CUDA 커널의 동작. 유휴 간격, 점유율, 메모리 스톨, 텐서 코어 활용률. | Nsight Systems → Nsight Compute |
작은 숫자로 한 번
그림 10-3. 종단 간 성능 프로파일링 의사결정 흐름도
항상 Nsight Systems에서 시작합니다. 첫 갈림길은 "GPU가 놀고 있는가"입니다.
놀고 있으면 PyTorch Profiler(CPU 모드)로 호스트 병목(느린 전처리·I/O 스톨)을 찾고, 바쁜데도 느리면 CUDA 모드로 무거운 오퍼레이터를 찾습니다.
두 번째 갈림길은 "커널 하나가 지배적인가"입니다. 지배적이면 Nsight Compute로 워프 스톨·메모리 대역폭·텐서 코어 활용률을, 아니면 다시 Nsight Systems로 커널 launch 동작·타임라인 간격·연산-메모리 오버랩을 봅니다.
어느 도구를 언제 쓰는가
↔ 슬라이더 2개단일 커널이 지배적이지 않은데 느리다면 원인은 커널 안이 아니라 launch 오버헤드·오버랩 부재·동기화입니다. 그럴 땐 다시 타임라인으로.
의사결정 흐름도 (그림 10-3)
Nsight Systems (시스템 전체 타임라인)
├─ GPU 활용률 낮음
│ → PyTorch Profiler (CPU 모드) → 호스트 측 병목 확인
│ (느린 전처리, Python 디스패치 오버헤드, 직렬화 작업)
│
└─ GPU는 바쁜데 지연시간 높음
→ PyTorch Profiler (CUDA 모드) → 어떤 오퍼레이터가 지배적인지
├─ 단일 커널이 지배적
│ → Nsight Compute로 미세 분석 → 튜닝 / 교체 / 퓨전
└─ 단일 커널 아님
→ launch 오버헤드 · 오버랩 부재 · 동기화 문제
→ Nsight Systems 타임라인 재점검
Nsight Systems가 드러내는 것 — GPU 사용률이 높아 보여도 실제로는 커널 사이에 큰 유휴 간격이 있을 수 있습니다. 호스트가 커널을 너무 느리게 실행시키거나, 데이터 전송이 연산과 겹치지 않기 때문입니다. 해결은 CUDA 스트림을 여러 개 써서 복사와 연산을 겹치는 쪽입니다.
Nsight Compute가 드러내는 것 — 커널 하나가 전체를 지배할 때 그 이유. 흔한 원인은 낮은 점유율과 잦은 메모리 스톨입니다. 예를 들어 attention softmax 커널이 큰 중간 텐서를 공유 메모리에 두지 않고 글로벌 메모리에서 반복해서 읽고 있을 수 있습니다. 그러면 메모리 접근 패턴을 고치거나, 블록/그리드 구성을 바꾸거나, 퓨즈드 커널로 교체합니다.
CH9에서 우리는 정확히 이 순서를 밟았습니다. 벤치마크로 "AWQ가 2.2배 빠르다"를 확인하고(서빙 레이어), Nsight Systems로 "총 커널 시간은 같은데 동기화 대기가 다르다"를 찾아내고(런타임 레이어), Nsight Compute로 "커널 하나하나의 효율은 그대로다"를 확인했습니다. 층을 내려갈수록 답이 구체적이 되는 걸 그대로 보여준 사례입니다.
- 정의 — 프로파일링은 서빙 / 프레임워크 / 런타임 세 층으로 나뉘고, 각 층의 도구가 다릅니다.
- 성질 — Nsight Systems로 시작해 GPU가 병목인지 먼저 가르고, PyTorch Profiler로 오퍼레이터를 좁힌 뒤, 단일 커널이 지배적일 때만 Nsight Compute로 내려갑니다.
- 쓰임 — 대규모 서빙에서 1퍼센트포인트는 수백만 달러입니다. 증상에서 원인까지 계층적으로 내려가는 전략 자체가 도구보다 중요합니다.
여기까지가 텍스트 이야기였습니다. 입력에 이미지가 섞이면 병목이 GPU 밖으로 나갑니다.
04멀티모달 서빙 — 병목이 CPU로 옮겨간다
한 줄 요약: 이미지 전처리가 GPU 앞을 막습니다. 해법은 프로세스를 갈라놓는 것이었습니다.
아닙니다. 텍스트 토크나이징은 가볍지만, 이미지 전처리는 CPU를 많이 씁니다. 고해상도 이미지를 픽셀로 풀고, 크롭하고, 리사이즈하고, 텐서로 바꾸는 일이 LLM이 시작되기 전에 순차적으로 끝나야 합니다.
요청이 몰려 CPU가 포화되면, 값비싼 GPU는 일감이 없어서 놉니다. 이때 전체 처리량을 결정하는 건 LLM이 아니라 그 앞의 비전 전처리 단계입니다.
- VLM — Vision-Language Model
- 이미지(또는 영상·오디오)를 입력으로 받고 텍스트를 출력하는 모델. 이 장이 다루는 대상입니다.
- placeholder token
- 프롬프트 안에서 이미지가 들어갈 자리를 잡아두는 토큰. 나중에 비전 임베딩으로 통째로 교체됩니다.
- vision encoder
- 이미지를 작은 패치로 잘라 각각을 벡터로 만들고, LLM이 쓰는 차원으로 맞춰주는 부분.
- projection
- 벡터의 차원을 갈아 끼우는 변환. 비전 쪽 차원을 LLM의 히든 차원에 맞춥니다.
- front-loading
- 계산을 앞단에 몰아넣는 것. 여기서는 전처리가 전부 앞에 쌓이는 상황을 가리킵니다.
- decoupling (분리)
- 서로 기다리게 만드는 두 작업을 다른 프로세스로 떼어내 동시에 돌게 하는 것.
비유 — 주방과 손질대
초고속 오븐(GPU)을 들여놨습니다. 그런데 재료 손질(CPU 전처리)이 한 사람 손에 달려 있습니다. 손님이 몰리면 오븐은 재료를 기다리며 비어 있게 됩니다.
해결책은 오븐을 더 사는 게 아니라, 손질하는 사람과 굽는 사람을 갈라놓고 손질이 끝난 것부터 계속 오븐에 밀어 넣는 것입니다. vLLM V1이 한 일이 정확히 이겁니다.
작은 숫자로 한 번
이미지 한 장이 프롬프트 안에서 어떻게 표현되는지 봅시다.
이미지 한 장이 644개의 자리를 차지합니다. 텍스트 "Describe this image."는 6개입니다. 실제 처리에서 이 644개 자리는 vision encoder가 만든 임베딩으로 교체됩니다.
그림 10-4. VLM의 텍스트 입력과 비전 입력 이중 스트림 처리
두 줄기가 따로 들어와 한 벌의 임베딩으로 합쳐집니다. 이미지·영상은 vision encoder를 거치고, 텍스트는 tokenizer와 텍스트 임베딩 레이어를 거칩니다.
합쳐진 뒤부터는 LLM 디코더 입장에서 그냥 하나의 긴 임베딩 시퀀스일 뿐입니다 — 이것이 멀티모달 입력을 "특별하지 않게" 만드는 지점입니다.
CPU가 포화되면 GPU가 논다
↔ 슬라이더 + 버튼실제 벤치마크 값이 아니라, "CPU 전처리가 GPU 앞을 막는다"는 구조를 보여주는 모형입니다. 전처리 시간과 요청률은 여러분이 정하는 가정입니다.
vLLM V0 → V1이 바꾼 것
V0에서는 멀티모달 입력 전처리와 API 서버 오버헤드가 CPU 연산을 붙잡아 GPU 유휴 시간을 만들었습니다.
V1은 프로세스를 완전히 갈랐습니다.
두 프로세스가 비동기로 동시에 돌기 때문에, Process 0이 비싼 멀티모달 전처리로 바빠도 Process 1은 GPU 커널을 계속 밀어 넣습니다. 결과적으로 텍스트와 멀티모달 워크로드 모두 처리량이 크게 올랐습니다.
그림 10-5. 멀티모달 전처리를 별도 프로세스로 분리한 vLLM V1
점선 위가 Process 0, 아래가 Process 1입니다.
Process 0은 API 서버 · 입력 전처리(process() — 무거운 멀티모달 작업이 여기서 일어납니다) · 출력 후처리를 맡고, Process 1의 EngineCore는 오직 GPU 커널 스케줄링과 실행만 합니다.
둘은 소켓과 큐로만 연결되어 비동기로 동시에 돕니다. Process 0이 이미지 전처리로 아무리 바빠도 Process 1의 커널 실행 루프는 멈추지 않습니다.
이미지가 임베딩이 되기까지
Image ↓ 16×16 / 14×14 등의 Patch 로 분할 ↓ 각 Patch → Vector ↓ LLM hidden dimension 으로 projection ↓ 패치끼리 attention → 전역적인 공간·의미 관계 인코딩 ↓ Vision Embedding # LLM 입장에서는 결국 Text embedding → Vision embedding → Text embedding 이 하나의 긴 embedding sequence 로 들어온다.
텍스트 토큰 ID는 평소처럼 텍스트 임베딩으로 매핑되고, 이미지 플레이스홀더 자리는 vision encoder의 출력으로 대체됩니다. 모델 입장에서는 한 줄로 이어진 임베딩일 뿐입니다.
이 장이 다루는 것은 멀티모달 입력 → 텍스트 출력 모델뿐입니다. Midjourney·Sora·Veo처럼 이미지나 영상을 생성하는 모델은 확산(diffusion) 기반이라 지금까지 다룬 자기회귀 텍스트 생성과 동작 방식이 다릅니다. 그래서 책에서도 제외했습니다.
- 정의 — VLM은 이미지를 플레이스홀더 토큰으로 받아, vision encoder가 만든 임베딩으로 그 자리를 채웁니다.
- 성질 — 이미지 전처리는 CPU 집약적이고 LLM보다 먼저 끝나야 해서, 요청이 몰리면 병목이 GPU에서 CPU로 이동합니다.
- 쓰임 — vLLM V1은 API·전처리·후처리(Process 0)와 GPU 커널 실행(Process 1)을 갈라 이 병목을 없앴습니다. 캐싱·배칭·스트리밍의 원칙이 텍스트 밖으로 확장되는 사례입니다.
데이터센터 밖에서는 또 다른 제약이 기다립니다 — 전력, 그리고 열.
05엣지 AI — 클라우드 모델을 줄인 게 아니다
한 줄 요약: 지연·프라이버시·비용이 밀어붙이고, 다섯 가지 기술이 받쳐줍니다.
세 가지 이유가 있습니다. 로보틱스·자율주행·AR/VR에서는 클라우드까지 오가는 20~50ms 네트워크 홉조차 용납이 안 됩니다. 의료·금융 데이터는 시설 밖으로 나가면 안 되는 경우가 있습니다. 그리고 카메라·센서가 쏟아내는 데이터를 전부 클라우드로 보내면 대역폭 비용이 감당이 안 됩니다.
엣지 AI는 클라우드 모델을 축소해서 밀어 넣는 일이 아닙니다. 하드웨어·압축·이기종 컴퓨트·열 관리·클라우드 협업이 다 같이 맞물려야 성립하는 시스템 엔지니어링입니다.
- NPU — Neural Processing Unit
- 신경망 연산 전용 칩(또는 SoC 안의 블록). 강력한 코어 몇 개가 아니라 작고 효율적인 처리 요소 수천 개로 이루어집니다.
- TOPS/W
- 와트당 초당 테라 연산. 엣지 가속기의 업계 표준 지표입니다. 클라우드가 성능을 본다면 엣지는 효율을 봅니다.
- heterogeneous compute (이기종 컴퓨트)
- CPU·NPU·GPU처럼 성격이 다른 여러 연산 유닛에 작업을 나눠 맡기는 것.
- subgraph partitioning
- 모델 안의 개별 레이어를 서로 다른 가속기에 동적으로 배정하는 것. 이기종 컴퓨트의 고급 형태입니다.
- thermal throttling (열 스로틀링)
- 칩이 너무 뜨거워지면 손상을 막으려고 스스로 속도를 낮추는 것.
- adaptive offloading
- 대역폭·배터리·발열·지연 요구에 따라 어떤 단계를 기기에서 할지 클라우드로 보낼지 그때그때 결정하는 것.
비유 — 노트북과 데스크톱
데스크톱은 전기를 얼마든지 쓰고 팬을 크게 돌립니다. 노트북은 무릎 위에 올려놓고 쓰기 때문에 같은 칩이라도 오래 돌리면 스스로 느려집니다. 팬 없는 기기라면 더합니다.
그래서 엣지에서는 "얼마나 빠른가"보다 "이 온도에서 얼마나 오래 유지되는가"가 실질적인 성능입니다. 똑똑한 스케줄러는 뜨거워지기 전에 미리 작은 모델로 갈아타거나 프레임 레이트를 낮춥니다.
세 가지 동인(왜)
| 동인 | 내용 |
|---|---|
| 지연시간 | 로보틱스·자율주행·AR/VR은 밀리초 단위 반응이 필요합니다. 클라우드 왕복 20~50ms조차 허용되지 않습니다. |
| 데이터 로컬리티 | 원시 오디오·비디오, 의료 기록, 금융 정보, 산업 데이터. 로컬 처리로 GDPR·HIPAA 같은 규제를 지키고 유출 위험을 줄입니다. |
| 비용 | IoT 센서와 고해상도 카메라가 만드는 데이터를 전부 올리면 대역폭·저장 비용이 폭증합니다. 로컬에서 걸러 요약과 메타데이터만 올립니다. |
다섯 가지 인에이블러(어떻게)
- 특화된 저전력 하드웨어NPU 같은 AI 가속기. 지표는 TOPS/W입니다. 배터리를 크게 소모하거나 케이스를 녹이지 않으면서 성능을 냅니다.
- 모델 압축과 최적화양자화·프루닝·증류에 KV 캐싱, speculative decoding, 커널 최적화까지. 클라우드에서는 처리량 최적화 수단이지만 엣지에서는 동작 자체의 전제조건입니다.
- 이기종 컴퓨트CPU가 전처리(리사이즈·색공간 변환·정규화), NPU가 연산 집약 레이어, GPU가 후처리(바운딩 박스 오버레이 등). 책 7장의 파이프라인 병렬과 비슷하지만 서로 다른 하드웨어에 걸쳐 있습니다.
- 열 인지 스케줄링온도를 계속 모니터링하다가 임계값에 가까워지면 더 작은 모델로 전환하거나, 프레임 레이트를 줄이거나, 뜨거운 big 코어에서 시원한 little 코어로 워크로드를 잠시 옮깁니다. 최대 성능보다 안정성이 목표입니다.
- 엣지–클라우드 하이브리드웨이크워드 감지, 경량 이미지 전처리, 초소형 온디바이스 LLM으로 의도 파악까지는 기기가. 무거운 추론은 클라우드가. 엣지가 미리 걸러 압축했기 때문에 클라우드도 자원을 덜 씁니다.
그림 10-6. CPU · GPU · NPU 이기종 컴퓨트
한 요청이 세 종류의 연산 유닛을 갈아타며 처리됩니다. CPU는 분기 로직과 메모리 조작이 많은 전처리(리사이즈·색공간 변환·정규화)를, NPU는 양자화 친화적인 연산 집약 레이어를, GPU는 바운딩 박스 오버레이 같은 후처리를 맡습니다.
책 7장의 파이프라인 병렬과 구조는 같지만, 나뉘는 대상이 GPU들이 아니라 서로 다른 종류의 하드웨어라는 점이 다릅니다.
그림 10-7. 엣지–클라우드 하이브리드 추론 구조
엣지가 먼저 걸러서 압축한 것만 클라우드로 보냅니다. 넘어가는 것은 원시 오디오·비디오가 아니라 임베딩과 압축된 특징입니다.
그래서 지연시간과 데이터 노출이 줄어들고, 클라우드도 자원을 덜 씁니다 — 이미 정리된 입력을 받기 때문입니다.
열 스로틀링과 오프로딩 결정
↔ 슬라이더 2개 + 재생온도·성능 곡선은 가상의 모형입니다. 실제 기기의 스로틀링 곡선은 칩과 케이스 설계에 따라 완전히 다릅니다.
참고 — 엣지 서빙 프레임워크
| 프레임워크 | 설명 |
|---|---|
| TensorFlow Lite | 모바일·엣지용 경량 솔루션. 모델 양자화와 하드웨어 가속을 지원합니다. |
| ONNX Runtime | 다양한 하드웨어에서 모델을 돌리는 오픈소스 추론 엔진. |
| ExecuTorch | PyTorch의 온디바이스 추론용 엔드투엔드 솔루션. |
| Apache TVM | NPU·GPU·CPU 같은 특정 백엔드에 맞춰 모델을 최적화하는 딥러닝 컴파일러 스택. |
더 진보한 런타임은 서브그래프 파티셔닝까지 지원합니다 — 한 모델 안의 개별 레이어를 서로 다른 가속기에 동적으로 배정하는 것입니다. 성능 향상은 크지만 동기화·메모리 이동·스케줄링 부담이 만만치 않아, 현대 엣지 AI에서 가장 정교한 인에이블러로 꼽힙니다.
- 정의 — 엣지 AI는 지연시간·데이터 로컬리티·비용 세 가지 동인이 밀어붙이는 흐름입니다.
- 성질 — 다섯 인에이블러(저전력 하드웨어, 모델 압축, 이기종 컴퓨트, 열 인지 스케줄링, 엣지–클라우드 하이브리드)가 맞물려야 성립합니다. 지표는 성능이 아니라 TOPS/W입니다.
- 쓰임 — 클라우드 모델의 축소판이 아니라, 전력·메모리·발열 예산 안에서 실시간 인텔리전스를 만드는 시스템 설계입니다.
이번엔 반대 방향입니다 — 모델이 많아졌을 때 GPU를 어떻게 아낄 것인가.
06Multi-LoRA 서빙 — 어댑터 열 개, GPU 한 장
한 줄 요약: 베이스 모델 하나 위에 어댑터 여러 개를 올려 함께 서빙합니다. 단, 조건이 붙습니다.
예전에는 그랬습니다. 파인튜닝된 모델은 각각이 완전한 모델이라 GPU를 따로 차지했습니다.
LoRA는 원래 가중치를 건드리지 않고 작은 저랭크 레이어만 학습합니다. 그러면 베이스 모델은 한 벌만 올리고, 어댑터 열 개를 그 위에 얹을 수 있습니다. GPU 한 장으로 끝날 수도 있다는 뜻입니다.
- PEFT
- Parameter-Efficient Fine-Tuning — 모델 파라미터 대부분을 동결하고 작은 일부만 적응시키는 파인튜닝 방식.
- LoRA
- PEFT 중 가장 인기 있는 방법. 모델 구조에 학습 가능한 저랭크(low-rank) 레이어를 삽입합니다.
- adapter (어댑터)
- 그렇게 학습된 작은 부품. 베이스 모델과 별도로 저장·교체됩니다.
- merge (병합)
- 어댑터를 베이스 모델 가중치에 합쳐서 하나의 모델로 만드는 것. 그러면 평범한 모델처럼 독립 서빙합니다.
- Punica kernel
- 한 배치 안에 서로 다른 어댑터를 쓰는 요청이 섞여 있어도 베이스 가중치 연산과 어댑터별 연산을 함께 처리해 합치는 전용 커널.
- cold adapter
- 지금 트래픽이 없어 GPU 메모리에 올려두지 않은 어댑터. CPU 메모리나 디스크에서 필요할 때 불러옵니다.
비유 — 기본 정장에 갈아 끼우는 넥타이
정장 열 벌을 사는 대신, 정장 한 벌에 넥타이 열 개를 두는 방식입니다. 회의 성격에 따라 넥타이만 바꾸면 됩니다.
주의할 점이 있습니다. 넥타이를 바꾸는 데도 시간이 듭니다. 그리고 열 사람이 동시에 각자 다른 넥타이로 나가야 한다면, 정장 한 벌로는 감당이 안 됩니다. 그럴 땐 그냥 정장을 열 벌 사는 게 낫습니다. 이게 이 장의 결론입니다.
작은 숫자로 한 번
그림 10-9. 파인튜닝 모델 N개 vs 베이스 모델 + LoRA 어댑터 N개
왼쪽은 파인튜닝된 모델마다 GPU를 한 장씩 쓰는 기존 방식입니다. 모델 N개면 GPU N장입니다.
오른쪽은 베이스 모델 한 벌 위에 LoRA 어댑터 N개를 얹은 방식입니다. 도메인별·테넌트별 커스터마이징은 그대로 유지하면서 GPU 수를 줄입니다.
단, 어댑터마다 트래픽이 이미 GPU를 포화시킨다면 왼쪽이 낫습니다.
Multi-LoRA가 이기는 구간, 지는 구간
↔ 슬라이더 2개Multi-LoRA는 "커스터마이징은 많은데 각각의 트래픽은 적은" 환경을 위한 기법입니다. 트래픽이 많으면 오히려 서로 자원을 다투게 됩니다.
동작의 두 가지 핵심
첫째, 활성 어댑터는 모두 GPU 메모리에 올라가 있습니다. 필요할 때 하나씩 불러오는 방식이 아닙니다. 지금 트래픽을 받고 있는 어댑터는 전부 대기 상태로 상주하고, 비활성("콜드") 어댑터만 CPU 메모리나 디스크에 있다가 필요할 때 올라옵니다.
둘째, 연속 배칭과 함께 써야 합니다. GPU 활용률과 처리량을 유지하려면 서로 다른 어댑터를 쓰는 요청들도 한 배치에 묶여야 합니다. 그래서 베이스 모델 가중치 연산과 여러 어댑터별 연산을 한꺼번에 처리하고 합치는 Punica 같은 전용 커널이 개발됐습니다.
각 LoRA 어댑터가 이미 수평 확장이 필요할 만큼 무거운 트래픽을 받고 있다면, 각 어댑터를 베이스 모델에 병합해서 독립적으로 서빙하는 편이 낫습니다. Multi-LoRA는 주로 어댑터별 트래픽이 낮아서 각각을 독립 서빙하면 하드웨어가 남는 경우를 위한 기법입니다.
같은 "트래픽 패턴"이라는 변수가, 1장의 시맨틱 캐싱에서는 많을수록 유리하게, 여기서는 많을수록 불리하게 작동합니다. 기법마다 유리한 방향이 반대일 수 있다는 걸 기억해 두세요.
- 정의 — Multi-LoRA는 베이스 모델 하나 위에 여러 LoRA 어댑터를 올려 한 인스턴스에서 함께 서빙하는 방식입니다.
- 성질 — 활성 어댑터는 모두 GPU에 상주하고, 서로 다른 어댑터의 요청도 연속 배칭으로 묶입니다. 그래서 Punica 같은 전용 커널이 필요합니다.
- 쓰임 — 저트래픽 다수 테넌트에 최적입니다. 어댑터별 트래픽이 이미 하드웨어를 포화시킨다면 병합 후 독립 서빙이 정답입니다.
마지막 흐름입니다. 서빙 엔진이 이번엔 훈련 파이프라인 안으로 들어갑니다.
07강화학습에서의 서빙 — 훈련 시간의 80%가 생성이다
한 줄 요약: RLHF에서 서빙 엔진은 부속이 아니라 훈련 루프의 핵심 부품입니다. 그리고 결정론이 요구됩니다.
RLHF는 모델이 후보 응답을 잔뜩 만들어내는 것에서 시작합니다. 오픈소스 RLHF 프레임워크 OpenRLHF는 훈련 시간의 80%가 이 생성 단계에서 쓰인다고 추정합니다.
생성이 느리면 훈련 워커가 샘플을 기다리며 놉니다. 그래서 vLLM·SGLang 같은 고성능 추론 엔진이 훈련 파이프라인 전체의 처리량을 좌우합니다.
- RLHF
- Reinforcement Learning from Human Feedback — 사람의 선호를 반영해 모델의 응답 방식을 다듬는 학습.
- actor model / current policy
- 지금 최적화되고 있는 현재 버전의 언어 모델. 강화학습 용어로는 "현재 정책"입니다.
- reward model (보상 모델)
- 생성된 응답에 품질 점수를 매기는 모델.
- reference model (참조 모델)
- 정책 그래디언트를 계산할 때 기준점이 되는 모델.
- determinism (결정론)
- 같은 입력에 항상 같은 출력이 나오는 성질.
- batch-invariant
- 배치 크기나 배치 구성이 달라져도 결과가 바뀌지 않는 성질.
- drift (드리프트)
- 작은 오차가 반복되며 쌓여 결과가 서서히 벗어나는 현상.
비유 — 시험지를 대량으로 채점하는 학원
학생(actor model)이 문제를 잔뜩 풉니다. 채점자(reward model)가 점수를 매깁니다. 그 점수로 학생이 배우고, 배운 내용이 다시 학생에게 반영됩니다. 그리고 처음으로 돌아갑니다.
이 루프에서 가장 오래 걸리는 건 채점이 아니라 학생이 문제를 푸는 시간입니다. 그리고 한 가지 조건이 더 붙습니다 — 같은 문제를 다시 풀면 같은 답이 나와야 합니다. 안 그러면 점수가 흔들려서 무엇 때문에 좋아졌는지 알 수 없게 됩니다.
작은 숫자로 한 번
어디를 개선해야 하는지가 숫자로 명확합니다. 이것이 RL 팀이 추론 엔진에 신경 쓰는 이유입니다.
그림 10-10. LLM 훈련의 세 단계
Pretraining은 자기지도 토큰 완성으로 언어·개념의 기반을 쌓고, Supervised fine tune은 잘 고른 프롬프트–응답 쌍으로 지시를 따르는 법을 배우며, Reinforcement learning은 보상 기반 피드백으로 응답을 다듬어 인간의 의도에 정렬시킵니다.
이 장이 다루는 서빙 엔진은 세 번째 칸 안에서 일합니다.
생성이 빨라지면 훈련 루프가 얼마나 빨라지는가
↔ 슬라이더 + 버튼실측은 "훈련 시간의 80%가 생성 단계"라는 OpenRLHF 추정뿐입니다. 드리프트 곡선은 성질을 보여주기 위한 모형입니다.
그림 10-11. 강화학습의 생성(서빙) 단계와 훈련 단계
왼쪽 Generation phase가 훈련 시간의 80%를 씁니다. 프롬프트가 actor model(서빙 엔진, 여러 레플리카)로 들어가 응답을 대량으로 만들어냅니다.
오른쪽 Training phase에서 reward model이 점수를 매기고 reference model이 정책 그래디언트 계산을 돕습니다. 갱신된 actor model의 새 가중치는 주기적으로 서빙 레플리카에 다시 동기화됩니다(weight sync).
루프가 도는 방식
원래 추론용으로 만들어진 서빙 시스템이 이제 훈련 루프의 핵심이 되었다는 점이 중요합니다. 수천 개의 동시 요청에 걸쳐 대규모 모델로부터 확장 가능하고 저지연인 샘플링을 해내는 것이 이들의 새 역할입니다.
RLHF에서는 레플리카 사이, 또는 실행 사이의 미세한 비결정성조차 일관되지 않은 보상, 불안정한 훈련, 재현 불가능한 결과로 이어집니다.
Thinking Machines의 "Defeating Nondeterminism in LLM Inference" 같은 최근 연구는 배치 형태(batch-shape) 변화 같은 미묘한 구현 세부사항이 작은 편차를 만들고, 그것이 수천 번의 RLHF 반복에 걸쳐 누적될 수 있음을 보여줍니다. 그래서 현대 서빙 엔진은 성능뿐 아니라 배치 불변(batch-invariant) 결정론적 추론에도 초점을 맞춥니다.
일반 프로덕션 서빙에서 중요한 것이 빠르고, 싸고, 확장 가능이었다면, RL 서빙에는 여기에 재현 가능이 하나 더 붙습니다. 이것이 "서빙 엔진의 역할이 확장되고 있다"는 이 장의 메시지가 가장 선명하게 드러나는 지점입니다.
5주차 과제와 도전 과제
과제 — 5주차 스터디에서 학습한 내용 혹은 LLM 관련 내용을 간략히 정리해 공개된 링크에 글을 쓰고, 그 링크를 과제제출표에 공유합니다. 작성 도구는 블로그, GitHub, 개인 홈페이지, 유튜브, 링크드인/페이스북 공개 글 등 자유입니다.
도전 과제
· 모니터링(Prometheus + Grafana, PCIe, GPU 메트릭) vs Nsight Systems/Compute 추출 후 종합 분석
· 큰 최신 MoE 모델 vLLM 서빙 (예: TP=2 × EP=2 = GPU 4장)
· GPU 2장 서버에서 PP=2 vs TP=2 vs Router → Replica=2 비교 측정
· 'Client → vLLM Semantic Router → vLLM ×2' 환경에서 라우팅·Failover·시맨틱 라우팅 + 모니터링 구성
· LiteLLM Getting Started 설치 및 사용
· 'Client → LiteLLM GW/Proxy → vLLM ×2' 환경에서 마스킹·라우팅·Failover·Auto Routing + 모니터링 구성
· vLLM 벤치마크 실행 시 Nsight Systems/Compute와 PyTorch Profiler(CPU/CUDA 모드)로 프로파일링 후 분석
· vLLM에 Multi-Model(멀티모달) 서빙 실습
- 정의 — RLHF의 생성 단계에서 actor model(현재 정책)이 후보 응답을 대량 생성하고, 그것을 reward/reference 모델이 평가해 정책을 업데이트합니다.
- 성질 — 훈련 시간의 약 80%가 생성 단계입니다. 서빙이 느리면 훈련 워커가 놉니다.
- 쓰임 — 추론용으로 만들어진 vLLM·SGLang이 훈련 루프의 핵심 부품이 되었고, 여기에는 처리량뿐 아니라 배치 불변 결정론이 요구됩니다.
여섯 가지를 다 봤습니다. 마지막으로 이 기법들을 한 장에 모아 놓고, 언제 무엇을 고를지 정리합니다.
08다양한 LLM 서빙 최적화 기법 — 한자리에 모아보기
한 줄 요약: 기법을 외우는 것보다 "언제 쓰면 안 되는가"를 외우는 편이 오래 갑니다.
지금까지 스터디에서 나온 최적화 기법은 열 개가 넘습니다. 양자화, prefix caching, chunked prefill, speculative decoding, LMCache, 시맨틱 캐싱, Multi-LoRA, 텐서 병렬, 수평 확장… 각각은 이해했는데 막상 내 서비스 앞에 서면 무엇부터 켜야 할지가 안 보입니다.
답은 기법 목록이 아니라 워크로드 성격에 있습니다. 입력이 긴가 출력이 긴가, 반복이 많은가, 모델이 한 장에 들어가는가 — 이 세 질문이 대부분을 결정합니다.
- prefill 위주 (prefill-heavy)
- 입력이 길고 출력이 짧은 워크로드. RAG나 문서 요약이 여기 속합니다. 연산의 대부분이 입력을 읽는 데 쓰입니다.
- decode 위주 (decode-heavy)
- 입력이 짧고 출력이 긴 워크로드. 코드 생성이나 장문 작성이 여기 속합니다. 연산의 대부분이 토큰을 하나씩 뱉는 데 쓰입니다.
- 반복 트래픽
- 같은 prefix나 같은 뜻의 질문이 얼마나 자주 다시 들어오는가. 캐싱 계열 기법의 효과를 결정합니다.
- 테넌트 (tenant)
- 서로 다른 고객사·부서·용도. 각각 자기 파인튜닝 모델을 갖고 있으면 Multi-LoRA의 대상이 됩니다.
- 워크로드 프로파일
- 입출력 길이 분포·반복률·동시성을 묶어 부르는 말. 기법을 고르기 전에 먼저 재야 하는 것입니다(CH9 3·4장).
비유 — 공구함
공구함에 드라이버·펜치·렌치가 다 들어 있다고 해서 아무거나 꺼내 쓰지 않습니다. 나사 머리 모양을 먼저 보고 드라이버를 고릅니다.
서빙 최적화도 같습니다. 먼저 볼 것은 기법 목록이 아니라 내 트래픽의 모양입니다. 그리고 이 모양을 재는 도구가 3장에서 본 프로파일링입니다 — 그래서 프로파일링은 기법이 아니라 항상 맨 앞에 옵니다.
작은 숫자로 한 번
세 가지 흔한 서비스를 놓고 조합을 짜 봅시다.
내 워크로드면 무엇을 켤 것인가
↔ 슬라이더 2개 + 버튼어떤 조합에서도 양자화는 항상 켜져 있습니다. 나머지는 전부 조건부입니다 — 그래서 베이스라인부터 잡고 시작합니다(CH9 6장).
기법 카탈로그
스터디 전체에서 나온 기법을 한 표에 모았습니다. 오른쪽 두 칸 — "켜야 할 때"와 "쓰면 안 될 때" — 가 이 표의 핵심입니다.
| 기법 | 무엇을 줄이나 | 켜야 할 때 | 쓰면 안 될 때 | 어디서 봤나 |
|---|---|---|---|---|
| 프로파일링 | 잘못된 방향의 최적화 | 항상 맨 먼저. 무엇을 켤지 모를 때 | — | 이 페이지 3장 |
| 양자화 (AWQ·FP8) | 모델 가중치 메모리 | 거의 항상. 남는 메모리가 KV 캐시로 가 처리량이 오름 | 품질 저하를 감당할 수 없을 때 | CH9 7장 · 책 6장 |
| prefix caching | 반복되는 prefill 연산 | 시스템 프롬프트·공통 지시문이 긴 트래픽 | 요청이 전부 제각각이라 겹치는 앞부분이 없을 때 | CH9 3·6장 |
| chunked prefill | 긴 입력이 다른 요청을 막는 시간 | 아주 긴 입력이 섞여 들어올 때 | 입력이 짧고 고른 트래픽 | CH9 8장 |
| speculative decoding | decode 반복 횟수 | 출력이 긴 워크로드 | 출력이 짧거나 초안 모델 품질이 낮을 때 | CH9 8장 · 책 7장 |
| LMCache | 공유 컨텍스트의 KV 재계산 | 멀티턴 채팅·RAG처럼 컨텍스트를 공유할 때 | 요청 사이에 공유되는 컨텍스트가 없을 때 | CH9 8장 · 책 7장 |
| 시맨틱 캐싱 | LLM 호출 자체 | 표현은 달라도 뜻이 같은 질문이 반복될 때 | 트래픽이 적어 임베딩·벡터 DB 운영이 배보다 배꼽일 때 | 이 페이지 1·2장 |
| 시맨틱 라우팅 | 큰 모델을 부르는 비율 | 쉬운 질문과 어려운 질문이 섞여 들어올 때 | 질문 난이도가 균일할 때 | 이 페이지 1·2장 |
| Multi-LoRA | 파인튜닝 모델당 GPU 수 | 테넌트는 많고 각각의 트래픽은 적을 때 | 어댑터별 트래픽이 이미 GPU를 포화시킬 때 → 병합 후 독립 서빙 | 이 페이지 6장 |
| 텐서 병렬 (TP) | 요청당 지연시간, 모델 크기 제약 | 모델이 한 장에 안 들어가거나 TTFT를 줄여야 할 때 | 인터커넥트가 PCIe뿐이거나 목표가 처리량일 때 | CH9 9장 |
| 수평 확장 (복제) | — (총 처리량을 올림) | 목표가 처리량이고 모델이 한 장에 들어갈 때 | 요청 하나의 지연시간을 줄여야 할 때 | CH9 9·10장 |
| 프로세스 분리 (vLLM V1) | CPU 전처리가 GPU를 막는 시간 | 멀티모달, 또는 작은 모델을 큰 배치로 돌릴 때 | — (옵션이 아니라 구조적 개선) | 이 페이지 4장 |
| 모델 압축 (프루닝·증류) | 모델 크기 자체 | 엣지처럼 메모리가 절대적으로 부족할 때 | 품질 여유가 없을 때 | 이 페이지 5장 · 책 6장 |
| 열 인지 스케줄링 | 스로틀링으로 인한 성능 붕괴 | 팬 없는 엣지 기기 | 냉각이 충분한 데이터센터 | 이 페이지 5장 |
위에서 아래로 읽지 마세요. 첫 줄(프로파일링) → 둘째 줄(양자화)까지만 무조건이고, 그다음부터는 "쓰면 안 될 때" 칸을 먼저 읽어 해당되는 것을 지워 나가는 편이 빠릅니다. 남는 것이 여러분의 조합입니다.
- 정의 — 최적화 기법은 세 갈래입니다. 메모리를 줄이는 것(양자화·압축), 계산을 재사용하는 것(prefix·시맨틱 캐싱·LMCache), 일을 나누는 것(배칭·TP·복제·프로세스 분리).
- 성질 — 무조건 켜는 것은 프로파일링과 양자화뿐이고, 나머지는 전부 조건부입니다. 같은 "반복 트래픽"이라는 변수가 시맨틱 캐싱에는 유리하게, Multi-LoRA에는 불리하게 작동합니다.
- 쓰임 — 워크로드 성격(prefill/decode) · 반복률 · 모델 크기 세 질문에 답하면 조합이 거의 정해집니다. 기법 목록보다 "쓰면 안 될 때" 칸을 먼저 읽으세요.
마치며
처음 던진 질문으로 돌아갑니다. 이 여섯 주제의 공통점은 무엇인가?
첫째, 병목은 늘 GPU가 아닙니다. 멀티모달에서는 CPU 전처리가(4장), 프로파일링에서는 커널 사이의 유휴 간격이(3장), 엣지에서는 발열이(5장) 진짜 한계선이었습니다. 그리고 세 곳 모두 해법이 같은 모양이었습니다 — 서로 기다리게 만드는 것들을 떼어놓기. vLLM V1의 프로세스 분리도, CUDA 스트림으로 복사와 연산을 겹치는 것도, 엣지의 이기종 분업도 같은 패턴입니다.
둘째, 서빙 엔진이 결정을 떠맡기 시작했습니다. 시맨틱 라우터는 어떤 모델을 쓸지, Multi-LoRA는 어떤 어댑터를 쓸지, 엣지–클라우드 하이브리드는 어디서 실행할지, RLHF의 서빙 엔진은 같은 입력에 같은 출력을 낼지를 결정합니다. 예전의 추론 전용 엔진에는 없던 요구사항 — 결정론, 정책 집행, 의미 이해 — 이 여기서 생겨납니다.
셋째, 모든 기법에 "쓰면 안 되는 조건"이 붙어 있습니다. 시맨틱 캐싱은 트래픽이 적으면 배보다 배꼽이고, Multi-LoRA는 어댑터별 트래픽이 많으면 오히려 손해입니다. 같은 "트래픽 패턴"이라는 변수가 두 기법에서 정반대 방향으로 작동한다는 점이 특히 인상적입니다. 기법을 외우는 것보다 그 조건을 외우는 편이 오래 갑니다.
이 페이지는 CH10: Advancements in LLM Serving의 스터디 정리본입니다. 참고한 것은 vLLM Semantic Router, LiteLLM 라우팅 문서, PyTorch Profiler, vLLM 멀티모달 입력, vLLM LoRA Adapters, Punica 논문, OpenRLHF, 그리고 vLLM RLHF 문서입니다.
설명이 틀렸거나, 실제 운영에서 다르게 동작하는 부분이 있다면 알려주세요.
'AI > [LLMSO] Hands-On LLM 서빙과 최적화 스터디' 카테고리의 다른 글
| [7주차-LLMSO] Envoy: Agent Router (2026.09.13) (0) | 2026.09.20 |
|---|---|
| [6주차-LLMSO] Scaling LLM Inference with vLLM and AWS Trainium (2026.09.06) (1) | 2026.09.13 |
| [5주차-LLMSO]CH9. LLM Optimization in Practice (2026.08.30) (0) | 2026.09.05 |
| [4주차-LLMSO]CH8. LLM Serving Frameworks (2026.08.23) (0) | 2026.08.30 |
| [4주차-LLMSO]CH7. Advanced LLM Optimization Techniques (2026.08.23) (0) | 2026.08.30 |