- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며 — 로컬 LLM이 다시 뜨는 이유
- 하드웨어 선택 — VRAM 중심으로 사고하라
- 양자화 포맷 — GGUF, 4bit, AWQ, GPTQ
- 추론 엔진 비교 — llama.cpp vs vLLM vs Ollama
- KV cache와 컨텍스트 길이의 메모리 산수
- VRAM 예산별 현실적 구성 가이드
- 오프로딩 전략 — 부족한 VRAM과 싸우는 법
- 서빙 설정 예제
- 멀티 GPU — 한 장으로 모자랄 때
- 성능 측정 방법론 — 감이 아니라 숫자로
- 흔한 함정
- 마치며
- 참고 자료
들어가며 — 로컬 LLM이 다시 뜨는 이유
2026년 상반기, 로컬 LLM 커뮤니티가 다시 뜨겁습니다. 해커뉴스에서는 GPU의 남는 VRAM을 리눅스 스왑 장치로 쓰는 nbd-vram 같은 역발상 프로젝트가 화제가 되었고, GeekNews에도 로컬 추론 최적화 글이 꾸준히 올라옵니다. 몇 가지 흐름이 겹친 결과입니다.
첫째, 프라이버시입니다. 코드와 문서, 일기까지 LLM에 넣는 시대가 되면서, 민감한 데이터를 외부 API로 보내는 것에 대한 거부감이 커졌습니다. npm 공급망 공격이 Red Hat Cloud Services까지 침투한 2026년 6월의 사건이나 VSCode 확장 버그로 GitHub 토큰이 탈취된 사례는 "내 데이터는 내 머신에"라는 정서를 강화했습니다.
둘째, 비용입니다. AI 코딩 에이전트가 보편화되면서 토큰 소비량이 폭증했습니다. 에이전트가 수 시간씩 자율 작업을 돌리는 워크플로에서는 API 청구서가 무시할 수 없는 수준이 되고, 반복적인 보조 작업을 로컬 모델로 돌리려는 수요가 생겼습니다.
셋째, 빅테크 피로감입니다. DuckDuckGo의 no-AI 검색 트래픽 급증과 Gmail 이탈 흐름이 보여주듯, 모든 것이 클라우드 AI로 수렴하는 데 대한 반작용이 분명히 존재합니다. 로컬 LLM은 이 정서의 기술적 출구입니다.
마침 하드웨어와 소프트웨어도 준비됐습니다. 통합 메모리를 큰 폭으로 늘린 소비자 하드웨어, 성숙한 양자화 생태계, 그리고 llama.cpp와 vLLM이라는 두 축의 추론 엔진이 그것입니다. 이 글은 로컬 인퍼런스 최적화의 전체 지도를 그립니다.
하드웨어 선택 — VRAM 중심으로 사고하라
로컬 LLM 하드웨어 선택의 제1원칙은 단순합니다. 연산 속도보다 메모리 용량과 대역폭이 먼저라는 것입니다. 모델이 메모리에 들어가지 않으면 아무리 빠른 GPU도 소용없고, 들어간 뒤의 토큰 생성 속도는 대체로 메모리 대역폭이 결정합니다.
토큰 생성 속도의 1차 근사:
토큰/초 ~= 메모리 대역폭 (GB/s) / 모델 크기 (GB)
예: 양자화 후 5GB 모델
- 대역폭 100 GB/s (CPU DDR5 듀얼채널) -> 약 20 토큰/초
- 대역폭 400 GB/s (Apple M 시리즈 Max) -> 약 80 토큰/초
- 대역폭 1000 GB/s (하이엔드 dGPU) -> 약 200 토큰/초
선택지는 크게 두 갈래입니다.
| 항목 | 통합 메모리 (Apple Silicon, Strix Halo 류) | 디스크리트 GPU (RTX 류) |
|---|---|---|
| 메모리 용량 | 큼 (64GB~512GB) | 작음 (16GB~32GB가 일반적) |
| 메모리 대역폭 | 중간 (200~800 GB/s) | 높음 (800~1700 GB/s) |
| 큰 모델 적재 | 70B 이상도 양자화로 가능 | 단일 카드로는 어려움 |
| 생성 속도 | 중간 | 빠름 |
| 프롬프트 처리 속도 | 상대적으로 느림 | 매우 빠름 |
| 전력/소음 | 낮음 | 높음 |
| 확장성 | 불가 (구매 시 결정) | 멀티 GPU로 확장 가능 |
요약하면, 큰 모델을 적당한 속도로 돌리고 싶으면 통합 메모리, 중간 모델을 최고 속도로 돌리고 싶으면 dGPU입니다. 긴 문서를 자주 넣는 워크로드(RAG, 코드베이스 분석)라면 프롬프트 처리 속도가 빠른 dGPU의 체감 이점이 크고, 대화 위주라면 통합 메모리의 용량 이점이 큽니다.
모델이 차지하는 메모리의 어림 계산은 다음과 같습니다.
모델 가중치 메모리 (대략):
fp16: 파라미터 수 x 2 바이트
8bit (Q8): 파라미터 수 x 1 바이트 + 약간의 오버헤드
4bit (Q4): 파라미터 수 x 0.5 바이트 + 약간의 오버헤드
예: 8B 모델 -> fp16 16GB / Q8 8.5GB / Q4 4.7GB
예: 70B 모델 -> fp16 140GB / Q8 75GB / Q4 40GB
여기에 KV cache와 활성화 메모리가 추가됨 (아래 절 참고)
양자화 포맷 — GGUF, 4bit, AWQ, GPTQ
양자화는 가중치를 낮은 정밀도로 표현해 메모리와 대역폭 요구량을 줄이는 기술입니다. 로컬 LLM에서는 사실상 필수입니다.
GGUF — llama.cpp 생태계의 표준
GGUF는 llama.cpp가 사용하는 단일 파일 포맷입니다. 가중치, 토크나이저, 메타데이터가 한 파일에 담겨 배포가 간편합니다. 양자화 수준은 파일명 접미사로 구분합니다.
| 양자화 | 비트 수준 | 8B 모델 크기 | 품질 영향 |
|---|---|---|---|
| Q8_0 | 8비트 | 약 8.5GB | 거의 무손실 |
| Q6_K | 6비트대 | 약 6.6GB | 매우 작음 |
| Q5_K_M | 5비트대 | 약 5.7GB | 작음 |
| Q4_K_M | 4비트대 | 약 4.9GB | 체감 어려운 수준 (권장 기본값) |
| Q3_K_M | 3비트대 | 약 4.0GB | 작업에 따라 체감됨 |
| Q2_K | 2비트대 | 약 3.2GB | 뚜렷한 저하, 비상용 |
커뮤니티의 경험칙은 명확합니다. 같은 메모리라면 작은 모델의 고정밀보다 큰 모델의 4비트가 대체로 낫다는 것입니다. 예컨대 8GB 예산에서 8B Q8보다 14B Q4가 더 나은 결과를 내는 경우가 많습니다.
AWQ와 GPTQ — GPU 서빙 진영의 양자화
vLLM 같은 GPU 서빙 엔진에서는 AWQ와 GPTQ 계열이 주류입니다.
- GPTQ: 보정 데이터셋을 흘려보내며 레이어별로 양자화 오차를 최소화하는 사후 양자화. 4비트에서 좋은 품질을 보입니다.
- AWQ: 활성화 값 분포를 관찰해 중요한 가중치 채널을 보호하면서 양자화하는 방식. 보정 의존성이 낮고 품질 유지가 좋아 4비트 GPU 서빙의 기본 선택지가 되었습니다.
- FP8: 최신 GPU의 하드웨어 지원을 받는 8비트 부동소수점. 처리량 서빙에서 빠르게 표준이 되는 중입니다.
요약하면, llama.cpp로 돌리면 GGUF의 Q4_K_M 부터, vLLM으로 돌리면 AWQ 4bit 또는 FP8부터 시작하는 것이 무난합니다.
추론 엔진 비교 — llama.cpp vs vLLM vs Ollama
| 항목 | llama.cpp | vLLM | Ollama |
|---|---|---|---|
| 주 타깃 | 개인 머신, 엣지 | GPU 서버, 팀/프로덕션 | 개인 머신 (간편함 우선) |
| 하드웨어 | CPU, Apple Silicon, GPU 모두 | NVIDIA/AMD GPU 중심 | llama.cpp 기반과 동일 |
| 모델 포맷 | GGUF | HF safetensors, AWQ, GPTQ, FP8 | GGUF (내부적으로 llama.cpp) |
| 동시 처리 | 제한적 (소수 슬롯) | 강력 (연속 배칭, PagedAttention) | 제한적 |
| CPU 오프로딩 | 강력 (레이어 단위) | 제한적 | 지원 (자동) |
| API | OpenAI 호환 서버 내장 | OpenAI 호환 서버 내장 | 자체 API + OpenAI 호환 |
| 운영 난이도 | 중간 (빌드/플래그 이해 필요) | 중간~높음 | 매우 낮음 |
| 어울리는 사용자 | 튜닝을 즐기는 파워유저 | 처리량이 필요한 팀 | 일단 써보고 싶은 입문자 |
선택 기준을 한 줄씩으로 줄이면 다음과 같습니다.
- Ollama: 5분 안에 시작하고 싶다. 세부 튜닝은 나중 문제.
- llama.cpp: 내 하드웨어에서 마지막 한 방울까지 짜내고 싶다. VRAM이 부족해 오프로딩이 필요하다.
- vLLM: 여러 사용자나 에이전트가 동시에 때리는 서버가 필요하다. GPU가 모델을 통째로 담을 수 있다.
같은 머신에서도 용도가 다르면 둘을 함께 쓰는 구성이 흔합니다. 평소엔 Ollama로 가볍게, 팀 데모 때는 vLLM으로 처리량을 뽑는 식입니다.
KV cache와 컨텍스트 길이의 메모리 산수
로컬 LLM에서 가장 자주 부딪히는 벽은 모델 가중치가 아니라 KV cache입니다. 컨텍스트가 길어질수록 토큰마다 어텐션의 키와 값을 저장해야 하고, 이것이 VRAM을 갉아먹습니다.
계산 공식은 다음과 같습니다.
def kv_cache_bytes(n_layers, n_kv_heads, head_dim, seq_len,
batch=1, bytes_per_elem=2):
"""KV cache 메모리 (K와 V 두 텐서이므로 x2).
bytes_per_elem: fp16/bf16=2, q8=1, q4=0.5
"""
return 2 * n_layers * n_kv_heads * head_dim * seq_len * batch * bytes_per_elem
# 예 1: 8B급 모델 (32레이어, KV헤드 8, head_dim 128, fp16)
per_token = kv_cache_bytes(32, 8, 128, 1)
print(per_token) # 131072 바이트 = 토큰당 128KB
print(kv_cache_bytes(32, 8, 128, 8192) / 2**30) # 8k 컨텍스트: 1.0GB
print(kv_cache_bytes(32, 8, 128, 32768) / 2**30) # 32k 컨텍스트: 4.0GB
print(kv_cache_bytes(32, 8, 128, 131072) / 2**30) # 128k 컨텍스트: 16.0GB
# 예 2: 70B급 모델 (80레이어, KV헤드 8, head_dim 128, fp16)
print(kv_cache_bytes(80, 8, 128, 32768) / 2**30) # 32k 컨텍스트: 10.0GB
이 산수가 알려주는 실전 감각은 이렇습니다.
- 8B 모델을 Q4로 받으면 가중치는 5GB 남짓이지만, 128k 컨텍스트를 쓰는 순간 KV cache가 16GB로 가중치의 3배가 됩니다. "모델은 들어가는데 컨텍스트를 늘리면 죽는" 이유가 이것입니다.
- 동시 사용자(배치)가 늘면 KV cache는 정비례로 늘어납니다. 멀티 에이전트가 동시에 붙는 로컬 서버에서 컨텍스트 한도를 보수적으로 잡아야 하는 이유입니다.
- 대응 수단은 세 가지입니다. KV cache 양자화(fp16 대신 q8/q4로 절반~4분의 1), GQA가 강한 모델 선택(KV 헤드 수가 적을수록 유리), 그리고 컨텍스트 한도 설정입니다.
llama.cpp에서 KV cache를 양자화하려면 다음과 같이 합니다.
# KV cache를 q8로: 메모리 절반, 품질 영향 미미
llama-server -m model-q4_k_m.gguf \
--ctx-size 32768 \
--cache-type-k q8_0 \
--cache-type-v q8_0
VRAM 예산별 현실적 구성 가이드
가중치와 KV cache 산수를 합치면, 메모리 예산별로 현실적인 구성이 나옵니다.
| 메모리 예산 | 무난한 구성 | 컨텍스트 여유 | 용도 감각 |
|---|---|---|---|
| 8GB | 7~8B 모델 Q4 | 8k 내외 | 가벼운 보조, 요약, 분류 |
| 12GB | 8B Q6 또는 14B Q4 | 8k~16k | 일상 코딩 보조의 하한선 |
| 16GB | 14B Q4 + KV q8 | 16k~32k | 코딩/문서 작업 실용 구간 |
| 24GB | 32B Q4 또는 14B 고정밀 | 32k | 로컬 단독으로 충분한 첫 구간 |
| 48GB (2장 또는 통합) | 70B급 Q4 | 16k~32k | API 의존도를 크게 낮추는 구간 |
| 96GB 이상 (통합) | 70B 고정밀, 대형 MoE Q4 | 64k 이상 | 로컬 워크스테이션의 끝판 |
두 가지 보정이 필요합니다. 첫째, 표의 컨텍스트 여유는 KV cache를 q8로 양자화했을 때 기준입니다. 둘째, MoE 모델은 같은 총 파라미터라도 활성 파라미터가 작아 생성 속도가 훨씬 빠르므로, 통합 메모리 머신에서는 대형 MoE의 Q4가 동급 덴스 모델보다 체감이 좋은 경우가 많습니다.
모델 계열 선택은 단순화하면 이렇습니다. 코딩 보조라면 코드 특화 파인튜닝 모델을, 다국어(한국어 포함) 품질이 중요하면 다국어 토크나이저가 좋은 계열을, 에이전트 용도라면 도구 호출(tool calling) 형식을 공식 지원하는 모델을 우선 후보로 두고, 반드시 자기 작업 샘플 10~20개로 직접 비교하세요. 리더보드 순위는 참고일 뿐입니다.
오프로딩 전략 — 부족한 VRAM과 싸우는 법
정공법: 레이어 단위 CPU 오프로딩
llama.cpp의 대표 기능입니다. 모델 레이어 일부만 GPU에 올리고 나머지는 CPU 메모리에서 실행합니다.
# 70B Q4 모델 (약 40GB)을 24GB GPU에서:
# 80레이어 중 48개만 GPU에, 나머지는 CPU에
llama-server -m llama-70b-q4_k_m.gguf \
--n-gpu-layers 48 \
--ctx-size 8192 \
--threads 16
경험칙은 "GPU에 올라간 레이어 비율만큼 빨라진다"가 아니라 CPU에 남은 레이어가 전체 속도를 지배한다입니다. 절반만 올리면 GPU가 아무리 빨라도 CPU 속도에 수렴합니다. 그래도 "아예 못 돌리는 모델을 돌릴 수 있게" 해주는 가치는 큽니다. MoE 모델이라면 전문가(expert) 가중치만 CPU로 보내는 옵션이 효과적입니다. 활성 전문가만 그때그때 쓰이므로 체감 저하가 작습니다.
# MoE 모델: 어텐션 등 공용 가중치는 GPU에, 전문가 FFN은 CPU에
llama-server -m moe-model-q4.gguf \
--n-gpu-layers 99 \
--n-cpu-moe 30
역발상: 남는 VRAM을 시스템 스왑으로 — nbd-vram
2026년 해커뉴스를 달군 nbd-vram은 발상을 뒤집습니다. "VRAM이 부족해 시스템 메모리를 빌려 쓰는" 것이 아니라, 놀고 있는 VRAM을 리눅스 블록 디바이스로 노출해 스왑이나 램디스크로 쓰는 프로젝트입니다. 네트워크 블록 디바이스(NBD) 프로토콜로 GPU 메모리를 묶어, 커널 입장에서는 그냥 빠른 디스크처럼 보이게 합니다.
일반적 발상: 모델이 VRAM보다 큼 -> RAM/디스크로 오프로딩
nbd-vram: RAM이 부족함 -> 남는 VRAM을 스왑으로 활용
+--------+ NBD 프로토콜 +-----------------+
| 리눅스 | <------------------> | GPU VRAM |
| 커널 | (블록 디바이스) | (CUDA 버퍼) |
| 스왑 | | |
+--------+ +-----------------+
PCIe를 거치므로 진짜 RAM보다는 느리지만 NVMe 스왑보다는 훨씬 빠릅니다. 게이밍 GPU가 놀고 있는 워크스테이션에서 메모리 폭식 작업(대규모 데이터 처리, 컴파일)을 돌릴 때 의외로 실용적이라는 평이 많았습니다. 로컬 LLM과 직접 결합하면, CPU 추론 중인 거대 모델의 일부 페이지가 VRAM 스왑에 얹히는 묘한 구성도 가능합니다. 기술적 정합성보다 중요한 것은 이 프로젝트가 보여주는 태도입니다. VRAM, RAM, 디스크는 고정된 역할이 아니라 속도가 다른 메모리 계층일 뿐이며, 조합은 우리가 정한다는 것입니다.
서빙 설정 예제
llama.cpp 서버 — 단일 머신 파워유저용
# 빌드 (CUDA 예시)
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j
# OpenAI 호환 서버 기동
./build/bin/llama-server \
-m models/qwen2.5-14b-q4_k_m.gguf \
--host 0.0.0.0 --port 8080 \
--ctx-size 16384 \
--n-gpu-layers 99 \
--flash-attn \
--cache-type-k q8_0 --cache-type-v q8_0 \
--parallel 2
Ollama — 가장 빠른 시작점
# 설치 후 모델 받기와 실행이 한 줄
ollama pull qwen2.5:14b
ollama run qwen2.5:14b
# 커스텀 설정은 Modelfile로
cat > Modelfile <<'EOF'
FROM qwen2.5:14b
PARAMETER num_ctx 16384
PARAMETER temperature 0.7
SYSTEM 당신은 간결하게 답하는 코딩 어시스턴트입니다.
EOF
ollama create my-coder -f Modelfile
ollama run my-coder
Ollama는 내부적으로 llama.cpp를 쓰므로 성능 특성은 비슷하지만, 기본값이 보수적입니다. 특히 num_ctx 기본값이 작아서 긴 대화에서 조용히 컨텍스트가 잘리는 함정이 있으니 명시적으로 늘려두는 것이 좋습니다.
vLLM — 동시 요청이 있는 팀 서버용
# docker-compose.yml
services:
vllm:
image: vllm/vllm-openai:latest
ports:
- "8000:8000"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
volumes:
- ./models:/root/.cache/huggingface
command: >
--model Qwen/Qwen2.5-14B-Instruct-AWQ
--quantization awq
--max-model-len 16384
--gpu-memory-utilization 0.92
--max-num-seqs 16
vLLM 핵심 플래그의 의미는 다음과 같습니다.
- gpu-memory-utilization: 전체 VRAM 중 vLLM이 선점할 비율. 가중치를 뺀 나머지가 전부 KV cache 풀이 됩니다.
- max-model-len: 시퀀스 최대 길이. KV cache 산수와 직결되므로 워크로드에 맞게 보수적으로.
- max-num-seqs: 동시 처리 시퀀스 수 상한. 처리량과 개별 지연의 트레이드오프 다이얼입니다.
멀티 GPU — 한 장으로 모자랄 때
24GB 카드 두 장으로 70B를 돌리는 식의 구성은 이제 흔합니다. 방식은 두 가지입니다.
| 방식 | 원리 | 장점 | 단점 |
|---|---|---|---|
| 텐서 병렬 (TP) | 각 레이어의 행렬을 카드들이 분담 | 지연 감소에도 기여 | 카드 간 통신이 잦음, 동일 카드 권장 |
| 파이프라인 병렬 (PP) | 레이어를 구간으로 나눠 분담 | 이기종 카드 조합 가능 | 단일 요청 지연은 개선 안 됨 |
# vLLM: 2-way 텐서 병렬
vllm serve Qwen/Qwen2.5-72B-Instruct-AWQ \
--quantization awq \
--tensor-parallel-size 2 \
--max-model-len 8192
# llama.cpp: 카드별 분담 비율 지정 (이기종 조합 예)
llama-server -m llama-70b-q4_k_m.gguf \
--n-gpu-layers 99 \
--split-mode layer \
--tensor-split 60,40
소비자 보드에서는 PCIe 레인이 병목이 되기 쉽습니다. 텐서 병렬은 통신량이 많아 x8/x8 이상을 권장하고, 레인이 부족한 구성이면 파이프라인(레이어) 분할이 안전합니다.
성능 측정 방법론 — 감이 아니라 숫자로
로컬 LLM 튜닝은 측정 없이는 미신이 됩니다. 표준 지표는 네 가지입니다.
TTFT (Time To First Token) : 첫 토큰까지의 시간. 프롬프트 처리 속도 반영
TPOT (Time Per Output Token): 출력 토큰당 시간. 생성 속도의 역수
pp 속도 (prompt processing) : 프롬프트 토큰/초. 긴 입력 워크로드의 체감 좌우
tg 속도 (token generation) : 생성 토큰/초. 대화 워크로드의 체감 좌우
llama.cpp에는 전용 벤치마크 도구가 내장되어 있습니다.
# 프롬프트 512토큰 처리 + 128토큰 생성 시나리오 측정
./build/bin/llama-bench \
-m models/qwen2.5-14b-q4_k_m.gguf \
-p 512 -n 128 \
-ngl 99
# 출력 예 (열: 설정, pp512, tg128 토큰/초)
# 양자화 수준, ngl, 스레드 수를 바꿔가며 표를 만들면
# 내 머신의 품질-속도 곡선이 그려진다
서버 전체의 부하 테스트는 동시성을 바꿔가며 측정합니다.
# vLLM 내장 벤치마크: 동시성을 바꿔가며 TTFT/TPOT 측정
vllm bench serve \
--backend openai \
--base-url http://localhost:8000 \
--model Qwen/Qwen2.5-14B-Instruct-AWQ \
--num-prompts 200 \
--request-rate 4
측정 시 원칙 세 가지를 지켜야 합니다.
- 워밍업 후 측정: 첫 요청은 모델 로딩과 커널 컴파일이 섞여 항상 느립니다.
- 자기 워크로드와 같은 분포로: 짧은 프롬프트 벤치마크는 RAG 워크로드의 성능을 전혀 대표하지 못합니다. 입력/출력 길이 분포를 실제와 맞추세요.
- 평균이 아니라 p95: 에이전트 파이프라인은 가장 느린 호출이 전체를 지연시킵니다. 꼬리 지연을 보세요.
흔한 함정
마지막으로, 커뮤니티에서 반복적으로 보이는 함정들입니다.
- 컨텍스트 한도를 잊는 것: 기본 설정의 컨텍스트는 짧습니다. 대화가 길어지며 조용히 앞부분이 잘려나가고, 모델이 갑자기 바보가 된 것처럼 보입니다. ctx-size를 명시하고, 그만큼의 KV cache 메모리를 계산에 넣으세요.
- 과한 양자화로 인한 미세한 품질 붕괴: Q2~Q3 양자화는 짧은 답변에서는 멀쩡해 보이지만 긴 추론 체인이나 코드 생성에서 무너집니다. 자기 작업의 평가셋으로 양자화 수준별 품질을 직접 비교해야 합니다.
- 벤치마크와 체감의 괴리: tg 토큰/초가 높아도 pp가 느리면 RAG에서는 답답합니다. 두 숫자를 항상 같이 보세요.
- 샘플링 파라미터 방치: 모델마다 권장 temperature와 top-p가 다릅니다. 기본값 그대로 쓰고 모델 탓을 하는 경우가 많습니다.
- 전력과 발열 무시: 24시간 서버로 돌리는 경우 전력 한도를 약간 낮추면(power limit) 토큰/초 손실 몇 퍼센트로 전력과 발열을 크게 줄일 수 있습니다.
- 보안 방치: 로컬 서버라고 인증 없이 0.0.0.0에 열어두면, 같은 네트워크의 누구나 내 GPU를 쓸 수 있습니다. 최소한 API 키와 방화벽 규칙을 설정하세요.
- 출처 불명 모델 파일: 양자화 모델은 누구나 올릴 수 있습니다. 공급망 공격이 일상이 된 시대에, 다운로드 수가 많고 업로더가 검증된 저장소를 쓰고 해시를 확인하는 습관은 로컬에서도 유효합니다.
- 업데이트 추적 소홀: llama.cpp와 vLLM은 몇 주 단위로 성능이 눈에 띄게 개선됩니다. 반년 전 벤치마크로 내린 결론은 이미 낡았을 수 있습니다.
마치며
로컬 LLM 인퍼런스 최적화는 결국 하나의 질문으로 수렴합니다. 내 메모리 예산 안에서 품질, 속도, 컨텍스트 길이를 어떻게 배분할 것인가. 양자화는 가중치 예산을 줄이고, KV cache 양자화와 컨텍스트 한도는 캐시 예산을 다스리고, 오프로딩은 예산 자체를 빌려옵니다. nbd-vram 같은 역발상은 그 예산 장부의 칸막이가 생각보다 자유롭다는 것을 보여줍니다.
오늘 시작한다면 추천 경로는 이렇습니다.
- Ollama로 14B Q4 모델을 받아 일단 자기 작업에 며칠 써본다
- 컨텍스트 부족이나 속도 불만이 생기면 llama.cpp로 내려가 KV 양자화와 오프로딩을 튜닝한다
- 동시 사용자가 생기면 vLLM으로 올라가 연속 배칭의 처리량을 가져간다
- 매 단계에서 llama-bench와 부하 테스트로 변경 전후를 숫자로 비교한다
하나 덧붙이면, 이 분야는 변화 속도가 빠릅니다. 오늘의 최적 설정은 다음 분기에 낡은 지식이 될 수 있으니, 측정 스크립트를 자동화해 두고 주기적으로 다시 돌리는 습관이 가장 오래가는 자산입니다.
클라우드 API와 로컬 모델은 대체 관계가 아니라 역할 분담입니다. 민감한 데이터, 반복 작업, 오프라인 환경은 로컬로, 최고 품질이 필요한 순간은 API로. 그 경계선을 자기 워크로드의 숫자로 그릴 수 있게 되는 것, 그것이 이 글에서 다룬 측정과 산수의 목적입니다.
참고 자료
- nbd-vram (VRAM을 블록 디바이스로): https://github.com/c0dejedi/nbd-vram
- llama.cpp 공식 저장소: https://github.com/ggml-org/llama.cpp
- vLLM 공식 문서: https://docs.vllm.ai/
- Ollama 공식 사이트: https://ollama.com/
- GGUF 포맷 명세: https://github.com/ggml-org/ggml/blob/master/docs/gguf.md
- AWQ 논문: https://arxiv.org/abs/2306.00978
- GPTQ 논문: https://arxiv.org/abs/2210.17323
- PagedAttention (vLLM) 논문: https://arxiv.org/abs/2309.06180
- llama.cpp 서버 문서: https://github.com/ggml-org/llama.cpp/tree/master/tools/server
- Hacker News의 로컬 LLM 토론: https://news.ycombinator.com/
- GeekNews: https://news.hada.io/