로컬 LLM을 써본 사람이라면 한 번쯤 이런 의문을 품는다. Ollama가 내부적으로 llama.cpp를 쓴다고 하는데, 왜 직접 llama.cpp를 빌드해서 실행하면 더 빠른 경우가 생기는 걸까. 같은 엔진 위에서 돌아가는 거라면 결과도 같아야 하지 않나.
사실 Ollama는 llama.cpp를 그대로 가져다 쓰지 않는다. 정확하게는 llama.cpp의 C++ 코어를 Go로 작성된 서버 레이어로 감싼 형태다. 사용자가 ollama run 명령을 실행하면 내부에서 REST API 서버가 뜨고, 토큰 생성 요청과 응답이 이 HTTP 레이어를 통해 오간다. 모델 추론 자체는 여전히 llama.cpp 코어가 담당하지만, 요청을 직렬화하고 HTTP로 주고받는 과정이 중간에 끼어든다. 이 오버헤드는 짧은 프롬프트에서 특히 두드러진다. 긴 문서를 생성할 때는 토큰당 처리 시간이 병목이 되어 차이가 묻히지만, 응답 첫 토큰이 나오기까지의 지연, 즉 TTFT(Time to First Token)를 측정하면 차이가 선명하게 드러난다.
빌드 플래그가 만드는 조용한 격차
그런데 오버헤드만으로는 설명이 되지 않는 경우도 있다. 토큰 생성 속도(토큰/초) 자체가 다를 때다. 이건 대체로 컴파일 시점의 최적화 플래그 차이에서 온다.
llama.cpp를 직접 빌드할 때는 cmake 옵션으로 Metal, CUDA, AVX2, AVX-512 같은 하드웨어 가속 경로를 명시적으로 켤 수 있다. macOS에서 Apple Silicon을 쓴다면 -DLLAMA_METAL=ON을 지정하면 GPU 셰이더를 활용한 행렬 곱셈이 활성화된다. Ollama도 Metal 백엔드를 지원하지만, 릴리스 빌드를 만들 때 설정하는 플래그가 항상 사용자가 직접 빌드할 때의 최신 최적화 상태와 일치하지는 않는다. Ollama의 llama.cpp 의존성은 특정 커밋에 고정되어 있고, 업스트림 llama.cpp가 새 하드웨어 최적화를 추가해도 Ollama가 해당 커밋을 업데이트하기 전까지는 반영되지 않는다.
예를 들어 M3 이후 칩에 추가된 Metal 셰이더 개선이나 특정 퀀타이즈 포맷(Q4_K_M, IQ4_XS 등)에 대한 커널 최적화가 llama.cpp 메인에 먼저 들어오고, Ollama 쪽에는 몇 주 뒤에 반영되는 식이다. 이 시차 동안 직접 빌드한 llama.cpp와 Ollama 사이에 눈에 띄는 속도 차가 생길 수 있다.
컨텍스트와 GPU 레이어 기본값의 함정
또 하나 간과하기 쉬운 원인이 기본값이다. llama.cpp를 CLI로 직접 실행할 때는 -ngl(num-gpu-layers) 옵션으로 몇 개의 트랜스포머 레이어를 GPU에 올릴지 명시한다. 이 값을 모델의 전체 레이어 수(예: Llama 3 8B는 32레이어)로 설정하면 추론 전체가 GPU에서 돌아간다.
Ollama는 이 값을 자동으로 감지해서 설정하려 하지만, 환경에 따라 보수적인 값이 들어가거나 VRAM(통합 메모리 포함)을 과소 추정하는 경우가 있다. 실제로 Apple Silicon 맥에서 Ollama를 쓸 때 OLLAMA_NUM_GPU_LAYERS 환경 변수를 명시하지 않으면 일부 레이어가 CPU로 떨어지는 상황이 생긴다. CPU와 GPU를 오가는 레이어 분산 처리는 단순히 느린 정도가 아니라, 메모리 버스 경합 때문에 순수 CPU 추론보다도 특정 조건에서 느려지는 역설적인 상황을 만들기도 한다.
컨텍스트 길이도 마찬가지다. OLLAMA_NUM_CTX 기본값은 2048인데, 이를 4096이나 8192로 올리면 KV 캐시가 커져서 VRAM을 더 점유하지만 동시에 prefill 속도에도 영향을 준다. 적절한 컨텍스트 크기는 모델과 메모리 용량에 따라 다르고, Ollama의 자동값이 항상 최적은 아니다.
이미지 출처: Unsplash
그렇다면 Ollama를 쓸 이유가 있는가
속도만 놓고 보면 직접 빌드한 llama.cpp가 유리할 수 있다. 그런데 실용 관점에서는 이야기가 달라진다.
Ollama는 모델 다운로드, 버전 관리, 여러 모델의 동시 관리, Open WebUI 같은 프론트엔드와의 연동을 단 몇 줄의 명령어로 해결해준다. ollama pull llama3 한 줄이면 퀀타이즈 포맷 선택, 샤드 조합, 메모리 매핑 설정을 전부 Ollama가 처리한다. 직접 llama.cpp를 빌드하려면 cmake 설정, 플래그 선택, GGUF 파일 직접 다운로드, 실행 스크립트 관리까지 손이 많이 간다. 새 모델이 나올 때마다 이 과정을 반복해야 한다.
속도 차이가 실제로 체감될 만한 상황, 예를 들어 배치 추론을 돌리거나 응답 속도가 서비스 품질에 직결되는 경우라면 llama.cpp 직접 빌드에 투자할 가치가 있다. 반면 개인 개발 환경에서 코딩 보조나 텍스트 작업을 하는 수준이라면 Ollama의 편의성이 10~20% 속도 손실을 충분히 상쇄한다.
결국 Ollama와 llama.cpp의 속도 차이는 단순한 래퍼 오버헤드가 아니라, 빌드 시점의 최적화 상태, 기본값으로 설정되는 GPU 레이어 수, HTTP 직렬화 비용이 겹쳐서 만들어지는 복합적인 결과다. 앞으로 Ollama가 llama.cpp 업스트림을 더 빠르게 추적하고, 하드웨어 감지를 정교하게 개선한다면 이 격차는 점점 좁아질 것이다. 이미 최근 릴리스에서 Metal 백엔드 업데이트 주기가 빨라지고 있다는 점은 그 방향성을 보여준다. 당장은 성능이 중요한 작업에서 OLLAMA_NUM_GPU_LAYERS를 명시하고, 컨텍스트 크기를 직접 조정하는 것만으로도 기본 설정 대비 의미 있는 차이를 만들 수 있다.
출처