본문 바로가기
Inference/Engines

llama.cpp 란?

by AtoN 2026. 1. 3.

llama.cpp란 무엇인가

llama.cpp는 GGUF 계열 모델을 CPU와 여러 GPU Backend에서 실행하는 C/C++ 추론 Runtime입니다. 로컬 실행이 쉽다는 점 때문에 옵션을 몇 개 외우는 도구처럼 보이지만, 실제 성능은 모델 구조, 양자화, Context 길이, Batch, Memory 계층, Backend가 함께 만드는 병목으로 결정됩니다.

그래서 -ngl, KV Cache Precision, -ub 같은 Flag를 만능 공식으로 외우기보다 먼저 Prompt Processing(pp)과 Token Generation(tg)을 나눠 측정해야 합니다. 같은 옵션도 CUDA, Metal, Vulkan, SYCL 같은 Backend와 Dense, MoE, Hybrid Attention 모델에 따라 효과가 달라질 수 있습니다.

이 문서는 llama.cpp의 주요 구조와 실행 옵션을 기능별로 정리하되, 변하기 쉬운 기본값과 Flag는 사용 중인 Build의 --help와 공식 Source를 최종 기준으로 봅니다.


1장. llama.cpp의 역할과 전체 아키텍처

llama.cpp는 특정 모델 자체가 아니라 학습이 끝난 언어모델을 다양한 로컬 하드웨어에서 실행하기 위한 C/C++ 기반 추론 런타임입니다.

처음에는 Llama 계열을 실행하는 프로젝트로 시작했지만 현재는 다양한 Transformer 계열과 일부 hybrid architecture를 지원합니다.

핵심 목적은 다음과 같이 정리할 수 있습니다.

적은 의존성
다양한 CPU 지원
다양한 GPU Backend
GGUF 기반 로컬 모델 실행
저비트 양자화
부분 GPU Offload
로컬 API Server
다중 요청 처리
구조화 출력
Tool Calling
Multimodal
Speculative Decoding

프로젝트 구성

llama.cpp를 이해할 때 세 층으로 나누면 편합니다.

ggml
  ↓
libllama
  ↓
실행 도구
구성 역할
ggml Tensor 표현, 연산, Backend 추상화
libllama 모델 로딩, Tokenizer, Inference Graph, Context, Cache
실행 도구 CLI, Server, Benchmark, Quantization 등

ggml은 일반 Tensor Runtime에 가깝고 libllama가 언어모델에 필요한 실행 로직을 제공합니다.

대표 도구

도구 역할
llama-cli 터미널 기반 생성과 대화
llama-server HTTP Server와 API Serving
llama-bench Prompt Processing과 Generation Benchmark
llama-quantize GGUF Weight Quantization
llama-imatrix Importance Matrix 계산
llama-perplexity Perplexity 측정
llama-mtmd-cli Multimodal 테스트와 개발

실무에서는 대부분 다음 조합을 많이 사용합니다.

모델 변환
    ↓
llama-quantize
    ↓
llama-server
    ↓
Client 또는 Agent

Inference Stack에서의 llama.cpp

LLM 시스템을 넓게 보면 llama.cpp는 다음 위치에 있습니다.

학습
Fine-tuning
RLHF
    ↓
모델 배포 파일
    ↓
llama.cpp
    ↓
Application
Agent
Chat UI
RAG

llama.cpp가 담당하는 핵심은 Inference Runtime입니다.

다음은 llama.cpp 외부에서 처리하는 경우가 많습니다.

데이터 수집
Pretraining
대규모 Fine-tuning
RAG Vector DB
Application Business Logic
Agent Planning
Workflow Engine

반대로 다음은 llama.cpp 자체가 직접 지원 범위를 넓혀 온 영역입니다.

Chat Template
Tool Calling
Grammar
JSON Schema
Reasoning Output Parsing
Multimodal Input
MCP Integration
Server Tools

기본 Server 실행 흐름

사용자 요청 하나가 처리되는 과정을 단순화하면 다음과 같습니다.

User Input
   ↓
Chat Template
   ↓
Tokenization
   ↓
Prompt Tokens
   ↓
Model Graph
   ↓
Prefill
   ↓
KV Cache
   ↓
Sampling
   ↓
Decode
   ↓
Output Tokens
   ↓
Detokenization

이후 장들은 이 각 단계를 하나씩 확장해서 설명합니다.


2장. GGUF와 모델 로딩 구조

llama.cpp의 모델 실행에서 가장 먼저 만나는 것이 GGUF입니다.

GGUF의 역할과 범위과 범위

GGUF는 llama.cpp 생태계에서 사용하는 모델 저장 형식입니다.

중요한 점은:

GGUF = Quantization

이 아니라는 것입니다.

정확히는:

GGUF
= 모델과 Metadata를 저장하는 파일 형식

Quantization
= Tensor를 낮은 정밀도로 저장하는 방법

따라서 다음 파일은 모두 GGUF가 될 수 있습니다.

F32 GGUF
F16 GGUF
BF16 GGUF
Q8 GGUF
Q4 GGUF
IQ 계열 GGUF

Hugging Face 모델의 GGUF 변환

공식 문서에서는 Hugging Face 모델을 convert_hf_to_gguf.py 계열 스크립트로 변환합니다.

개념적인 흐름은 다음과 같습니다.

HF Config
Tokenizer
Safetensors
   ↓
convert_hf_to_gguf.py
   ↓
GGUF Metadata
GGUF Tensor

공식 모델 추가 가이드에 따르면 변환 스크립트는 크게 다음 정보를 읽습니다.

Model Configuration
Tokenizer
Tensor Names
Tensor Data

그리고 이를 GGUF Metadata와 Tensor로 변환합니다.

GGUF 내부 구성

개념적으로 다음과 같이 볼 수 있습니다.

GGUF
├─ Header
├─ Key-Value Metadata
│  ├─ Architecture
│  ├─ Context Length
│  ├─ Tokenizer
│  ├─ RoPE
│  ├─ Chat Template
│  └─ 기타 정보
│
├─ Tensor Metadata
│  ├─ Tensor Name
│  ├─ Shape
│  ├─ Offset
│  └─ Type
│
└─ Tensor Data
   └─ Weight

이 Metadata 덕분에 Runtime이 모델 구조와 Tokenizer 정보를 모델 파일에서 읽을 수 있습니다.

-hf와 로컬 파일

현재 llama.cpp는 Hugging Face의 llama.cpp 호환 GGUF Repository에서 모델을 직접 가져오는 흐름도 지원합니다.

예:

llama-cli -hf ggml-org/gemma-3-1b-it-GGUF

로컬 파일은 일반적으로 다음처럼 실행합니다.

llama-cli -m model.gguf

Server도 동일한 방식으로 모델을 지정할 수 있습니다.

Model Loading과 mmap

모델을 실행할 때 모든 Byte를 단순히 복사해 RAM에 올리는 방식만 있는 것은 아닙니다.

현재 llama.cpp는 모델 로딩 모드에서 mmap, mlock 등을 지원합니다.

대표적인 개념은 다음과 같습니다.

방식 의미
mmap 파일을 Virtual Memory에 Mapping
mlock Page가 Swap이나 Compression으로 밀리는 것을 방지
mmap+mlock 두 방식 결합
dio 지원 환경에서 Direct IO
auto Runtime이 적절한 방식 선택

mmap은 OS Page Cache를 활용할 수 있기 때문에 모델 시작 시간과 메모리 관리에서 장점이 있습니다.

Chat Template

Chat 모델은 단순 문자열 하나를 받는 것이 아닙니다.

다음 Messages:

[
  {"role": "system", "content": "You are helpful."},
  {"role": "user", "content": "Hello"}
]

는 내부적으로 Chat Template을 거쳐 실제 Prompt String으로 변환됩니다.

Messages
  ↓
Jinja Chat Template
  ↓
Prompt String
  ↓
Tokenizer
  ↓
Tokens

이 구조는 뒤에서 다룰 Prompt Caching과 Tool Calling에도 직접 영향을 줍니다.


3장. Weight Quantization과 모델 경량화

로컬 LLM에서 가장 먼저 체감하는 제약은 Weight Memory입니다.

Weight Memory

단순하게 생각하면 Parameter 수와 Parameter당 Byte 수가 모델 크기를 결정합니다.

예를 들어:

7B × 2 byte
≈ 14 GB

이것이 FP16 계열의 대략적인 출발점입니다.

4-bit 수준으로 줄이면 단순 계산상:

7B × 0.5 byte
≈ 3.5 GB

가 되지만 실제 파일에는 Block Metadata와 Tensor별 혼합 정밀도 등이 있어 정확히 이 값과 같지는 않습니다.

llama.cpp 양자화 계열

현재 llama-quantize는 매우 다양한 형식을 지원합니다.

대표적인 형식은 다음과 같습니다.

형식 성격
Q8_0 높은 정밀도와 큰 크기
Q6_K 높은 품질 유지
Q5_K_M 품질과 용량 절충
Q4_K_M 널리 사용되는 4-bit급 절충
Q4_K_S 조금 더 작은 크기
Q3_K_* 더 공격적인 압축
IQ4_NL, IQ4_XS Non-linear I-Quant
IQ2_*, IQ3_* 낮은 bit 계열
MXFP4_MOE MoE용 MXFP4 계열
F16, BF16, F32 높은 정밀도

Q4_K_M 해석

이 이름을 부분별로 보면:

Q4
4-bit급 Quantization

K
K-Quant 계열

M
Medium 성격의 Preset

여기서 중요한 것은 Q4_K_M이 모든 Tensor를 동일한 4-bit로 저장한다는 의미가 아니라는 것입니다.

Preset에 따라 중요 Tensor에 서로 다른 정밀도를 배치할 수 있습니다.

따라서 모델 전체 평균 Bit와 특정 Tensor Bit는 다를 수 있습니다.

Importance Matrix

낮은 Bit에서 품질 손실을 줄이기 위해 llama.cpp는 Importance Matrix를 지원합니다.

Calibration Dataset
   ↓
llama-imatrix
   ↓
Importance Matrix
   ↓
llama-quantize

공식 llama-imatrix 문서는 주어진 Text Dataset에서 Importance Matrix를 계산하고 이를 Quantization 품질 향상에 사용할 수 있다고 설명합니다.

예:

llama-imatrix \
  -m model.gguf \
  -f calibration-data.txt \
  -o imatrix.gguf

이후:

llama-quantize \
  --imatrix imatrix.gguf \
  model-f16.gguf \
  model-q4_k_m.gguf \
  q4_k_m

Quantization 선택 기준과 Trade-off과 Trade-off

Quantization은 단순히 파일 크기만 보고 선택하면 안 됩니다.

봐야 할 항목은 다음과 같습니다.

기준 내용
RAM 또는 VRAM 모델이 실제 Memory에 들어가는지
품질 Task 정확도 유지 여부
Decode 속도 Memory Bandwidth와 Kernel 효율
Prefill 속도 Matrix 연산 효율
Backend 해당 Type 최적화 수준
Hardware CPU SIMD, GPU Kernel 지원
Context KV Cache까지 포함한 총 Memory

실무에서는 동일 모델에 여러 Quant를 준비하고 실제 Task Evaluation과 Benchmark를 같이 보는 편이 안전합니다.


4장. CPU와 GPU Backend 및 Layer Offload

llama.cpp의 가장 큰 특징 중 하나는 특정 GPU Vendor에 종속되지 않는다는 점입니다.

주요 Backend

현재 프로젝트는 여러 Backend를 지원합니다.

대표적인 예는 다음과 같습니다.

Backend 주요 환경
CPU x86, ARM
Metal Apple Silicon
CUDA NVIDIA
HIP AMD
Vulkan 여러 GPU
SYCL Intel 중심
OpenCL 일부 모바일 GPU
CANN Ascend
RPC Remote Device

지원 범위는 모델과 연산자에 따라 달라질 수 있으므로 실제 빌드 로그를 확인해야 합니다.

CPU 추론

CPU 추론의 성능은 다음 요소에 영향을 받습니다.

Core 수
Memory Bandwidth
SIMD 지원
NUMA
Thread 배치
Quantization Kernel

특히 양자화 Weight를 사용하는 Decode에서는 Memory Bandwidth가 병목이 되는 경우가 많습니다.

GPU Layer Offload

-ngl 또는 --n-gpu-layers는 llama.cpp에서 매우 자주 사용하는 옵션입니다.

예:

llama-server \
  -m model.gguf \
  -ngl 99

개념적으로는 Transformer Layer를 GPU에 배치하는 것입니다.

Embedding
Layer 0
Layer 1
Layer 2
...
Layer N
Output

중 가능한 Layer를 Accelerator로 Offload합니다.

모델 전체가 GPU Memory에 들어가지 않아도 일부 Layer만 GPU에 두고 나머지는 CPU에서 처리할 수 있습니다.

Hybrid 실행

예:

GPU
Layer 0
Layer 1
...
Layer 19

CPU
Layer 20
...
Layer 31

이 방식은 큰 모델을 제한된 VRAM에서 실행할 수 있게 하지만 CPU와 GPU 사이 Data Transfer가 증가할 수 있습니다.

따라서 ngl을 높이는 것이 항상 선형적인 속도 향상을 의미하지는 않습니다.

Apple Silicon

Apple Silicon은 전통적인 CPU RAM과 GPU VRAM 분리 구조와 다릅니다.

CPU
  ↘
   Unified Memory
  ↗
GPU

CPU와 GPU가 Unified Memory를 공유하기 때문에 "VRAM에 모델이 들어가는지"보다 전체 Memory Budget을 보는 편이 정확합니다.

다만 GPU가 많은 Memory를 사용하면 OS와 Application이 사용할 Memory도 줄어들기 때문에 전체 시스템 여유량은 중요합니다.

Multi-GPU

llama.cpp는 Multi-GPU 환경에서 Layer나 Row 등을 분배할 수 있는 옵션을 제공합니다.

대표 개념:

split-mode
main-gpu
tensor-split

이 영역은 Backend와 Hardware 구성에 따라 최적 설정이 크게 달라지므로 동일 모델로 Benchmark하는 방식이 가장 안전합니다.


5장. Prefill과 Decode 기반 추론 구조

LLM 추론 성능을 제대로 보기 위해서는 Prefill과 Decode를 반드시 분리해야 합니다.

전체 추론 단계

Text
  ↓
Tokenization
  ↓
Prompt Tokens
  ↓
Prefill
  ↓
KV Cache
  ↓
Logits
  ↓
Sampling
  ↓
Decode
  ↓
Next Token

Prefill

Prefill은 입력 Prompt 전체를 처리하는 단계입니다.

다음과 같은 입력이 모두 Prefill 대상입니다.

System Prompt
Few-shot Examples
Tool Schema
RAG Documents
Conversation History
User Query

Prompt가 길면 Prefill 계산량이 커집니다.

Prefill은 많은 Token을 Batch로 처리할 수 있기 때문에 GPU Parallelism을 잘 활용할 수 있습니다.

Decode

Decode는 다음 Token을 하나씩 생성합니다.

Token t
  ↓
KV Cache 참조
  ↓
Forward
  ↓
Logits
  ↓
Sampling
  ↓
Token t+1

Autoregressive 구조 때문에 순차성이 큽니다.

이 때문에 Prefill과 Decode의 Hardware 병목은 다를 수 있습니다.

TTFT와 TPOT

서비스 Latency에서 자주 사용하는 개념입니다.

TTFT
Time To First Token

TPOT
Time Per Output Token

긴 Prompt에서는 TTFT가 크게 증가할 수 있습니다.

반대로 Prompt가 짧고 출력이 길다면 Decode 단계가 전체 지연의 대부분을 차지할 수 있습니다.

Batch와 UBatch

llama.cpp에서는 다음 옵션을 자주 봅니다.

-b, --batch-size
-ub, --ubatch-size

공식 llama-bench 현재 기본값은:

batch-size   2048
ubatch-size   512

Batch는 논리적인 처리 단위이고 UBatch는 실제 Graph가 한 번에 처리하는 Physical Micro-batch 한도와 연결됩니다.

특히 Prefill 성능과 Memory 사용량에 영향을 줍니다.

llama-bench의 pp와 tg

공식 llama-bench는 세 종류의 Test를 제공합니다.

표기 의미
pp Prompt Processing
tg Text Generation
pg Prompt Processing + Generation

예:

pp512
tg128

Prompt Processing 속도와 Decode 속도를 분리해서 볼 수 있다는 것이 중요합니다.


6장. KV Cache와 Context 메모리

KV Cache는 llama.cpp Memory 최적화에서 Weight 다음으로 중요한 요소입니다.

KV Cache의 역할

Transformer Attention에서 각 Token은 Key와 Value를 만듭니다.

Autoregressive Generation에서 과거 Token의 K와 V는 변하지 않으므로 다시 계산할 필요가 없습니다.

Token 1
K1 V1 저장

Token 2
K1 V1 재사용
K2 V2 저장

Token 3
K1 V1 K2 V2 재사용
K3 V3 저장

이 저장 공간이 KV Cache입니다.

KV Cache와 Context Length

일반적인 Full Attention Transformer에서는 KV Cache Memory가 Context Length에 거의 선형적으로 증가합니다.

개념적으로:

KV Memory
∝
Layer 수
× KV Head 수
× Head Dimension
× Context Length
× K와 V
× Dtype Size

따라서 Context를 8K에서 32K로 늘리면 KV Memory도 큰 폭으로 증가합니다.

MHA와 GQA

MHA에서는 Query, Key, Value Head 수가 비슷합니다.

Q = 32
K = 32
V = 32

GQA에서는 여러 Query Head가 적은 K/V Head를 공유합니다.

Q = 32
K = 8
V = 8

따라서 GQA는 KV Cache Memory를 크게 줄일 수 있습니다.

KV Cache Quantization

Weight Quantization과 KV Cache Quantization은 서로 다른 최적화입니다.

Weight Quantization
모델 Weight를 줄임

KV Cache Quantization
Runtime Context State를 줄임

현재 llama.cpp CLI 문서에서는 K와 V Cache Type을 별도로 지정할 수 있습니다.

-ctk, --cache-type-k
-ctv, --cache-type-v

현재 공식 문서에 나열된 Type 예:

f32
f16
bf16
q8_0
q4_0
q4_1
iq4_nl
q5_0
q5_1

기본값은 K와 V 모두 f16입니다.

KV Offload

KV Cache를 Accelerator 쪽에 둘지 Host 쪽에 둘지도 성능과 Memory에 영향을 줍니다.

현재 CLI는 KV Cache Offload를 제어하는 옵션을 제공합니다.

--kv-offload
--no-kv-offload

GPU에 KV를 유지하면 Data Movement를 줄일 수 있지만 GPU Memory 사용량이 증가합니다.

Architecture별 KV Cache 차이

모든 모델이 동일한 KV 구조를 갖지는 않습니다.

최근 모델은 다음과 같은 구조를 사용할 수 있습니다.

Sliding Window Attention
MLA
Recurrent State
Hybrid Attention

따라서 "Layer 수 × Head 수" 식은 기본 이해용이며 실제 Memory 계산은 Model Architecture를 확인해야 합니다.


7장. Prompt Caching과 Prefix Reuse

Prompt Caching은 llama.cpp Agent Serving에서 특히 중요한 기능입니다.

KV Cache와 Prompt Cache

둘은 연결되어 있지만 범위가 다릅니다.

구분 KV Cache Prompt Cache
재사용 범위 한 Generation 내부 여러 Request
재사용 대상 과거 Token의 K/V 공통 Prefix의 계산 State
주요 효과 Decode 계산 절감 반복 Prefill 절감
체감 지표 Decode tok/s TTFT, Prompt Time

Prefix Reuse

예를 들어 Agent가 매 요청마다 10,000 Token의 System Prompt와 Tool Schema를 보낸다고 하겠습니다.

Request 1

[Static Prefix 10000]
[User A]

Request 2

[Static Prefix 10000]
[User B]

공통 Prefix가 동일하다면 두 번째 요청에서 앞쪽 10,000 Token을 다시 Prefill할 필요가 없습니다.

기존 State
████████████████████

새 Request
██████████████████████

재사용
████████████████████

신규 계산
                    ██

cache_prompt

공식 llama-server 문서는 cache_prompt=true일 때 새 Prompt를 이전 Completion의 Prompt와 비교하고 보지 못한 Suffix만 평가한다고 설명합니다.

현재 기본값은 true입니다.

{
  "prompt": "...",
  "cache_prompt": true
}

Server 차원에서도 다음 옵션이 있습니다.

--cache-prompt
--no-cache-prompt

현재 기본은 활성화입니다.

Prefix 기준

Prompt Cache는 사람이 보는 문자열이 아니라 실제 Token Sequence 관점에서 이해해야 합니다.

다음 요소는 Cache Hit을 깨뜨릴 수 있습니다.

변경 요소 영향
System Prompt 앞부분 Token 변화
Chat Template 전체 Formatting 변화 가능
Tool Schema Token Sequence 변화
Tool 순서 직렬화 결과 변화
Timestamp 해당 위치부터 Miss
Random ID 해당 위치부터 Miss
Conversation History 변경 지점 이후 Miss
Reasoning Format Template 변화 가능

Cache Hit과 Cache Miss

Cache Hit:

Previous
AAAA BBB

Current
AAAA CCC

AAAA 재사용

Cache Miss:

Previous
AAAA BBB

Current
XXAA CCC

앞부분부터 다르면 재사용 범위가 크게 줄어듭니다.

cache_reuse

cache_prompt와 cache_reuse는 같은 기능이 아닙니다.

공식 Server 문서에서 --cache-reuse N은 최소 N Token 크기의 Cached Chunk를 KV Shifting으로 재사용하려는 옵션입니다.

현재 기본값은 0, 즉 비활성입니다.

cache_prompt
공통 Prefix 재사용

cache_reuse
Cached Chunk 재사용 시도

Host RAM Prompt Cache

현재 llama-server는 Host RAM Prompt Cache를 제공합니다.

옵션:

-cram, --cache-ram N

현재 공식 문서 기본값:

8192 MiB

특수값:

-1 = 제한 없음
 0 = 비활성

이 기능은 계산된 Prompt State를 Host RAM에도 유지해 Slot 밖에서도 재사용 가능성을 높이는 방향입니다.

Idle Slot Cache

현재 다음 옵션도 있습니다.

--cache-idle-slots
--no-cache-idle-slots

공식 문서 기준 기본 활성이고 cache-ram이 필요합니다.

Idle Slot State를 Prompt Cache로 보관하는 데 사용됩니다.

Context Checkpoint

현재 Server는 Slot당 Context Checkpoint를 지원합니다.

--ctx-checkpoints
--checkpoint-min-step

현재 공식 기본값:

ctx-checkpoints       32
checkpoint-min-step 8192

SWA와 Hybrid Model처럼 임의 Prefix로 되돌아가기 어려운 구조에서 Context State Snapshot이 중요한 역할을 할 수 있습니다.

Cache 사용 시 Determinism

공식 Server 문서는 Backend와 Batch Size 차이 때문에 cache_prompt 활성 시 Logits가 Bit-for-bit 동일하지 않을 수 있으며 결과가 비결정적으로 달라질 가능성을 언급합니다.

따라서 완전한 Reproducibility가 필요한 Evaluation에서는 Cache On과 Off 조건을 명시해야 합니다.


8장. Slot과 Context 관리

Prompt Caching을 이해하려면 llama-server의 Slot 구조를 함께 봐야 합니다.

Slot

Server는 여러 Request를 처리하기 위해 실행 Context를 Slot 단위로 관리합니다.

llama-server

Slot 0
Slot 1
Slot 2
Slot 3

개념적으로 Slot에는 다음 State가 연결됩니다.

Prompt Tokens
Processed Tokens
KV State
Generated Tokens
Sampling State
Timing
Context State

Parallel Slot

현재 Server의 Slot 수는 다음 옵션으로 설정합니다.

-np, --parallel N

현재 기본값은 -1, 즉 Auto입니다.

Parallel Slot이 많으면 동시 요청을 더 많이 처리할 수 있지만 KV Memory와 Scheduling 복잡도도 증가합니다.

Continuous Batching

현재 Server는 Continuous Batching을 지원하며 공식 문서상 기본 활성입니다.

-cb, --cont-batching

기존 Request가 Decode 중이라고 해서 새 Request가 반드시 완료까지 기다릴 필요가 없습니다.

Time →

A A A A A A
    B B B B
        C C C

여러 Sequence를 동적으로 Batch에 넣을 수 있습니다.

Unified KV

현재 Server는 Unified KV Buffer를 지원합니다.

--kv-unified
--no-kv-unified

공식 문서에서는 Slot 수가 Auto일 때 Unified KV가 기본 활성일 수 있다고 설명합니다.

개념적인 차이:

고정 영역 방식

Slot 0 [          ]
Slot 1 [          ]
Slot 2 [          ]


Unified KV

Shared Pool
[Slot0][Free][Slot1][Free][Slot2]

Unified KV는 Sequence마다 Context 사용량이 다를 때 Memory를 더 유연하게 쓸 수 있습니다.

kv-unified-per-slot

현재:

--kv-unified-per-slot N

옵션을 통해 Parallel Slot당 Context Limit을 지정할 수 있습니다.

공식 문서에서는 별도의 --ctx-size가 없을 때 Shared KV Pool을 n_parallel × N으로 잡는 동작을 설명합니다.

Context Shift

Context Window가 가득 찼을 때 오래된 Token 일부를 제거하고 최근 Token을 유지하는 방식입니다.

현재 Server 옵션:

--context-shift
--no-context-shift

공식 문서 기준 기본 비활성입니다.

개념:

Before

[System][Old][Old][Recent][Generation]

After

[Keep][Recent][Generation][Free]

Context Shift는 장기 Memory와 동일하지 않습니다.

Context 밖으로 제거된 정보는 더 이상 직접 Attention할 수 없습니다.

Slot State 저장

Server는 Slot State를 저장하고 복원하는 기능도 제공합니다.

이 기능은 장시간 Context를 File로 보관하거나 특정 Session State를 복원하는 데 활용할 수 있습니다.

하지만 "Restore 성공"과 "실제 KV Reuse가 발생함"은 별도 검증이 필요합니다.

운영에서는 다음을 함께 봐야 합니다.

Cached Tokens
Prompt Time
TTFT
Server Log

9장. llama-server와 API Serving

llama-server는 llama.cpp를 Application에서 사용하는 핵심 진입점입니다.

Server 기능 범위

현재 공식 Server 문서는 다음 기능들을 명시합니다.

F16과 Quantized Inference
CPU와 GPU
OpenAI Compatible Chat
OpenAI Compatible Responses
Embeddings
Anthropic Compatible Messages
Reranking
Parallel Decoding
Continuous Batching
Multimodal
Monitoring
Schema-constrained JSON
Function Calling
Tool Use
Speculative Decoding
Web UI

기본 Server 실행

기본 예:

llama-server \
  -m model.gguf \
  -c 8192 \
  -ngl 99

기본적으로 HTTP Server가 실행되고 Client에서 API를 호출할 수 있습니다.

OpenAI 호환 API

기존 OpenAI Client를 로컬 Server에 연결하는 패턴이 가능합니다.

개념적으로:

OpenAI SDK
   ↓
Base URL 변경
   ↓
llama-server

이를 통해 Application Code를 크게 바꾸지 않고 로컬 모델로 교체할 수 있습니다.

Chat Template

Server의 Chat API는 Messages를 Model-specific Template에 맞춰 변환합니다.

Messages
  ↓
Jinja Template
  ↓
Prompt
  ↓
Tokenizer

Template이 Tool Calling과 Reasoning Format을 이해하는 데 매우 중요합니다.

Structured Output

Server는 Grammar와 JSON Schema 기반 제약을 지원합니다.

대표 옵션:

--grammar
--grammar-file
--json-schema
--json-schema-file

Request에서도 JSON Schema를 지정할 수 있습니다.

Prompt에 단순히:

JSON으로 답해

라고 쓰는 것과 다릅니다.

Prompt Instruction
형식을 따르도록 유도

Grammar 또는 JSON Schema
허용 가능한 Token 경로를 제약

Function Calling과 Tool Use

현재 공식 Server 문서는 Function Calling과 Tool Use를 지원한다고 명시합니다.

개념적인 Agent Loop:

User
  ↓
Model
  ↓
Tool Call
  ↓
Tool Execution
  ↓
Tool Result
  ↓
Model
  ↓
Final Answer

Model마다 Tool Call Format이 다르기 때문에 Chat Template과 Parser가 중요합니다.

Server Tools와 MCP

현재 Server는 Built-in Server Tool과 MCP 관련 기능도 포함하고 있습니다.

공식 문서에는 --tools 또는 --agent를 활성화하면 File Read/Write 같은 민감한 Capability가 노출될 수 있다는 보안 주의가 있습니다.

따라서 Local Agent를 운영할 때 다음을 같이 설계해야 합니다.

API Key
CORS
Reverse Proxy
Filesystem Boundary
Sandbox
Tool Allowlist
Approval

Reasoning Model

현재 Server는 Reasoning 관련 옵션도 제공합니다.

예:

--reasoning
--reasoning-format
--reasoning-effort
--reasoning-budget
--reasoning-preserve

이는 Reasoning 능력을 새로 만드는 기능이 아니라 해당 모델의 Template과 Output Contract를 Runtime에서 처리하는 기능입니다.


10장. 추론 가속과 확장 기능

llama.cpp에는 Weight Quantization 외에도 여러 가속 기능이 있습니다.

Flash Attention

Flash Attention은 Attention 계산의 Memory Access를 줄이는 최적화 계열입니다.

Prompt Cache와는 목적이 다릅니다.

Prompt Cache
이미 계산한 Prefix를 재사용

Flash Attention
새로 계산해야 하는 Attention을 효율화

긴 Context와 GPU Backend에서 효과가 클 수 있습니다.

Speculative Decoding

공식 llama.cpp 문서는 Speculative Decoding을 다음 원리로 설명합니다.

Draft
여러 Token을 빠르게 예측
  ↓
Target Model
한 Batch에서 검증
  ↓
승인된 Token을 여러 개 진행

현재 Server는 여러 Speculative 방식과 Draft Model 방식을 지원합니다.

대표적인 범주:

Draft Model
EAGLE-3
N-gram 계열
MTP 계열

Draft Prediction의 Acceptance가 높을수록 효율이 좋아집니다.

Prompt Cache와 Speculative Decoding의 차이

기능 병목
Prompt Caching 반복 Prefill
Flash Attention Attention 계산
Speculative Decoding 순차 Decode
Weight Quantization Weight Memory와 Compute
KV Quantization Context Memory

하나의 기능이 모든 병목을 해결하는 것이 아닙니다.

LoRA

llama.cpp는 Runtime에서 LoRA Adapter 적용을 지원합니다.

대표 개념:

Base GGUF
  +
LoRA Adapter
  ↓
Inference

Adapter를 자주 바꾸는 Multi-user Serving에서는 Batching 효율에 영향이 생길 수 있으므로 실제 Workload Benchmark가 필요합니다.

Multimodal

현재 공식 Multimodal 문서는 libmtmd 기반으로 다음 입력을 지원한다고 설명합니다.

Image
Audio
Video

대표 실행 도구:

llama-cli
llama-server
llama-mtmd-cli

일반적인 실행:

llama-server \
  -m model.gguf \
  --mmproj projector.gguf

호환 Hugging Face Repository를 사용하는 경우 -hf 경로도 지원합니다.

Multimodal Memory

Multimodal에서는 Text Model 외에 Projector와 Visual 또는 Audio Token이 추가되기 때문에 Memory와 Context 비용이 증가할 수 있습니다.

따라서 Image 입력이 있는 Agent는 Text-only Context와 동일한 기준으로 Context Budget을 잡으면 안 됩니다.


11장. 성능 측정과 최적화

llama.cpp 최적화에서 가장 중요한 것은 측정 순서입니다.

llama-bench

공식 llama-bench는 다음 Test를 제공합니다.

pp
Prompt Processing

tg
Text Generation

pg
Prompt Processing + Generation

각 Test는 평균 Token/s와 표준편차를 제공합니다.

공식 문서는 Tokenization과 Sampling 시간이 llama-bench 측정에 포함되지 않는다고 명시합니다.

따라서 Server 실제 Latency와 동일하다고 보면 안 됩니다.

기본 측정 지표

지표 의미
PP tok/s Prefill Throughput
TG tok/s Decode Throughput
TTFT 첫 Token까지 지연
TPOT 출력 Token당 지연
RAM Host Memory
VRAM Accelerator Memory
Cache Hit Prompt Prefix 재사용량
Concurrency 동시 처리 성능
Task Success 실제 업무 성공률

Agent Benchmark

Agent는 일반 Chat Benchmark와 다른 지표가 필요합니다.

전체 Task 완료 시간
LLM 호출 횟수
총 Prompt Token
Cached Prompt Token
Tool Call 횟수
Tool 실행 시간
성공률

Agent에서 Decode tok/s만 비교하면 실제 병목을 놓칠 수 있습니다.

튜닝 순서

권장 흐름:

1. 모델 크기
2. Weight Quantization
3. GPU Offload
4. Context Size
5. Flash Attention
6. Batch와 UBatch
7. KV Dtype
8. Prompt Cache
9. Parallel Slot
10. Speculative Decoding

한 번에 옵션을 여러 개 바꾸지 않는 것이 중요합니다.

Model과 Quantization

가장 먼저 모델이 목표 Hardware에 안정적으로 들어가는지 확인합니다.

Weight Memory
+
KV Memory
+
Compute Buffer
+
OS 여유 Memory

모델 Weight만 Memory에 맞는다고 끝이 아닙니다.

Context Size

Context를 필요 이상으로 크게 잡으면 KV Memory를 낭비합니다.

예:

실제 평균 Prompt 4K
설정 Context 64K

라면 Long Context가 정말 필요한지 먼저 확인합니다.

KV Dtype

Long Context에서 Memory가 부족하면 K와 V Cache Type을 낮추는 방법을 테스트할 수 있습니다.

다만:

Memory 절감
Quality
Speed
Backend Kernel
Flash Attention

을 같이 측정해야 합니다.

Prompt Cache

Agent처럼 고정 Prefix가 긴 Workload에서는 다음 지표가 핵심입니다.

Cached Tokens
Prompt Processing Time
TTFT

Cache Hit이 높아도 실제 TTFT가 줄지 않는다면 다른 병목을 찾아야 합니다.

Server Benchmark

llama.cpp 저장소에는 llama-server를 실제 OpenAI Compatible API로 호출하는 Benchmark Tool도 있습니다.

SPEED-Bench Client는 Throughput, Latency, Draft Acceptance 등을 측정합니다.

Multi-user Serving이나 Speculative Decoding 검증에 유용합니다.


12장. llama.cpp의 실무 적용과 Runtime 비교

마지막으로 llama.cpp를 어떤 환경에서 선택할지 정리합니다.

llama.cpp의 강점

llama.cpp의 대표적인 강점은 다음과 같습니다.

GGUF 생태계
CPU 실행
Apple Silicon
다양한 GPU Backend
부분 GPU Offload
저비트 Quantization
낮은 배포 의존성
Local Server
Prompt Cache
Multimodal
Tool Calling
Structured Output

특히 범용 PC와 On-device 환경에서 강합니다.

llama.cpp와 Ollama

Ollama는 사용자 경험과 모델 관리 계층을 더 높은 수준에서 제공합니다.

개념적으로:

Application
   ↓
Ollama
   ↓
llama.cpp 계열 Runtime

와 같은 추상화로 이해할 수 있습니다.

직접 Runtime 옵션과 Server 내부를 튜닝하려면 llama.cpp가 더 직접적이고, 모델 실행과 관리 경험을 단순화하려면 Ollama 계열이 편할 수 있습니다.

llama.cpp와 vLLM

vLLM은 GPU Server Throughput과 높은 Concurrency에 강점을 두는 Runtime입니다.

대표 개념:

Paged KV Cache
Continuous Batching
High-throughput Serving

반면 llama.cpp는:

CPU
Metal
GGUF
Hybrid Offload
Local Runtime

범위가 강합니다.

llama.cpp와 SGLang

SGLang은 Agent와 Structured Workload, Prefix Reuse가 많은 Server 환경에서 강하게 발전해 왔습니다.

대표 개념:

RadixAttention
Prefix Tree
Serving Runtime
Structured Generation

llama.cpp의 Prompt Cache는 Slot과 KV State, Host Prompt Cache를 중심으로 발전하고 있고 SGLang은 Prefix Tree를 적극적으로 이용한다는 차이가 있습니다.

llama.cpp와 ONNX Runtime

ONNX Runtime은 LLM 전용 Runtime이 아니라 범용 Machine Learning Runtime입니다.

ONNX Runtime
Language
Vision
Audio
General Graph

llama.cpp
LLM 중심
GGUF 중심
Local Generative Inference

NPU Execution Provider가 중요한 환경에서는 ONNX Runtime이 더 적합할 수 있습니다.

반면 GGUF 기반 로컬 LLM을 빠르게 배포할 때 llama.cpp의 생태계가 편리합니다.

Runtime 선택 표

기준 llama.cpp vLLM SGLang ONNX Runtime
로컬 CPU 강함 약함 약함 강함
Apple Silicon 강함 제한적 제한적 가능
GGUF 핵심 비핵심 비핵심 사용 안 함
GPU 대규모 Serving 가능 강함 강함 용도별
Prefix Reuse 지원 지원 강함 직접 설계 필요
Agent Serving 가능 가능 강함 상위 로직 필요
다양한 ML Task LLM 중심 LLM 중심 LLM 중심 강함
NPU 제한적 또는 Backend별 주력 아님 주력 아님 강점

실무 선택 기준

범용 PC 로컬 Agent

GGUF
CPU 또는 GPU Hybrid
Apple Silicon 또는 Windows PC
Tool Calling
Prompt Caching

이 중요하면 llama.cpp가 매우 자연스러운 선택입니다.

대규모 GPU API Server

높은 Concurrency
GPU Cluster
Throughput
Paged KV

가 핵심이라면 vLLM이나 SGLang을 함께 비교하는 것이 좋습니다.

NPU 중심 Edge 배포

NPU Execution Provider
Vendor Runtime
Operator Graph

가 중요하면 ONNX Runtime 계열을 검토할 가치가 큽니다.


llama.cpp 전체 흐름

지금까지 내용을 하나로 연결하면 다음과 같습니다.

Hugging Face Model
        ↓
     GGUF 변환
        ↓
Weight Quantization
        ↓
     Model Load
        ↓
CPU / GPU Backend
        ↓
   Chat Template
        ↓
    Tokenization
        ↓
      Prefill
        ↓
     KV Cache
        ↓
Prompt Prefix 비교
        ↓
Cache Hit 또는 Miss
        ↓
Slot과 Context 관리
        ↓
      Decode
        ↓
     Sampling
        ↓
    llama-server
        ↓
Application / Agent

Agent 환경에서는 여기에 다음 계층이 더 중요해집니다.

Stable System Prompt
Stable Tool Schema
Memory
Conversation
Current User Input
       ↓
Prefix Reuse
       ↓
Lower TTFT

최종 요약

llama.cpp를 제대로 이해하려면 Q4_K_M 같은 양자화 이름이나 실행 옵션만 외우는 방식에서 벗어나야 합니다.

가장 중요한 연결은 다음입니다.

GGUF
  ↓
Weight Memory
  ↓
Backend와 Offload
  ↓
Prefill
  ↓
KV Cache
  ↓
Prompt Cache
  ↓
Slot과 Context
  ↓
Decode
  ↓
Server

Weight Quantization은 모델 자체의 Memory를 줄이고, KV Quantization은 Context Memory를 줄이며, Prompt Caching은 반복 Prefill을 줄입니다.

즉 세 기능은 모두 "경량화 또는 가속"과 관련 있지만 해결하는 병목이 다릅니다.

특히 Agent에서는 매 Step마다 System Prompt와 Tool Schema가 반복되므로 단순 Decode tok/s보다 다음 지표가 중요합니다.

Cached Prompt Tokens
Prompt Processing Time
TTFT
전체 Task 완료 시간

결국 llama.cpp 최적화는 옵션을 많이 켜는 문제가 아니라 내 모델, 내 Hardware, 내 Context, 내 Workload에서 실제 병목을 측정하고 그 병목에 맞는 기능을 적용하는 문제입니다.


주요 개념 한 번에 정리

개념 의미
GGUF llama.cpp 모델 저장 형식
Quantization Weight 정밀도 감소
-ngl GPU Layer Offload
Prefill Prompt 전체 처리
Decode 다음 Token 순차 생성
KV Cache 과거 Token K/V 저장
KV Quantization Runtime K/V State 저정밀화
Prompt Cache Request 사이 Prefix State 재사용
Slot Server의 Inference Context 단위
Continuous Batching 실행 중 Request를 동적으로 Batch에 추가
Unified KV 여러 Sequence가 공유하는 KV Pool
Context Shift 가득 찬 Context에서 일부 과거 Token 제거
Flash Attention Attention Kernel 최적화
Speculative Decoding Draft를 이용한 Decode 가속
Grammar 생성 가능한 Token 구조 제약
JSON Schema JSON 구조 기반 생성 제약
Tool Calling 모델이 외부 기능 호출
llama-bench llama.cpp 성능 Benchmark

참고자료

llama.cpp 공식 자료

프로젝트

llama.cpp
https://github.com/ggml-org/llama.cpp

모델과 GGUF

Models and GGUF
https://github.com/ggml-org/llama.cpp/blob/master/docs/models.md

Model Architecture 추가 가이드
https://github.com/ggml-org/llama.cpp/blob/master/docs/development/HOWTO-add-model.md

llama-server

llama-server README
https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md

llama-server Development Documentation
https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README-dev.md

Quantization

llama-quantize
https://github.com/ggml-org/llama.cpp/blob/master/tools/quantize/quantize.cpp

Importance Matrix
https://github.com/ggml-org/llama.cpp/blob/master/tools/imatrix/README.md

Benchmark

llama-bench
https://github.com/ggml-org/llama.cpp/blob/master/tools/llama-bench/README.md

llama-server Benchmark
https://github.com/ggml-org/llama.cpp/blob/master/tools/server/bench/README.md

SPEED-Bench Client
https://github.com/ggml-org/llama.cpp/blob/master/tools/server/bench/speed-bench/README.md

Speculative Decoding

Speculative Decoding
https://github.com/ggml-org/llama.cpp/blob/master/docs/speculative.md

Multimodal

Multimodal
https://github.com/ggml-org/llama.cpp/blob/master/docs/multimodal.md

Runtime 비교

vLLM Documentation
https://docs.vllm.ai/

SGLang Documentation
https://docs.sglang.ai/

댓글