9,293 commit · 5,000+ release · 112k star · 18.6k fork · MIT · "ChatGPT 만들 줄 모르면 직접 굴려보자"가 만들어낸 로컬 LLM 생태계의 심장
llama.cpp가 정확히 무엇을 하는지부터.
2023년 3월 Georgi Gerganov가 LLaMA 가중치를 어떻게든 자기 맥북에서 돌려보고 싶어서 작성한 단일 C++ 파일로 시작했다. 3년 만에 112k 별 · 9,293 commit · 5,000+ release를 쌓으면서 로컬 LLM이라는 카테고리 자체를 만들어낸 사실상의 표준 추론 엔진이 됐다. Ollama·LM Studio·GPT4All·llamafile·Jan·LocalAI·koboldcpp 등 우리가 아는 거의 모든 로컬 LLM 앱이 내부적으로 llama.cpp를 깔고 그 위에 UI만 얹은 형태다.
트렌딩에 다시 올라오는 이유 + 경쟁 제품 대비 장점.
2026년 5월 트렌드시프트에 다시 25위로 진입한 건 "오랜 OSS가 새 모멘텀을 받았다"는 신호다. 최근 변동의 핵심은 세 가지: gpt-oss(OpenAI 공개 가중치 모델)의 MXFP4 네이티브 지원, multimodal 서버화(이미지·오디오 입력이 llama-server에서 1급 시민으로 승격), 그리고 WebGPU 백엔드로 브라우저에서 LLM이 돌아간다는 시연. Hugging Face가 llama.cpp 추론 엔드포인트를 자기 인프라에 박은 것도 컸다.
다만 트렌딩 자체보다 더 중요한 건 "왜 3년째 안 사라지고 더 커지는가"이다. 답은 단순하다 — vLLM·TensorRT-LLM 같은 GPU 전용 서버는 "8장의 H100이 있다"는 가정에서 시작하지만, llama.cpp는 "맥북에서도 돌아야 한다"는 가정에서 시작했다. 같은 코드가 어디서나 굴러가는 것은 우연이 아니라 의도된 설계다.
vLLM은 GPU에 올라간 모델의 throughput을 끝까지 짜내는 데이터센터 서버. PagedAttention·Continuous Batching이 핵심이고 NVIDIA GPU + CUDA가 필수다. llama.cpp는 정반대 방향 — 작은 가중치 + 낮은 메모리 + 임의 하드웨어를 우선한다. llama.cpp는 가난한 자의 vLLM이 아니라 다른 종(species)의 도구다. 둘 다 필요하지만 풀어야 할 문제가 다르다.
Transformers는 학습·연구·실험까지 다 되는 만능 도구. 단점은 무겁다 — Python 인터프리터 + PyTorch + CUDA 런타임 + 수많은 종속성. 노트북에서 7B 모델 한 번 띄우려면 디스크 30GB가 깨진다. llama.cpp는 의존성이 사실상 0개라서 brew install llama.cpp 한 줄로 끝난다. 추론 전용으로 한정한 대신, 그 한정 안에서 극단적으로 가볍다.
Ollama·LM Studio는 llama.cpp를 내부 엔진으로 깔고 그 위에 모델 매니저 + UI + 컨테이너 추상을 얹은 wrapper다. 사용자 입장에서 더 친절하다. 하지만 새 모델 아키텍처를 추가하거나, 양자화(quantization) 방식을 바꾸거나, FIM(중간 채우기)·grammar(JSON 강제)·speculative decoding·LoRA hot-swap 같은 진짜 깊은 기능이 필요하면 결국 llama.cpp 자체로 내려가야 한다. Ollama가 자동차라면 llama.cpp는 엔진이다.
MLX는 Apple Silicon 전용. MLC-LLM은 TVM 컴파일 기반으로 더 빠를 수 있지만 사용성이 무겁다. llama.cpp는 "어디서나 적당히 빠른" 포지션을 잡으며 둘 사이를 메운다. 특히 GGUF 포맷이 모델 배포의 표준 컨테이너가 되면서 — Hugging Face에서 "GGUF" 검색이 trending 정렬을 차지하는 — 사실상 락인된 생태계가 됐다.
백엔드(엔진), 프론트엔드(웹UI), 인프라(빌드·배포)를 각각 분리해서 본다.
전체 코드의 70% 이상이 C/C++. 외부 라이브러리 의존이 거의 0이라는 점이 가장 큰 특징이다. libllama(추론 그래프 + KV 캐시 관리)와 ggml(텐서 라이브러리)가 두 축이다.
| 레이어 | 역할 | 주요 파일 |
|---|---|---|
| ggml | 저수준 텐서 + 양자화 + 백엔드 추상 | ggml/src/*.c, ggml-cuda/, ggml-metal/ |
| libllama | 모델 그래프 빌드, KV 캐시, 샘플러 | src/llama-*.cpp (~50 files) |
| common | CLI args, 챗 템플릿, sampling 파라미터 | common/*.cpp |
| tools | llama-cli, llama-server, llama-bench, quantize | tools/*/main.cpp |
| gguf-py | Python 측 GGUF 파일 reader/writer | gguf-py/gguf/*.py |
struct ggml_tensor가 1급 시민이고 모든 모델 그래프는 이걸 조립해서 만든다. llama.cpp 외에 whisper.cpp(Whisper 음성 인식)·sd.cpp(Stable Diffusion)도 같은 ggml을 쓴다.v3 시점부터 tools/ui/ 폴더에 Svelte 기반 채팅 UI가 들어왔다 (2026-05-16 PR 23064으로 tools/server/webui/에서 재편됨). llama-server 실행 시 :8080에서 바로 뜬다. 의존성 없이 단일 바이너리에 정적 파일이 통째로 박혀 있는 구조라 노트북에서 띄우면 5초 안에 ChatGPT 비슷한 화면이 뜬다.
Svelte → Vite로 빌드 → build/index.html → xxd나 file_to_cpp.py로 C++ 배열로 변환 → llama-server 빌드 시 그대로 컴파일 inline. 그래서 바이너리 한 개만 가지고 다녀도 UI까지 같이 나간다. Electron이나 Node 서버가 필요 없다.
이 레포가 진짜 인상적인 건 한 코드베이스가 20개+ 백엔드와 5개+ OS를 동시에 지원한다는 점이다. cmake/, .devops/, ci/, .github/ 네 디렉토리에 그 복잡도가 다 모여있다.
| 도구 | 역할 |
|---|---|
| CMake | 크로스 플랫폼 빌드. CMakePresets.json에 macOS/Linux/Windows × CPU/CUDA/Metal/Vulkan/SYCL 프리셋 수십 개 박혀있음 |
| GitHub Actions | .github/workflows/에 30+ 워크플로 — 매 PR마다 모든 백엔드 매트릭스 빌드 + bench 회귀 테스트 |
| Docker | .devops/에 4개+ Dockerfile (cpu / cuda / rocm / vulkan) — GHCR에 자동 배포 |
| Nix flake | flake.nix로 NixOS·Determinate Nix 사용자에게 재현가능 빌드 제공 |
| XCFramework | build-xcframework.sh — iOS/visionOS/tvOS/macOS용 precompiled binary로 Swift Package에 바로 박힘 |
| Bash/PowerShell completion | llama-cli --completion-bash로 자동완성 스크립트 동적 생성 |
리눅스 커널을 처음 빌드해본 사람이라면 make menuconfig가 떠오를 거다. llama.cpp 빌드도 비슷하다 — 어떤 백엔드, 어떤 SIMD 명령어, 어떤 양자화 커널을 컴파일에 포함할지를 CMake 옵션으로 켰다 껐다 한다. 결과 바이너리가 작아지고 시작 속도가 빨라진다. -DGGML_CUDA=ON -DGGML_METAL=OFF 같은 식으로.
시스템 구조도 + 핵심 설계 패턴.
그림이 큰데 핵심은 "libllama가 백엔드 추상을 통해서만 ggml을 부르고, ggml은 그 아래에서 백엔드를 골라준다"이다. CPU 코드와 CUDA 코드가 같은 인터페이스(ggml_backend)를 구현하기 때문에, 모델 그래프 코드는 어떤 하드웨어인지 몰라도 굴러간다.
ggml_backend라는 인터페이스 하나에 alloc/free/compute/copy 같은 메소드만 정의해두고, CUDA·Metal·Vulkan 모두 그 인터페이스를 구현한다. 새 가속기(NPU·DSP)가 등장해도 인터페이스만 만족하면 된다. "동일 인터페이스, 다중 구현" 패턴 — 객체지향 책에서 본 게 실제 시스템에서 어떻게 쓰이는지 학습할 수 있는 모범 사례.
16-bit float 가중치를 8/6/5/4/3/2/1.5-bit 정수로 압축하면 7B 모델이 4GB가 된다. 그러나 단순 "그냥 자르기"가 아니라 블록 단위(보통 32개 원소)로 묶고 scale + zero point를 따로 저장하는 GGUF의 K-quant / IQ-quant 방식이다. ggml/src/ggml-quants.c에 약 5,600 라인의 비트 트릭이 있다 — SIMD intrinsics가 어떻게 정수 곱을 가속하는지 보여주는 교과서.
Transformer는 매 토큰마다 이전 토큰들의 Key/Value 텐서를 다시 계산하면 O(n²) 비용. KV 캐시는 한 번 계산한 K,V를 메모리에 두고 다음 토큰 때 재사용해서 토큰당 비용을 O(1)에 가깝게 만든다. llama-server에선 여러 사용자의 KV 캐시를 슬롯 단위로 관리해서 동시 요청을 처리한다.
큰 모델(target)이 한 토큰 뽑는 동안, 작은 모델(draft)이 미리 4~8개 토큰을 추측한다. 그러고 target이 한 번에 검증해서 맞으면 다 쓰고 틀린 시점부터 다시. 정확도는 똑같지만 속도가 2~3배 빨라진다. llama-server -m big.gguf -md draft.gguf 한 줄로 켠다.
샘플링 단계에서 다음 토큰의 logit에 grammar 마스크를 씌워서 "여기선 숫자만 나올 수 있다", "여기선 }만 가능하다" 식으로 강제한다. JSON·SQL·정규표현식 등 어떤 컨텍스트-프리 문법이든 따라간다. LLM이 절대로 형식을 깰 수 없게 만드는 트릭이라 에이전트 도구 호출의 신뢰도를 결정한다. grammars/json.gbnf 참고.
9,000+ commit이 만들어낸 폴더 지도.
llama.cpp/
├── ggml/ ← 텐서 + 양자화 + 백엔드 추상 (별도 레포로도 존재)
│ ├── include/ ← ggml.h, ggml-backend.h (외부 공개 API)
│ └── src/
│ ├── ggml.c ← 텐서 코어 (~8k LoC, ggml-quants.c 등으로 분리됨)
│ ├── ggml-quants.c ← 양자화 커널 (7k+ LoC)
│ ├── ggml-cuda/ ← NVIDIA CUDA 백엔드 (~50 .cu 파일)
│ ├── ggml-metal/ ← Apple Silicon Metal 백엔드
│ ├── ggml-vulkan/ ← Vulkan (모든 GPU)
│ ├── ggml-sycl/ ← Intel SYCL
│ ├── ggml-hip/ ← AMD HIP
│ └── ggml-cpu/ ← AVX/NEON/RVV/AMX SIMD
│
├── src/ ← libllama 본체
│ ├── llama.cpp ← 메인 진입점
│ ├── llama-model.cpp ← GGUF 로드 + 그래프 빌드 (40+ 아키텍처)
│ ├── llama-context.cpp ← KV 캐시, batching
│ ├── llama-sampler.cpp ← top-k/top-p/grammar 샘플러
│ ├── llama-vocab.cpp ← tokenizer (BPE/SPM/WPM)
│ └── llama-quant.cpp ← 양자화 변환
│
├── include/llama.h ← 공개 C API (Python·Go·Rust 바인딩이 다 이걸 부른다)
│
├── common/ ← CLI 파싱, 챗 템플릿, 샘플링 헬퍼 (재사용 공통 코드)
│
├── tools/ ← 실제 실행 가능한 도구들
│ ├── cli/ ← llama-cli (REPL 대화 모드)
│ ├── server/ ← llama-server (OpenAI 호환 REST API)
│ ├── ui/ ← Svelte 채팅 WebUI (2026-05-16 tools/server/webui/ 에서 이동)
│ ├── llama-bench/ ← 벤치마크 도구
│ ├── perplexity/ ← 모델 품질 측정
│ ├── quantize/ ← FP16 → INT8/INT4 변환
│ ├── rpc/ ← 분산 추론 (여러 머신 연결)
│ └── tts/, mtmd/ ← 음성 합성, 멀티모달
│
├── examples/ ← 미니멀 예제 (llama-simple, embedding, lookup …)
│ └── llama.android/ ← 안드로이드 앱 예제
│
├── gguf-py/ ← Python에서 GGUF 파일 read/write/inspect
│
├── grammars/ ← GBNF 샘플 (json.gbnf, c.gbnf, chess.gbnf …)
│
├── conversion/ ← Hugging Face .safetensors → GGUF 변환 스크립트
├── convert_hf_to_gguf.py ← 메인 변환기 (~3k LoC)
├── convert_lora_to_gguf.py ← LoRA 어댑터 변환
│
├── docs/ ← 빌드·백엔드·HOWTO 마크다운 (~50 문서)
├── cmake/ ← 빌드 시스템 (CMakePresets.json + helpers)
├── .devops/ ← Dockerfile, 패키지 스크립트
├── ci/ ← GitHub Actions에서 부르는 셸 스크립트
├── tests/ ← unit + integration + grammar 테스트
├── scripts/ ← sync-ggml, run-server, gen-doc 등 운영 스크립트
├── benches/ ← 하드웨어별 벤치마크 결과 데이터 (dgx-spark / mac-m2-ultra / nemotron)
├── models/ ← 토크나이저 vocab 샘플
└── pocs/ ← proof-of-concept (실험 파편)
루트 파일:
CMakeLists.txt ← 빌드 진입점
CMakePresets.json ← OS × 백엔드 프리셋
AGENTS.md, CLAUDE.md ← AI 코딩 에이전트용 컨텍스트 파일
Makefile ← 단순 wrapper (cmake 부른다)
flake.nix ← Nix 빌드
pyproject.toml ← Python convert 스크립트용
CODEOWNERS, AUTHORS ← 컨트리뷰터 1,000+ 추적
이 구조에서 배울 점은 "엔진(ggml)·라이브러리(libllama)·도구(tools)가 세 단계로 분리"되어 있다는 것이다. ggml은 LLM을 모른다 — 텐서만 안다. libllama는 OpenAI API를 모른다 — 모델 그래프만 안다. tools는 사용자만 안다. 이 계층 분리가 다른 프로젝트(whisper.cpp, sd.cpp)에서 ggml을 재활용할 수 있게 만든다.
이 레포에서 무엇을 배울 수 있는가 — 기술별 정리.
cpp-httplib·nlohmann/json·stb-image처럼 single-header 라이브러리만 쓴다. 패키지 매니저가 필요 없는 코드베이스가 어떻게 작동하는지 학습.__m256i(AVX2), vshlq_n_s32(NEON) 같은 CPU 명령어를 직접 부르는 코드가 ggml-cpu/에 가득. CPU 벡터 명령어와 친해질 절호의 기회.ggml/src/ggml-cuda/에 50+ .cu 파일. Tensor Core 활용, shared memory tiling, warp shuffle 등 CUDA 최적화 패턴의 라이브 코드.ggml-metal-impl.h·ggml-metal.metal에, Obj-C 래퍼는 ggml-metal-context.m·ggml-metal-device.m으로 분리됨. Metal로 GPGPU 코드를 짜는 흔치 않은 오픈소스 예시.llama-model.cpp의 llm_build_llama()는 attention·FFN·rmsnorm 같은 블록을 ggml_* 함수로 조립한다. 논문에서 보던 식이 코드로 어떻게 표현되는지 알 수 있다.llama-sampler.cpp에 단일 소스로. 각 알고리즘이 30~80 라인 정도로 짧다.llama-vocab.cpp 한 파일에서 비교 가능..github/workflows/build.yml 한 파일이 macOS-arm64 / Linux-x86_64 / Windows-x64 × CPU/CUDA/Vulkan/Metal 조합으로 수십 개 작업을 만든다. CI 매트릭스 설계의 실전 예제..github/workflows/release.yml 참고.어디서 어떤 모델을 굴릴 수 있는가 — 현실적인 가이드.
| 하드웨어 | 가능한 모델 크기 (Q4 양자화 기준) | 비고 |
|---|---|---|
| 라즈베리파이 4 (4GB RAM) | 1B~3B (Phi-mini, Gemma 1B) | 토큰/초 한 자릿수, 데모용 |
| 맥북 M1 8GB | 3B~7B (Mistral 7B Q4) | Metal로 30~50 t/s |
| 맥북 M3 Max 36GB | 13B~70B (Llama 3 70B Q4) | 유니파이드 메모리 덕분에 70B도 굴러감 |
| RTX 3060 12GB | 7B~13B (전체) / 30B (부분 offload) | CUDA + CPU 하이브리드 |
| RTX 4090 24GB | 30B 전체 / 70B (Q3/Q2) | 200+ t/s 가능 |
| H100 80GB / H200 141GB | 405B (DeepSeek/Llama 405B) | vLLM과 경쟁 시작 |
| Pixel 8 / iPhone 15 | 1B~3B (CoreML/QNN 백엔드) | 안드로이드/iOS 예제 폴더 참고 |
| 브라우저 (WebGPU) | ~3B | 실험 단계, demo 링크 있음 |
모델 크기와 양자화는 "사진 해상도와 JPEG 압축률"로 생각하면 쉽다. 70B 모델 FP16은 140GB짜리 RAW 사진. 같은 모델 Q4 양자화는 35GB JPEG-95. Q2는 18GB JPEG-50. 작아질수록 메모리는 줄고 화질(품질)은 떨어진다. 7B Q4 정도가 노트북에서 ChatGPT 3.5 비슷한 느낌이 나는 sweet spot.
13B Q4 모델은 약 8GB가 필요한데 OS + 다른 앱이 RAM을 잡고 있으면 swap이 폭발한다. llama-bench로 미리 측정 + -ngl 0으로 GPU 오프로드 끄고 시도해서 어디서 막히는지 분리 진단할 것.
llama-cli -hf ggml-org/gemma-3-1b-it-GGUF 한 줄로 다운로드 + 실행이 동시에 된다. 잘 돌면 더 큰 모델로 단계적으로 올린다. Hugging Face의 GGUF 정렬 탭에서 Q4_K_M 또는 Q5_K_M 양자화를 우선 시도.
난이도별 5개 — 깊이 들어가는 순서.
brew/winget으로 설치하고, 1B 모델로 대화 모드에 들어가서 5분 동안 던지고 싶었던 질문 다 던져본다.
llama-server -hf TheBloke/Mistral-7B-Instruct-v0.2-GGUF -c 4096로 띄운 다음, 평소 ChatGPT 호출하던 Python 스크립트의 base_url만 http://localhost:8080/v1으로 바꿔서 같은 코드가 그대로 동작하는지 확인. 이게 되면 거의 모든 LLM 앱을 로컬로 옮길 수 있다는 뜻.
grammars/json.gbnf를 참고해서 자기만의 스키마(예: {"action": "...", "args": {...}})를 정의하고 --grammar-file로 넘겨서, 모델이 절대 그 형식을 깨지 못하게 만든다. 실제 존재하는 샘플: c.gbnf, chess.gbnf, json_arr.gbnf 등. 이게 에이전트 도구 호출의 기본 메커니즘.
HF에서 좋아하는 작은 모델(예: microsoft/Phi-3-mini-4k-instruct) 다운받아서 convert_hf_to_gguf.py로 GGUF로 변환 → llama-quantize로 Q4_K_M·Q5_K_M·Q8_0를 각각 만들어 → 같은 프롬프트에 답변·속도·메모리가 어떻게 달라지는지 직접 측정.
docs/development/HOWTO-add-model.md를 따라 아직 지원되지 않는 신생 모델(허깅페이스 trending에서 골라봄)을 직접 추가해보기. convert_hf_to_gguf.py에 변환 클래스 추가 + llama-model.cpp에 그래프 빌더 추가. PR 통과하면 컨트리뷰터 명단에 이름이 박힌다.
8주 코스 — 매주 한 단계씩.
llama.cpp 설치 + 3B 모델로 채팅. llama-bench로 자기 컴퓨터 성능 측정. Ollama·LM Studio도 같이 깔아서 같은 모델이 다른 UI에서 어떻게 보이는지 비교.
3Blue1Brown "Attention" 영상 + Karpathy "Let's build GPT" 영상. 그런 다음 src/llama-vocab.cpp를 읽고 SentencePiece vs BPE 차이를 코드로 확인.
tools/quantize/README.md + ggml-quants.c 첫 1,000라인. K-quant·IQ-quant가 어떻게 다른지 이해. 자기 모델을 Q2_K부터 Q8_0까지 다 만들어서 perplexity로 품질 측정 (llama-perplexity 사용).
llama-context.cpp의 llama_kv_cache_* 함수들 읽기. llama-server -np 4 -c 16384로 동시 4명 요청 처리 시 GPU·메모리가 어떻게 변하는지 nvtop·asitop으로 관찰.
큰 모델 + 작은 draft 모델 조합으로 추측 디코딩 켜고 t/s 측정. convert_lora_to_gguf.py로 LoRA adapter를 GGUF로 바꿔서 베이스 모델에 hot-swap.
Mac이면 ggml-metal/, NVIDIA면 ggml-cuda/. 행렬 곱 커널(mul_mat) 하나 골라서 워크그룹·shared memory·warp 단위가 어떻게 짜였는지 분석. 직접 한 줄 고쳐서 빌드하고 llama-bench로 회귀 측정.
GBNF로 도구 호출({"tool":"...","args":{...}}) 강제 + 그 출력을 파싱해서 실제 함수 실행 → 결과를 다시 모델에 피드백하는 미니 에이전트 루프 직접 짜기. 200줄 안에 가능.
이 시점이면 코드베이스에 익숙해졌을 것. good first issue 라벨 하나 골라서 PR 제출. 메인테이너 리뷰가 가장 좋은 코드 리뷰 교실이다.
이 레포 주변에서 자주 나오는 용어 모음.
.safetensors가 PyTorch용이면 GGUF는 llama.cpp용 표준.grammars/ 폴더에 샘플.llama.vim·llama.vscode가 이 기능으로 작동.convert_lora_to_gguf.py로 llama.cpp에 붙일 수 있다.다음 한 클릭.
brew install llama.cpp && llama-cli -hf ggml-org/gemma-3-1b-it-GGUF 한 줄로 노트북에서 ChatGPT 비슷한 대화를 띄워본다. 인터넷이 끊겨도 돌아간다는 점이 핵심.base_url만 http://localhost:8080/v1로 바꿔서 같은 코드가 OpenAI API 키 없이 동작하는지 확인한다.llama-perplexity로 품질을 측정한다. 메모리·속도·품질이 어떻게 트레이드오프 되는지 직접 숫자로 본다.grammars/json.gbnf를 응용해서 모델이 절대 깨지 못하는 JSON 스키마를 만들고, 그 결과로 미니 함수 호출 에이전트를 200줄로 짠다.ggml-cuda/ 또는 ggml-metal/)에서 mul_mat 커널 한 개를 끝까지 읽어본다. SIMD·shared memory·warp 같은 단어가 추상이 아닌 실제 코드로 보이기 시작한다.