페이지 목차
이 페이지에서 검색
로컬 LLM
이 페이지에 묻기
로컬 LLM · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.
생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.
LOCAL · LLM
로컬 LLM
생성 수정
로컬 모델 실행과 GPU·메모리 이해부터 서빙·RAG·도구 호출·업무형 앱 구현까지 차례로 살펴봅니다.
42개 문서 · 3일차 · 24 / 42
23차시 · vLLM 서버 성능 최적화
지도 위치 : 3일차 · ③추론 엔진의 손잡이 · 측정 → 조정 → 재측정 | 이전: 22차시 LLM Serving 성능 측정 | 다음: 24차시 Ollama와 vLLM 비교 키워드 : GPU Memory Utilization, Max Model Length, Batch · 동시성 설정
이 차시를 다 읽으면
- vLLM의 손잡이 일곱 개를 VRAM 예산식의 어느 항을 건드리는가 로 분류할 수 있다.
- 손잡이마다 기대 효과와 대가 를 한 줄로 말할 수 있다.
- 튜닝 루프 (SLO → 기준선 → 하나 바꾸기 → 재측정 → 기록)를 지키며 AI에게 튜닝을 맡길 수 있다.
- 문의 메일의 토큰 길이 분포 로
--max-model-len을 정하고, 넘치는 메일의 처리 방침을 세울 수 있다. - 바꾼 이유와 결과를 결정 기록 으로 남길 수 있다.
0. 이 차시의 판별 축
| # | 축 | 왼쪽 (0) | 오른쪽 (1) | 이 축으로 갈리는 것 | 큰 축 (README 5장) |
|---|---|---|---|---|---|
| 1 | 무엇을 내주고 무엇을 얻나 | 품질 · 길이 · 여유 | 속도 · 동시 수용량 | 손잡이마다의 거래 | 트레이드오프 (README 7장 문장 2) · 정밀도 (파생 축) |
| 2 | 감인가, 숫자인가 | "빨라진 것 같다" | 기준선 대비 측정값 | 튜닝 결과를 믿을 수 있는가 README 9장 — 출력 원문이 붙은 숫자만 믿는다 | |
| 3 | 한 번에 몇 개 바꾸나 | 여러 개 한꺼번에 | 하나씩 | 무엇 때문에 변했는지 아는가 | 14차시 측정 규칙 |
앞에서 이어집니다 — 19차시 2.3에서 "24GB에 Qwen3-8B BF16, 8192 토큰이면 최대 길이 기준 동시 3개 남짓"이라는 이론 계산을 했고, 22차시에서 SLO와 결과표를 만들었습니다. 이 차시는 그 둘 사이를 손잡이로 메웁니다. README 7장 문장 1(모든 것은 VRAM 예산 싸움) 과 문장 2(셋 다 가질 수 없다, 측정해서 고른다) 가 동시에 쓰이는 자리입니다.
1. 손잡이 — 예산식의 어디를 건드리는가
1.1 예산식에 손잡이를 꽂으면
GPU 전체 × --gpu-memory-utilization ............................. ① 예산 전체
= 가중치 ................................................... ⑤ --quantization (양자화 모델)
+ 오버헤드 (활성값 · CUDA 등) ................................ ④ --max-num-batched-tokens 가 영향
+ KV 캐시 풀
→ 풀에 들어가는 토큰 수 = 풀 ÷ 토큰당 KV ............... ⑥ --kv-cache-dtype fp8
→ 요청 하나의 상한 ..................................... ② --max-model-len
→ 한 스텝에 함께 도는 요청 수 ........................... ③ --max-num-seqs
→ 같은 앞부분 재사용 ................................... ⑦ --enable-prefix-caching
1.2 손잡이 표
| # | 손잡이 | 예산식의 어느 항 | 기대 효과 | 대가 | 확인할 지표 |
|---|---|---|---|---|---|
| ① | --gpu-memory-utilization (예: 0.90 → 0.95) | 예산 전체 | KV 풀↑ | 여유↓, 메모리 부족 위험. 같은 GPU에 다른 프로세스 불가 | 기동 로그의 KV 크기, 장시간 안정성 |
| ② | --max-model-len (예: 8192 → 4096) | 요청 하나의 상한 | 최대 길이 기준 동시 수용량↑ | 긴 메일을 못 받음 (3절) | 로그의 Maximum concurrency, 거절된 요청 수 |
| ③ | --max-num-seqs | 한 스텝의 요청 수 상한 | 낮추면 선점 · 꼬리 지연↓, 높이면 처리량↑ 여지 | 낮추면 처리량 상한↓, 높이면 KV 경쟁 · 선점↑ | 실행 중 · 대기 요청 수, preempt 로그 |
| ④ | --max-num-batched-tokens | 한 스텝에 처리할 토큰 상한 | 높이면 Prefill이 빨리 끝나 TTFT↓ 여지 | 활성값 메모리↑, 진행 중 Decode의 TPOT 흔들림 | TTFT · TPOT |
| ⑤ | --quantization (AWQ · GPTQ · FP8 사전 양자화 모델 ) | 가중치 | 가중치↓ → KV 풀 크게↑ , Decode 빨라질 여지 (15차시) | 품질 (평가셋 필수), GPU 지원 여부 (FP8은 최신 GPU) | 평가셋 점수, 로그의 가중치 메모리 |
| ⑥ | --kv-cache-dtype fp8 | 토큰당 KV (2바이트 → 1바이트) | 풀에 들어가는 토큰 수 ≈ 2배 | 품질 영향 가능, 지원 여부 | 평가셋 점수, 로그의 KV 토큰 수 |
| ⑦ | --enable-prefix-caching | KV 재사용 | 공통 시스템 프롬프트의 TTFT↓ (21차시 4절) | 거의 없음 | TTFT |
- ⑤는 대개 모델 자체를 바꾸는 손잡이입니다. Hugging Face의 사전 양자화 저장소(예: 모델 이름 뒤에
-AWQ,-FP8이 붙은 것 — 실제 존재와 이름은 Hugging Face에서 확인)를 받으면 vLLM이 형식을 대개 자동 인식 합니다. - ⑦은 최신 버전에서 기본 활성 일 수 있습니다.
- GPU가 여러 장이면
--tensor-parallel-size로 모델을 나눠 올립니다. 이 과정의 기준 환경은 한 장입니다. - ⚠️ 이름 · 기본값 · 지원 범위는 버전에 따라 다릅니다.
vllm serve --help와 공식 문서가 기준입니다.
1.3 이론 계산으로 손잡이 비교 — 실측 아님
19차시 2.3의 계산을 이어 갑니다. 조건: RTX 4090 24GB, --gpu-memory-utilization 0.90(≈ 21.6GB), 오버헤드 1~2GB, Qwen3-8B(36층 · KV 헤드 8 · head_dim 128, config.json에서 확인). 모든 값은 어림 계산 이고, 진짜 값은 기동 로그에서 확인합니다.
| 구성 | 가중치 (≈) | KV 풀 (≈) | 토큰당 KV | 풀의 토큰 수 (≈) | 8192 기준 동시 (≈) |
|---|---|---|---|---|---|
| 기준선: BF16 | 16.4GB | 3.2 ~ 4.2GB | 144KB | 2.2만 ~ 2.8만 | 2.7 ~ 3.5 |
| 기준선 + KV FP8 (⑥) | 16.4GB | 3.2 ~ 4.2GB | 72KB | 4.3만 ~ 5.7만 | 5.3 ~ 7 |
| FP8 가중치 모델 (⑤) | 8.2GB | 11.4 ~ 12.4GB | 144KB | 7.7만 ~ 8.4만 | 9.4 ~ 10.3 |
| FP8 가중치 + KV FP8 (⑤+⑥) | 8.2GB | 11.4 ~ 12.4GB | 72KB | 15만 ~ 17만 | 19 ~ 20 |
(②로 --max-model-len을 4096으로 줄이면 마지막 열은 같은 풀에서 두 배 가 됩니다.)
⭐ 읽는 법: 24GB에서 8B를 BF16으로 올리면 가중치가 예산의 3/4 을 먹습니다. 그래서 가장 큰 손잡이는 ⑤(가중치)입니다. 단, ⑤와 ⑥은 품질을 내주는 손잡이 라서 15 · 16차시처럼 평가셋을 통과해야만 채택합니다. README 문장 2 그대로입니다.
2. 튜닝 루프 — 하나 바꾸고, 다시 잰다
① SLO 정하기 (22차시 5절) 예: 동시 10명, TTFT p95 < 1초
↓
② 기준선 측정 (22차시 결과표) 기동 명령 원문 + 결과표 + 평가셋 점수
↓
③ 손잡이 하나만 바꾸기 ◀──────────────┐
↓ │
④ 같은 조건으로 재측정 │ SLO 미달이면 다음 손잡이
(속도는 22차시 표, 품질은 평가셋) │
↓ │
⑤ 결정 기록 (4절) ──────────────────────┘
↓
SLO 통과 + 품질 유지 → 멈춤
| 규칙 | 이유 |
|---|---|
| 한 번에 하나 | 둘을 같이 바꾸면 무엇이 효과였는지 모름 (0절 축 3) |
| 품질 손잡이(⑤ · ⑥)는 속도와 평가셋을 둘 다 잰다 | 빨라졌지만 분류가 틀리면 실패 |
| 입력은 실제 문의 로 | 무작위 입력에서 좋아진 것이 서비스에서도 좋아진다는 보장이 없음 (22차시 2.2) |
| SLO를 통과하면 멈춘다 | 더 돌리면 복잡도와 품질 위험만 늘어남 |
| 되돌릴 수 있게 | 기동 명령을 버전별로 남김 (4절) |
⚠️ 반례 — "손잡이를 전부 최대로 돌리면 가장 빠르다." ❌ ①을 0.98로 올리면 장시간 운영 중 메모리 부족으로 죽을 수 있고, ③을 무작정 올리면 선점이 늘어 꼬리 지연이 나빠지고(21차시 5절), ⑤ · ⑥을 겹치면 품질이 함께 떨어질 수 있습니다.
💡 AI에게 맡기면 "옵션 몇 개를 조정해 성능을 개선했습니다"라는 보고가 오기 쉽습니다. README 9장대로 "무엇을 하나 바꿨고, 기준선 대비 어느 칸이 얼마에서 얼마로" 를 원문과 함께 받습니다.
3. 문의봇 시나리오 — 메일 길이로 --max-model-len 정하기
3.1 필요한 길이는 무엇의 합인가
2차시 3절의 식 그대로입니다.
--max-model-len ≥ 시스템 프롬프트 + (대화 기록) + 문의 본문 + 출력 max_tokens + 여유
"모델이 몇 토큰까지 되나"가 아니라 "우리 문의가 얼마나 긴가" 로 정합니다(19차시 4절).
3.2 절차
- 평가셋 또는 최근 실제 문의(가명 처리) 수백 건을 모델의 토크나이저로 토큰 수를 잽니다(2차시 실습). 글자 수로 재면 안 됩니다.
- 분포를 봅니다. 평균이 아니라 p95 · p99 · 최대 가 중요합니다.
- 시스템 프롬프트 토큰 수와 출력
max_tokens를 더하고 여유를 둡니다.
| 항목 | 토큰 수 (직접 측정해서 채움) |
|---|---|
| 시스템 프롬프트 | |
| 문의 본문 p50 / p95 / p99 / 최대 | |
출력 max_tokens (요약 · 분류 기준) | |
| 여유 (10~20%) | |
→ --max-model-len 후보 |
계산 모양만 보이면 이렇습니다( 가상의 숫자 , 실측 아님). 시스템 1,200 + 문의 p99 2,000 + 출력 300 = 3,500 → 여유를 두고 4096 . 이렇게 되면 8192일 때보다 최대 길이 기준 동시 수용량이 두 배 가 됩니다(1.3).
3.3 p99를 넘는 메일은 어떻게 하나 — 결정이 필요하다
--max-model-len을 줄이는 순간 "아주 긴 메일"의 처리 방침 이 생겨야 합니다. 이 결정은 엔진이 아니라 API 서버 (17차시 2.2)에서 합니다.
| 방침 | 장점 | 위험 |
|---|---|---|
| 길이 검사 후 거절 + 안내 ("메일이 길어 자동 요약이 안 됩니다") | 단순, 틀린 요약이 없음 | 상담원이 직접 읽어야 함 |
| 앞부분만 잘라 요약 | 항상 결과가 나옴 | ⚠️ 2차시 3절: 잘린 부분에 주문번호가 있으면 그럴듯한 오답 |
| 나눠 요약한 뒤 합치기 | 긴 메일도 처리 | 요청 수 · 지연↑, 구현 복잡 |
⭐ 어느 쪽이든 조용히 잘리는 것 만은 막습니다. vLLM은 넘치는 요청을 대개 에러로 거절 하므로(20차시 2.3) 앱이 그 에러와 finish_reason: "length"를 처리해야 합니다.
4. 결정 기록
튜닝은 몇 달 뒤 반드시 " 왜 4096이지? ", " 왜 이 모델이 FP8이지? "라는 질문을 받습니다. 1차시 3.1의 통제와 재현성 을 지키려면 숫자와 이유가 함께 남아 있어야 합니다.
결정 기록 — [기술 문서]인데, [ 무엇을 정했는지만이 아니라 그때의 맥락 · 근거 · 대가 · 결과를 한 장에 남겨, 나중 사람이 같은 판단을 다시 따라갈 수 있게 한다 ]는 점에서 바뀐 값만 남는 설정 파일 · 변경 이력과 구별된다. 소프트웨어 팀에서는 흔히 ADR(Architecture Decision Record)이라는 이름으로 씁니다. 이 과정에서는 아래 양식 하나면 충분합니다.
## 결정: vLLM 기동 옵션 v3 (YYYY-MM-DD)
- 맥락: SLO(동시 10명 TTFT p95 < 1초) 미달. 기준선 동시 10에서 TTFT p95 = ___ (22차시 결과표 #__)
- 바꾼 것 (하나): --max-model-len 8192 → 4096
- 근거: 문의 토큰 분포 p99 = ___ (측정 파일: ___)
- 결과: 동시 10 TTFT p95 ___ → ___ / 출력 처리량 ___ → ___ / Maximum concurrency ___ → ___
- 대가: p99 초과 문의 ___% → 처리 방침: 거절 + 안내
- 품질: (품질 손잡이일 때) 평가셋 분류 정확도 ___ → ___
- 결정: 채택 / 보류 / 되돌림
- 기동 명령 (원문):
| 칸 | 왜 필요한가 |
|---|---|
| 맥락 · 근거 | 다음 사람이 같은 실험을 반복하지 않게 |
| 바꾼 것 (하나) | 효과의 원인을 한 줄로 귀속 |
| 대가 | 얻은 것만 적으면 트레이드오프가 사라짐 |
| 기동 명령 원문 | 되돌릴 수 있게. 19차시의 systemd 유닛 · Docker 명령과 같이 버전 관리 |
앞으로 다시 만납니다 — 5일차 34차시(모델 선정 및 최적화)와 39차시(성능 테스트 및 최적화)에서 이 결정 기록이 그대로 프로젝트 산출물이 됩니다.
5. 실습 — 맡기고 검수하기
지시
22차시 결과표를 기준선으로 vLLM 기동 옵션을 튜닝해줘.
맥락: vllm serve --help 출력과 공식 문서의 최적화/튜닝 페이지를 근거로. 기억으로 옵션 이름을 쓰지 마.
SLO: 동시 10명, 실제 문의 세트, max_tokens 200, TTFT p95 < 1초.
제약:
- 한 번에 옵션 하나만 바꿀 것. 바꿀 때마다 22차시와 같은 조건으로 동시성 8 · 10 · 16을 재측정.
- 양자화 모델이나 --kv-cache-dtype을 바꾸는 단계에서는 평가셋(첨부, 50건)의 분류 정확도도 함께 잴 것.
- --gpu-memory-utilization은 0.95를 넘기지 말 것.
- 먼저 문의 세트의 토큰 수 분포(p50/p95/p99/최대)를 Qwen3-8B 토크나이저로 재서 --max-model-len 후보를 제안할 것.
보고 형식:
1) [시도 # | 바꾼 옵션 (전 → 후) | 기동 로그의 KV 토큰 수 · Maximum concurrency | 동시 10 TTFT p95 | 처리량 | 평가셋 정확도 | 판정] 표
2) 채택한 시도마다 4절 양식의 결정 기록
SLO를 통과하면 거기서 멈추고 보고해. 추측하지 말고 실행 출력 원문을 붙여.
받을 증거
- 토큰 분포 측정 결과 원문
- 시도마다 기동 명령 원문, 기동 로그 세 줄(19차시 2.1), 측정 출력 원문
- 결정 기록
내가 직접 볼 것
| 볼 것 | 이걸로 아는 것 / 왜 내가 보는가 |
|---|---|
| 시도마다 바꾼 옵션이 정말 하나 인가 (기동 명령 원문끼리 비교) | 원인 귀속이 가능한가 |
| Maximum concurrency 변화가 1.3의 방향과 맞는가 | 이론과 실제가 크게 다르면 조건을 다시 확인 |
| 품질 손잡이 단계의 평가셋 정확도 | 빨라졌지만 틀리기 시작했는가. 결정은 내가 |
| p99 초과 문의의 비율과 처리 방침 | 기술이 아니라 업무 결정 (3.3) |
| SLO 통과 후에도 계속 돌렸는가 | 멈출 줄 아는 루프인가 (2절) |
부록 A. 스스로 확인하기
| # | 질문 | 답이 있는 곳 |
|---|---|---|
| 1 | 손잡이 일곱 개는 각각 예산식의 어느 항을 건드리는가? | 1.1, 1.2 |
| 2 | --max-num-seqs를 낮추면 얻는 것과 잃는 것은? | 1.2 |
| 3 | 24GB에서 8B BF16일 때 가장 큰 손잡이가 가중치인 이유는? | 1.3 |
| 4 | 양자화 · KV FP8 손잡이에만 붙는 조건은? | 1.3, 2 |
| 5 | 튜닝 루프의 다섯 단계와 멈출 조건은? | 2 |
| 6 | --max-model-len을 정하는 식과 재는 단위는? | 3.1, 3.2 |
| 7 | p99를 넘는 메일의 처리 방침 세 가지와 위험은? | 3.3 |
| 8 | 결정 기록에 "대가" 칸이 꼭 있어야 하는 이유는? | 4 |
부록 B. 자주 하는 실수
| 실수 | 바로잡기 |
|---|---|
| 옵션 여러 개를 한꺼번에 바꿈 | ❌ 무엇이 효과였는지 모름. 하나씩 |
--max-model-len을 모델 최대치로 | ⚠️ 우리 문의 길이 분포로 정함 |
| 양자화 모델로 바꾸고 속도만 잼 | ❌ 평가셋 도 같이 |
--gpu-memory-utilization 0.99 | ⚠️ 여유가 없어 운영 중 죽을 수 있음 |
| 긴 메일을 조용히 잘라 요약 | ❌ 앞부분 고객 정보 손실 위험. 방침을 정하고 알림 |
| 결과만 기록하고 기동 명령은 안 남김 | ❌ 되돌릴 수 없음 |
| SLO를 통과했는데 계속 튜닝 | ⚠️ 복잡도 · 품질 위험만 늘어남 |
부록 C. NotebookLM 복습 프롬프트
이 23차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"손잡이와 VRAM 예산식의 대응", "튜닝 루프에서 하나씩 바꾸는 이유", "메일 길이 분포로 max-model-len 정하기", "결정 기록의 대가 칸"은 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.
LangTailor