
Gemma 4 E4B MTP speculative decoding llama-swap llama.cpp Open WebUI
🔍 Ollama를 버린 이유
맥북 M2 Max에서 로컬 LLM을 구동할 때 보통 Ollama를 먼저 고려한다. 설치가 간편하고 웹 UI와 모델 pull 기능이 기본으로 제공되기 때문이다. 하지만 Gemma 4 E4B의 성능을 제대로 활용하려면 Ollama만으로는 한계가 있었다.
핵심은 MTP(Multi-Token Prediction)다. Gemma 4는 드래프터 모델을 통해 추론 속도를 가속하는 speculative decoding 구조를 지원한다. 현재 Ollama는 Gemma 4의 MTP를 지원하지 않으므로, llama.cpp를 사용해야 한다.
실측 결과, M2 Max 32GB 환경에서 Gemma 4 E4B + MTP 조합으로 약 81 tok/s를 기록했다. 이는 Ollama MLX 엔진으로 8B 모델을 돌릴 때(65-75 tok/s)보다 빠른 수치다. 4B 모델임에도 MTP가 없는 llama.cpp 단독 구동(50-60 tok/s) 대비 35-60%의 성능 향상을 확인했다. 이 글에서는 해당 환경의 구성과 운영 과정을 정리한다.
📋 환경 구성 — 세 컴포넌트
설치 경로는 ~/Git/local-llm/이다. 맥북 전용 설정이므로 git ignore 처리했다.
| 컴포넌트 | 역할 | 비고 |
|---|---|---|
| llama.cpp | 추론 엔진 | Metal GPU 백엔드, MTP 지원 b9549+ |
| llama-swap | 다중 모델 프록시 | Go 바이너리, TTL 언로드, OpenAI 호환 API |
| Open WebUI | 웹 인터페이스 | localhost:8888, 드롭다운 모델 선택 |
llama-swap이 localhost:11434에서 OpenAI 호환 API를 노출하며, Open WebUI는 이 엔드포인트를 사용한다. 사용자가 드롭다운에서 모델을 선택하면 llama-swap이 해당 llama-server를 기동하고, 10분(600초) 동안 활동이 없으면 자동으로 언로드한다.

🧠 MTP — 핵심 기술
드래프터 모델이 여러 토큰을 미리 예측하고, 메인 모델이 병렬로 검증하는 방식이다. 채택된 토큰은 추가 연산 없이 확정된다. 채택률이 높을수록 속도 향상이 크다.
Gemma 4 E4B 기준, 이 맥북에서의 채택률(Acceptance Rate)은 42–57%다. DGX Spark 서버 환경에서는 84-93%까지 올라간다. 컨텍스트 패턴이 일관적일수록 드래프터의 예측 정확도가 높아지기 때문이다. Google 공식 발표(2026-05-05)에 따르면 MTP는 Gemma 4의 핵심 추론 가속 기법이다.

설정 시 주의할 점은 두 가지다.
--flash-attn과 MTP는 충돌한다.--flash-attn off설정이 필수다.- 드래프트 깊이의 최적점(sweet spot)은
--spec-draft-n-max 4다. 4를 초과하면 수익이 감소한다. DGX 환경에서 n-max를 2로 낮췄을 때 +35%(80→109 tok/s)의 향상을 확인했다.
🛠️ 모델 파일 구성
현재 운영 중인 모델은 두 가지다. 기본 모델은 Unsloth의 UD-Q4_K_XL이다. QAT(Quantization-Aware Training)를 적용해 일반 Q4_K_M 대비 품질이 높다. uncensored 모델은 HauhauCS Aggressive 커뮤니티 파인튜닝 모델이다.
| 모델 ID | 메인 파일 (크기) | MTP 드래프터 | 속도 |
|---|---|---|---|
| gemma-4-E4B (기본) | UD-Q4_K_XL.gguf (4.22GB) | Q8_0-MTP.gguf (~156MB) | ~81 tok/s |
| gemma-4-E4B-uncensored | Q4_K_M.gguf (4.97GB) | 없음 | ~60 tok/s |
MTP 드래프터(Q8_0)는 약 156MB이며, 약 1.5~2GB의 추가 RAM을 점유한다. 32GB 메모리 기준으로는 여유로운 수준이다. vision 기능은 두 모델 모두 별도의 mmproj(F16.gguf)를 통해 지원한다.
uncensored 모델에서 발견한 특이사항이 있다. 개방형 질문 시 영어 reasoning이 길게 출력되어 답변 내용(content)이 비어 보이는 현상이다. Open WebUI 시스템 프롬프트에 thinking 출력을 억제하도록 명시하여 해결했다. 권장 샘플러 설정은 다음과 같다: temp=1.0, top_p=0.95, top_k=64, --jinja.
⚙️ 실행 설정
llama-swap과 Open WebUI를 동시에 기동하는 통합 스크립트를 사용한다.
# 통합 시작
./start-webui.sh
# OpenAI 호환 API 엔드포인트
http://localhost:11434/v1
# 종료
pkill -f "open-webui serve" \
&& pkill -f "llama-swap" \
&& pkill -f "llama-server"
llama-swap.yaml의 핵심 설정이다. ${PORT}는 llama-swap이 자동으로 할당한다.
healthCheckTimeout: 120
ttl: 600 # 10분 idle 후 자동 언로드
models:
gemma-4-E4B:
cmd: |
llama-server
--model /path/to/main-Q4_K_XL.gguf
--model-draft /path/to/draft-Q8_0.gguf
--mmproj /path/to/mmproj-F16.gguf
--spec-type draft-mtp
--spec-draft-n-max 4
--flash-attn off
--port ${PORT}
gemma-4-E4B-uncensored:
cmd: |
llama-server
--model /path/to/uncensored-Q4_K_M.gguf
--mmproj /path/to/mmproj-uncensored-F16.gguf
--port ${PORT}
brew tap mostlygeek/llama-swap && brew install llama-swap. Ollama 에코시스템 잠금 없이 모든 GGUF를 지원하며, 컨테이너 오버헤드 없이 Metal GPU를 100% 활용한다. GitHub: mostlygeek/llama-swap
📊 속도 비교 — 실측 및 외부 벤치마크
M2 Max(메모리 대역폭 400 GB/s) 기준 실측값과 외부 벤치마크 데이터다.
| 구성 | tok/s | 비고 |
|---|---|---|
| Ollama (MLX 엔진, 8B Q4_K_M) | 65–75 | 2026 macOS MLX JIT 컴파일 기준 |
| llama.cpp (E4B Q4_K_XL, MTP 없음) | 50–60 | GGUF 단독 실측 |
| llama.cpp + Gemma 4 E4B + MTP | ~81 | 채택률 42–57%, 실측 |
타 하드웨어 참고값 출처: GitHub karany97/llamacpp-gemma4-mtp, Reddit — RTX PRO 6000 3.34x 검증, Medium — 로컬 추론 벤치마크(2026-05-22).
| 하드웨어 | MTP 전 | MTP 후 | 향상 |
|---|---|---|---|
| Samsung Galaxy S26+ | ~12 tok/s | ~14 tok/s | +15% |
| NVIDIA Jetson Orin NX | ~13 tok/s | 18–20 tok/s | +30–40% |
| RTX 3060 12GB | ~30 tok/s | 60+ tok/s | 2x–3x |
| RTX PRO 6000 | 기준 | 3.34x | 검증됨 |
GPU 환경에서 채택률이 70–100%까지 치솟는 이유는 코딩 작업의 반복적인 패턴 때문이다. 맥북 Metal 환경은 42–57% 수준이지만, 이 역시 유의미한 속도 향상을 제공한다. llama.cpp의 MTP 지원은 PR #23398 (b9549, 2026-06-07)을 통해 병합되었다. Reddit LocalLLaMA에서도 +40% speedup 리포트가 지속적으로 보고되고 있다.
🔧 트러블슈팅 — 주요 이슈
| 증상 | 원인 | 해결 |
|---|---|---|
| “no implementations specified” | –spec-type 플래그 누락 | --spec-type draft-mtp 추가 |
| MTP 컨텍스트 생성 실패 | flash-attn 충돌 | --flash-attn off |
| b9820에서 플래그 오류 | 플래그명 변경 | --spec-draft-n-max (구: --draft-max) |
| uncensored 답변 비어 보임 | 영어 thinking 출력 누출 | WebUI 시스템 프롬프트로 억제 |
| py3.13 audioop ImportError | 표준 라이브러리 제거됨 | uv pip install audioop-lts |
uncensored 모델의 thinking 누출 문제는 처음에는 모델 결함으로 의심했다. 확인 결과, 영어 reasoning이 모두 출력되어 실제 답변 content가 뒤로 밀리는 구조였다. Open WebUI 시스템 프롬프트로 출력을 제어하여 해결했다. 모델 자체의 버그는 아니었다.
📚 참고 자료
- Google — Gemma 4 MTP 공식 발표 (2026-05-05)
- llama.cpp PR #23398 — MTP merged (2026-06-07)
- Reddit LocalLLaMA — MTP Gemma 4 +40% speedup
- Reddit — RTX PRO 6000 3.34x 검증
- GitHub — llamacpp-gemma4-mtp 벤치마크 하네스
- Medium — Gemma 4 MTP 로컬 추론 벤치마크 (2026-05-22)
- Hacker News — MTP 토론 (2026-05-12)
- AI Weekly — llama.cpp Gemma 4 E4B MTP 지원
- Unsloth Gemma 4 E4B GGUF (HuggingFace)
- HauhauCS Gemma-4-E4B-Uncensored (HuggingFace)
✅ 정리
M2 Max 32GB 환경에서 로컬 LLM을 효율적으로 쓰려면 llama.cpp와 llama-swap 조합이 최선이다. Ollama보다 설정은 복잡하지만, MTP 지원과 세밀한 파라미터 제어가 그 가치를 충분히 한다. Gemma 4 E4B + MTP 조합은 약 81 tok/s를 기록하며, 이는 4B 모델임에도 Ollama MLX 엔진의 8B 모델(65–75 tok/s)을 상회하는 수치다. 모든 컴포넌트는 MIT 또는 Gemma License 기반의 오픈소스다.
llama-swap의 TTL 기반 idle 언로드 기능은 다중 모델 운영 시 매우 실용적이다. 모델 전환이 간편하고, 미사용 모델을 10분 후 메모리에서 해제하여 SSD wear를 방지한다.
로컬 LLM 설정에 관한 더 많은 정보는 로컬 AI 카테고리에서 확인할 수 있다.
