LLM 핸드북 4: 추론·RAG·도구사용

LLM 추론 최적화, RAG 파이프라인, 도구 사용 설계, 제공자별 연동 패턴을 실무 중심으로 정리합니다.

개요

이 페이지는 모델을 실제 서비스에 연결하는 마지막 단계인 추론 최적화와 RAG/도구 사용 전략을 다룹니다. 학습/정렬 자체는 LLM 핸드북 2: 학습·정렬에서 다룹니다.

실제 서비스에서는 지연 시간, 처리량, 비용, VRAM의 균형을 맞추는 엔지니어링이 필요합니다. KV 캐시, 양자화, 배치 처리, 서빙 프레임워크부터 하드웨어와 비용 최적화까지 실무 전략을 정리합니다.

추론 성능 핵심 메트릭

추론 성능을 평가할 때 반드시 구분해야 하는 두 가지 핵심 메트릭이 있습니다.

TTFT (Time To First Token)

요청 시점부터 첫 토큰 생성까지의 시간. Prefill 성능을 반영하며 체감 응답 속도에 직결됩니다. 대화형 서비스에서 500ms 이하가 목표이며, Prefix 캐싱과 FlashAttention으로 최적화합니다.

TPS (Tokens Per Second)

초당 생성 토큰 수. 디코딩 속도를 나타내며 응답 완료 시간에 영향. 사용자당 30 TPS 이상이면 읽기 속도보다 빠릅니다. Speculative decoding, continuous batching, 양자화로 최적화합니다.

실무 팁: TTFT와 TPS는 트레이드오프 관계입니다. 배치 크기를 늘리면 처리량은 증가하지만 개별 TTFT는 길어집니다. 서비스 특성에 맞게 균형점을 찾으세요.

추론 최적화

모델을 실제 서비스로 제공하기 위해 속도와 비용을 최적화합니다. 캐싱, 배치, 양자화, KV 캐시 등이 핵심입니다.

POST /api/generate
# Ollama 예시: 로컬 추론 서버에 요청
{
  "model": "llama3.1",
  "prompt": "추론 최적화 전략을 3가지로 요약",
  "stream": false
}
참고: 로컬 추론 API는 Ollama, vLLM, TGI 등에서 유사한 구조로 제공됩니다.

KV 캐시 상세

Transformer 기반 LLM은 매 토큰 생성 시 이전 모든 토큰에 대한 Attention 연산을 수행합니다. KV 캐시는 이미 계산된 Key/Value 텐서를 메모리에 저장하여 중복 연산을 방지하는 핵심 최적화 기법입니다.

Prefill과 Decode 단계

LLM 추론은 두 단계로 나뉩니다.

  • Prefill (프리필): 입력 프롬프트의 모든 토큰을 한 번에 처리하여 KV 캐시를 초기화합니다. GPU 연산 집약적이며 병렬 처리 가능합니다.
  • Decode (디코드): 캐시된 KV를 재사용하며 한 번에 하나의 토큰을 생성합니다. 메모리 대역폭 바운드이며 순차적으로 진행됩니다.
KV 캐시 메커니즘: Prefill → Decode Prefill 단계 T₁ T₂ T₃ ... Tₙ 모든 K,V 계산 KV Cache [K₁V₁ ... KₙVₙ] Decode 단계 (순차 생성) Tₙ₊₁ 캐시 재사용 +Kₙ₊₁Vₙ₊₁ Tₙ₊₂ +Kₙ₊₂Vₙ₊₂ 메모리 증가 Prefill: 모든 K,V 한 번에 계산 (GPU 연산 바운드) | Decode: 캐시 재사용 + 신규 토큰만 연산 (메모리 바운드)

KV 캐시 동작 원리 — Prefill에서 초기 캐시 생성, Decode에서 캐시 재사용하며 토큰당 메모리 선형 증가

KV 캐시 메모리 계산

KV 캐시 메모리는 다음 공식으로 계산합니다.

// KV 캐시 메모리 = 2 × layers × kv_heads × head_dim × seq_len × bytes
// 예시: Llama 3.1 70B (FP16, GQA kv_heads=8)
KV_memory = 2 × 80 × 8 × 128 × 4096 × 21.25 GB // 요청 1건당!
주의: 동시 100명이면 KV 캐시만 125GB 필요. PagedAttention 같은 최적화가 필수입니다.

PagedAttention

vLLM이 도입한 기법으로 KV 캐시를 OS 가상 메모리처럼 페이지 단위(16토큰)로 관리합니다. 기존 방식의 60~80% 메모리 낭비를 4% 이하로 줄여 동시 배치 크기를 2~4배 늘립니다. 동일 시스템 프롬프트 요청은 KV 캐시 페이지를 Copy-on-Write로 공유합니다.

FlashAttention

Attention 행렬을 전체 실체화하지 않고 타일 단위로 연산하여 HBM↔SRAM 데이터 이동을 최소화합니다. 긴 컨텍스트(32K~128K)에서 메모리를 O(N²)→O(N)으로 줄이고 속도를 2~4배 향상시킵니다. FlashAttention-3은 H100의 FP8까지 지원합니다.

실무 팁: FlashAttention과 PagedAttention은 상호 보완적입니다. vLLM은 두 기법을 모두 지원하며, 함께 사용할 때 최대 효과를 얻습니다.

양자화 (Quantization)

양자화는 모델 가중치의 정밀도를 낮춰 메모리 사용량과 연산 비용을 줄이는 기법입니다. FP32에서 INT4까지 다양한 수준이 있으며, 정밀도와 품질 사이의 트레이드오프를 이해해야 합니다.

양자화 비교: 70B 모델 VRAM·품질 정밀도 VRAM 품질 FP32 ~280 GB 100% FP16 ~140 GB (50%↓) ~99.9% INT8 ~70 GB (75%↓) ~99% INT4 ~35 GB (87.5%↓) ~95-97% FP16 사실상 무손실 | INT8 대부분 충분 | INT4 소비자 GPU에서 대형 모델 가능 (일부 추론 저하 주의)

양자화 수준별 메모리 절감과 품질 트레이드오프 — 70B 파라미터 모델 기준

양자화 기법 비교

  • GPTQ: 후훈련 4/8비트. 보정 데이터 기반, GPU 추론 최적화 (vLLM, TGI)
  • AWQ: 후훈련 4비트. 중요 채널 보존으로 GPTQ 대비 품질 우수 (vLLM 권장)
  • GGUF: 후훈련 2~8비트. CPU/GPU 혼합 추론, 단일 파일 (llama.cpp, Ollama)
  • bitsandbytes: 동적 4/8비트. 로드 시 양자화, QLoRA 결합 가능 (HF Transformers)
  • FP8: H100+ 네이티브 8비트 부동소수. 거의 무손실 (vLLM, TensorRT-LLM)
# GGUF 양자화 모델 실행 (Ollama)
ollama run llama3.1:70b-instruct-q4_K_M

# bitsandbytes 4비트 로딩 (Python)
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-70B-Instruct",
    quantization_config=config, device_map="auto")
GGUF 가이드: Q4_K_M(범용 추천) > Q5_K_M(고품질) > Q3_K_M(저VRAM). Q2 이하는 비추천.

추론 최적화 세부 전략

Continuous Batching

정적 배치는 가장 긴 시퀀스가 끝날 때까지 대기하지만, continuous batching은 완료된 요청을 즉시 제거하고 새 요청을 투입합니다. 동일 하드웨어에서 처리량 최대 23배 향상됩니다 (Orca 논문).

Speculative Decoding

작은 draft 모델이 K개 토큰을 미리 생성하고, target 모델이 1회 forward pass로 검증합니다. 출력 분포 손실 없이 코드 생성 등에서 2~3배 속도 향상. 창의적 텍스트에서는 효과 제한적입니다.

병렬화 전략

  • Tensor Parallelism (TP): 하나의 레이어를 여러 GPU에 분할. NVLink 필요. 지연 감소
  • Pipeline Parallelism (PP): 레이어 그룹을 다른 GPU에 할당. 처리량 증가
  • 조합: 대형 모델은 TP + PP 혼합 (예: 8GPU에서 TP=4, PP=2)

기타 최적화

  • 스트리밍 응답: SSE로 토큰 즉시 전송, 체감 지연 감소
  • 프롬프트 캐싱: 동일 시스템 프롬프트 KV 캐시 재사용 (Anthropic prompt caching, vLLM prefix caching)
  • 커널 융합: 연산을 단일 GPU 커널로 합쳐 메모리 이동 최소화 (TensorRT-LLM)

서빙 프레임워크 비교

LLM을 API로 서빙하기 위한 주요 프레임워크를 비교합니다.

프레임워크주요 특징양자화최적 사용처
vLLMPagedAttention, continuous batching, OpenAI 호환AWQ, GPTQ, FP8프로덕션 GPU 서빙
TGIHF 통합, 스트리밍, 워터마크GPTQ, AWQHF 생태계
llama.cppCPU/GPU 혼합, GGUF, 단일 바이너리GGUF엣지/로컬/CPU
Ollamallama.cpp 래퍼, Docker식 관리GGUF개발/프로토타입
TensorRT-LLMNVIDIA 최적화, 커널 융합FP8, INT4NVIDIA 최대 성능
SGLangRadixAttention, 구조화 생성AWQ, FP8구조화 출력 서비스
# vLLM 서버 실행 (OpenAI 호환 API)
python -m vllm.entrypoints.openai.api_server \\
    --model "meta-llama/Llama-3.1-8B-Instruct" \\
    --max-model-len 8192 --gpu-memory-utilization 0.9

# Ollama (로컬 개발용)
ollama run llama3.1:8b
# API: curl http://localhost:11434/api/chat -d '{"model":"llama3.1:8b",...}'
선택: 프로덕션→vLLM, 로컬→Ollama, CPU→llama.cpp, NVIDIA 최적화→TensorRT-LLM

하드웨어 선택 가이드

모델 크기와 양자화 수준에 따른 GPU VRAM 요구사항입니다.

GPU VRAM 요구사항 표

모델 크기FP16INT4권장 GPU
7~8B14~16 GB4~5 GBRTX 4060 Ti 16GB
13~14B26~28 GB8~9 GBRTX 4090 24GB
30~34B60~68 GB18~21 GBA100 80GB
65~70B130~140 GB35~40 GB2x A100 80GB
405B~810 GB~210 GB8x H100 80GB
주의: 위 수치는 가중치만의 VRAM입니다. KV 캐시 등으로 20~40% 추가 필요합니다.

주요 GPU 비교

  • RTX 4090 (24GB, 1,008 GB/s): 로컬 개발, 소형 모델 서빙. ~$1,600
  • A100 80GB (80GB, 2,039 GB/s): 프로덕션 서빙 표준. ~$15,000
  • H100 SXM (80GB, 3,350 GB/s): 대규모 프로덕션, FP8 지원. ~$30,000
  • L40S (48GB, 864 GB/s): 중간 규모 비용 효율. ~$8,000
  • Apple M 시리즈 (통합 메모리 최대 192GB): CPU/GPU 공유 메모리로 대형 모델 로드 가능하나 속도 느림
핵심: LLM 추론은 메모리 대역폭 바운드입니다. TFLOPS보다 GB/s를 우선 고려하세요.

로컬 추론 vs 클라우드 API 비교

LLM을 서비스에 통합할 때 로컬 자체 호스팅과 클라우드 API 중 어떤 방식이 적합한지 비교합니다.

항목로컬 추론클라우드 API
비용 구조고정 (GPU 구매/임대 + 전력)종량제 (토큰당 과금)
확장성수동 스케일링자동 스케일링
지연 시간네트워크 지연 없음네트워크 RTT 추가
프라이버시완전 제어제공자 정책 의존
모델 품질오픈소스 수준최고 수준 (Claude, GPT-4o)
커스터마이징파인튜닝, 양자화 자유제한적 (API 파라미터 내)
손익분기점월 $3,000~5,000 이상 API 비용 시 자체 호스팅 고려
권장: 초기에는 클라우드 API로 시작, 트래픽 안정 후 자체 호스팅 검토. 하이브리드(일반→로컬, 복잡→API)도 유효합니다.

비용 최적화 전략

LLM 서비스의 비용을 최적화하기 위한 실무 전략을 정리합니다.

  • 프롬프트 압축/캐싱: 시스템 프롬프트 간결화 + Anthropic prompt caching (90% 절감)
  • 배치 API: 비실시간 작업은 배치 API (50% 할인)
  • 모델 계층화: 간단 → 소형 모델, 복잡 → 대형 모델 라우팅
  • 스팟 인스턴스: AWS Spot / GCP Preemptible (60~90% 할인)
  • 오토스케일링: 트래픽 패턴에 맞춰 GPU 수 조절
  • 양자화: INT4로 필요 GPU 수 1/4 절감
# 비용 비교 예시: 1M 토큰/일 처리
# Claude API (Sonnet): ~$315/월 (입력 $3/1M + 출력 $15/1M)
# 자체 호스팅 (A100): ~$1,800/월 (GPU 임대, 처리량 높음)
# 로컬 (RTX 4090): ~$93/월 (전기+감가상각, 오픈소스만)
핵심: 가장 큰 비용 레버는 모델 선택입니다. 난이도별 라우팅으로 70% 이상 절감 가능.

RAG와 도구 사용

모델이 모르는 정보는 검색/DB에서 가져오고, 계산/업무는 도구 호출로 처리합니다. LLM의 한계를 서비스 설계로 보완하는 핵심 패턴입니다.

  • RAG: 문서 임베딩 + 검색 + 요약/합성
  • Tool Use: 함수 호출, API 연동, 파일/DB 접근
  • MCP: 표준화된 도구 생태계 연결
상세 가이드: RAG의 청킹, 임베딩, 벡터DB, 고급 기법, 평가까지 심층 내용은 RAG 완전 가이드를 참고하세요.

RAG 설계 체크리스트

  • 문서 분할: 문단 단위로 적절히 쪼개기
  • 임베딩 모델: 도메인 적합도, 비용 고려
  • 검색 전략: 키워드 + 벡터 하이브리드
  • 답변 합성: 근거 인용, 출처 표기

RAG 파이프라인 다이어그램

문서 저장소 검색/리트리버 LLM 응답 합성

문서 검색 → 리트리버 → LLM 합성의 기본 구조

도구 사용 패턴

  • 검증형: LLM 출력 후 도구로 사실 확인
  • 생성형: LLM이 계획을 세우고 도구로 실행
  • 혼합형: 요약/추론은 LLM, 계산/조회는 도구

도구 호출 예제

// Tool Use 프롬프트 예시 (의사 코드)
{
  "role": "user",
  "content": "이 주문의 배송 상태를 조회해줘"
}
// 모델이 tools 호출을 제안
{
  "tool": "getOrderStatus",
  "arguments": { "orderId": "A-1029" }
}

제공자별 API 스니펫

엔드포인트, 모델명, 헤더는 제공자 문서 기준으로 교체하세요.

# Claude (예시)
curl -s "https://api.anthropic.com/v1/messages" \\
  -H "x-api-key: $CLAUDE_API_KEY" \\
  -H "content-type: application/json" \\
  -d '{"model":"MODEL_ID","max_tokens":256,"messages":[{"role":"user","content":"요약해줘"}]}'
# OpenAI (예시)
curl -s "https://api.openai.com/v1/chat/completions" \\
  -H "Authorization: Bearer $OPENAI_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"model":"MODEL_ID","messages":[{"role":"user","content":"요약해줘"}],"max_tokens":256}'
# Gemini (예시)
curl -s "https://generativelanguage.googleapis.com/v1beta/models/MODEL_ID:generateContent?key=$GEMINI_API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"contents":[{"role":"user","parts":[{"text":"요약해줘"}]}]}'
# Ollama (로컬 예시)
curl -s "http://localhost:11434/api/generate" \\
  -H "Content-Type: application/json" \\
  -d '{"model":"llama3.1","prompt":"요약해줘","stream":false}'

참고자료