Gemini

Gemma 4 12B 완전분석 2편: vLLM / SGLang / Ollama 서빙 실전 세팅

cell-devlog 2026. 6. 5. 09:57
반응형

 

✅ 핵심 요약

vLLM: PagedAttention 기반 멀티유저 고처리량 서빙 — 프로덕션 표준 → SGLang: RadixAttention으로 prefix 재사용 극대화 — 에이전트·긴 시스템 프롬프트 워크플로우 최적 → Ollama: 단일 개발자 로컬 실행, OpenAI 호환 API 즉시 제공 — 프로토타이핑 최선 → 세 엔진 모두 OpenAI 호환 API로 노출 — 클라이언트 코드 동일하게 재사용 가능 → 12B는 BF16 기준 24GB VRAM 권장, Q4 양자화 시 16GB에서 동작 → vLLM --limit-mm-per-prompt 플래그로 멀티모달 메모리 사용량 제어 가능 → SGLang MTP(NEXTN) + draft 모델로 speculative decoding 활성화 가능 → Ollama Modelfile로 컨텍스트 윈도우·샘플링 파라미터 고정 권장


엔진 선택 기준 먼저

상황 선택

멀티유저, 동시 요청 처리, 프로덕션 vLLM
에이전트 루프, 긴 시스템 프롬프트 반복, prefix 재사용 SGLang
단독 개발 환경, 빠른 프로토타이핑 Ollama
멀티모달(이미지·오디오) 배치 파이프라인 vLLM
Function calling + Thinking mode 실험 SGLang

VRAM 예산 계산

어떤 엔진을 써도 모델 웨이트 + KV 캐시 + 런타임 오버헤드를 같이 잡아야 합니다.

정밀도 웨이트 크기 권장 VRAM 비고

BF16 ~26.7GB 40GB+ A100 40GB, H100
SFP8 ~13.4GB 24GB RTX 4090, A10G
Q4_0 ~6.7GB 16GB RTX 4060 Ti 16GB, RTX 3090

⚠️ KV 캐시는 컨텍스트 길이에 비례해서 커집니다. 256K 풀 컨텍스트를 쓰려면 24GB 이상 필요합니다. --max-model-len 8192로 먼저 안정성을 확인하고 늘려가세요.


방법 1. vLLM — 프로덕션 멀티유저 서빙 표준

PagedAttention이 핵심입니다. 요청이 여러 개 들어올 때 KV 캐시를 페이지 단위로 쪼개서 메모리 낭비 없이 배치 처리합니다. 단일 개발자 환경에서도 멀티모달 배치 파이프라인에는 vLLM이 맞습니다.

설치

pip install vllm

기본 서버 실행 (텍스트 전용)

vllm serve google/gemma-4-12b-it \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92

멀티모달 (이미지 + 오디오) 서버

vllm serve google/gemma-4-12b-it \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92 \
  --mm-processor-kwargs '{"max_soft_tokens": 280}'

💡 max_soft_tokens는 이미지당 할당하는 비전 토큰 예산입니다. 70 / 140 / 280 / 560 / 1120 중 선택합니다. 높을수록 해상도가 올라가지만 VRAM을 더 먹습니다.

멀티모달 메모리 절약 플래그

# 이미지만 쓰고 오디오는 안 쓸 때
--limit-mm-per-prompt '{"audio": 0}'

# 텍스트 전용 워크플로우 — 멀티모달 프로파일링 스킵
--limit-mm-per-prompt '{"image": 0, "audio": 0}'

# 요청당 이미지 4개, 비디오 1개로 제한
--limit-mm-per-prompt 'image=4,video=1'

비동기 스케줄링 (처리량 향상)

vllm serve google/gemma-4-12b-it \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92 \
  --async-scheduling

Python 클라이언트 (이미지 포함 요청)

import base64
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")

with open("diagram.png", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
    model="google/gemma-4-12b-it",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "이 아키텍처 다이어그램에서 문제점 찾아줘"},
            {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}}
        ]
    }],
    temperature=1.0,
    top_p=0.95,
    max_tokens=1024,
)
print(response.choices[0].message.content)

Docker로 띄우기

# CUDA 12.9
docker pull vllm/vllm-openai:latest

docker run --gpus all \
  -p 8000:8000 \
  vllm/vllm-openai:latest \
  --model google/gemma-4-12b-it \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92

방법 2. SGLang — RadixAttention, 에이전트 워크플로우 특화

RadixAttention이 핵심입니다. prefix(시스템 프롬프트, 공통 컨텍스트)를 트리 구조로 캐싱해서, 같은 prefix를 가진 요청이 반복될 때 prefill을 통째로 스킵합니다. 에이전트 루프처럼 긴 시스템 프롬프트가 매 턴 반복되는 구조에서 vLLM 대비 처리량이 유의미하게 올라갑니다.

설치

pip install "sglang[all]"

기본 서버 실행

python -m sglang.launch_server \
  --model-path google/gemma-4-12b-it \
  --host 0.0.0.0 \
  --port 30000 \
  --max-total-tokens 32768

Thinking mode + Function calling 활성화

python -m sglang.launch_server \
  --model-path google/gemma-4-12b-it \
  --host 0.0.0.0 \
  --port 30000 \
  --max-total-tokens 32768 \
  --reasoning-parser gemma4 \
  --tool-call-parser gemma4

💡 --reasoning-parser gemma4를 붙여야 Gemma 4의 thinking mode 구분자(<|channel>thought\n...<channel|>)가 올바르게 파싱됩니다. 없으면 추론 토큰이 응답 텍스트에 그대로 섞입니다.

MTP(Multi-Token Prediction) — speculative decoding 활성화

# 12B 타겟 + draft 모델로 NEXTN MTP
python -m sglang.launch_server \
  --model-path google/gemma-4-12b-it \
  --speculative-algorithm NEXTN \
  --speculative-draft-model-path google/gemma-4-12b-assistant \
  --host 0.0.0.0 \
  --port 30000 \
  --reasoning-parser gemma4 \
  --tool-call-parser gemma4

품질 손실 없이 생성 속도 1.5~2배 향상을 기대할 수 있습니다. draft 모델(gemma-4-12b-assistant)은 HuggingFace에서 별도 다운로드가 필요합니다.

Python 클라이언트

from openai import OpenAI

client = OpenAI(api_key="EMPTY", base_url="http://localhost:30000/v1")

# 일반 텍스트 요청
response = client.chat.completions.create(
    model="google/gemma-4-12b-it",
    messages=[
        {"role": "system", "content": "당신은 시니어 백엔드 엔지니어입니다."},
        {"role": "user", "content": "FastAPI + PostgreSQL 연결 풀 설정 코드 짜줘"}
    ],
    temperature=1.0,
    top_p=0.95,
    max_tokens=2048,
)
print(response.choices[0].message.content)

vLLM vs SGLang 선택 정리

항목 vLLM SGLang

멀티유저 배치 처리 ✅ PagedAttention
Prefix 재사용 캐싱 부분적 ✅ RadixAttention
Thinking mode 파싱 별도 설정 필요 ✅ --reasoning-parser gemma4
Function calling 파싱 별도 설정 필요 ✅ --tool-call-parser gemma4
멀티모달 메모리 제어 ✅ --limit-mm-per-prompt 제한적
Docker 공식 이미지 직접 빌드
에이전트 루프 효율 보통 ✅ 높음

방법 3. Ollama — 단일 개발 환경, 즉시 시작

프로토타이핑이나 로컬 단독 개발에서 Ollama가 가장 빠릅니다. 설치 한 줄, 실행 한 줄, OpenAI 호환 API 자동 노출입니다.

설치 및 실행

# 설치
curl -fsSL https://ollama.com/install.sh | sh

# 실행 (자동으로 Q4 선택)
ollama run gemma4:12b

# 서버만 백그라운드로
ollama serve

Modelfile — 컨텍스트 윈도우와 샘플링 고정 권장

Ollama는 기본 컨텍스트 윈도우가 4096으로 잡히는 경우가 있습니다. 큰 코드베이스나 긴 문서 작업 전에 반드시 Modelfile로 고정해두세요.

# Modelfile
FROM gemma4:12b

# Gemma 4 공식 권장 샘플링 파라미터
PARAMETER num_ctx 32768
PARAMETER temperature 1.0
PARAMETER top_p 0.95
PARAMETER top_k 64
ollama create gemma4-12b-dev -f Modelfile
ollama run gemma4-12b-dev

OpenAI SDK 연결

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",
)

response = client.chat.completions.create(
    model="gemma4-12b-dev",
    messages=[
        {"role": "system", "content": "한국어로 답변하는 코딩 어시스턴트"},
        {"role": "user", "content": "Redis pub/sub 패턴 Python 예제 짜줘"}
    ],
)
print(response.choices[0].message.content)

세 엔진 최종 비교

항목 vLLM SGLang Ollama

설치 난이도 보통 보통 쉬움
멀티유저 처리량 ✅ 최고 ✅ 높음 ❌ 단일 세션
Prefix 캐싱 부분 ✅ RadixAttention
MTP speculative 미지원 ✅ NEXTN
Thinking mode 파싱 수동 ✅ 네이티브
멀티모달 제어 ✅ 세밀 제한적 ✅ (projector 자동)
Docker 공식 지원 직접 빌드
프로토타이핑 속도 보통 보통 ✅ 가장 빠름
프로덕션 적합성
정리:
프로덕션 멀티유저 서버  → vLLM
에이전트 / 함수 호출   → SGLang
로컬 개발 / 프로토타입  → Ollama

관련 글

반응형