본문으로 건너뛰기
페이지 목차
이 페이지에서 검색

로컬 LLM

이 페이지에 묻기

로컬 LLM · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.

생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.

LOCAL · LLM

로컬 LLM

생성 수정

로컬 모델 실행과 GPU·메모리 이해부터 서빙·RAG·도구 호출·업무형 앱 구현까지 차례로 살펴봅니다.

42개 문서 · 2일차 · 13 / 42

12차시 · GGUF와 경량 LLM

지도 위치 : 2일차 · ②모델 파일 층(GGUF) × ③추론 엔진(llama.cpp) × ①하드웨어(VRAM ↔ RAM) | 이전: 11차시 8bit · 4bit 양자화 실습 | 다음: 13차시 LLM 추론 파라미터 최적화 키워드 : GGUF 구조, llama.cpp, GGUF 모델 실행, CPU · GPU 혼합 추론

이 차시를 다 읽으면

  1. GGUF를 유와 종차로 정의하고, safetensors 묶음과 무엇이 다른지 말할 수 있다.
  2. Q4_K_M, Q8_0 같은 양자화 이름을 읽고 대략의 크기와 품질 위치를 말할 수 있다.
  3. llama.cpp의 -ngl과 -c가 각각 9차시 예산식의 어느 항 을 건드리는지 말할 수 있다.
  4. CPU · GPU 혼합 추론이 왜 크게 느려지는지 디스크 ↔ 메모리 축으로 설명할 수 있다.
  5. Ollama가 GGUF 위에 서 있다는 것과, 경량 LLM(1~4B) 이 문의봇의 어디에 쓰일 수 있는지 말할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1어느 메모리에 있는가VRAM (GPU)RAM (CPU)-ngl 값, ollama ps의 CPU/GPU 분할⭐ ① 디스크 ↔ 메모리 (한 칸 아래 배율)
2한 파일인가 여러 파일인가한 파일 (GGUF)여러 파일 (safetensors + config + tokenizer)옮기기 · 반입의 단위⑤ 하나 ↔ 여럿
3크기경량 (1~4B)중형 (8B 이상)맡길 수 있는 업무의 난이도— (이 차시에서 세우는 축, 5.2절)

앞에서 이어집니다 — 9차시 2.2에서 본 것처럼 Hugging Face 저장소의 모델은 여러 파일의 묶음 (가중치 파일 + config.json + 토크나이저 파일 …)입니다. 그런데 5차시에 ollama pull로 받은 모델은 따로 맞춰 줄 파일이 없었습니다. 그 모델이 사실 이번 차시의 형식(GGUF) 한 파일 이었습니다. 이번 차시는 그 형식과, 그 형식을 돌리는 엔진(llama.cpp), 그리고 VRAM이 모자랄 때 일어나는 일을 봅니다.


1. GGUF — 한 파일에 다 담은 형식

1.1 정의

GGUF — [모델 파일 형식]인데, [ 가중치뿐 아니라 모델 구조 · 토크나이저 · 채팅 템플릿 같은 메타데이터까지 한 파일에 담는다 ]는 점에서 가중치만 담고 나머지는 별도 파일로 두는 safetensors와 구별된다.

llama.cpp 프로젝트가 만든 형식이고(이전 형식 GGML의 후속), 처음부터 양자화된 가중치를 담는 것 을 전제로 설계되었습니다.

1.2 경계 — 모델 파일 확장자 세 가지

Hugging Face 저장소와 모델 배포 페이지에서 흔히 보는 가중치 파일 확장자는 세 가지입니다.

확장자정체함께 있어야 하는 파일주로 쓰는 엔진
.bin가중치 덩어리 (pickle 기반)config.json, tokenizer 파일들예전 Transformers
.safetensors안전하게 텐서만 담는 형식config.json, tokenizer.json, tokenizer_config.json(채팅 템플릿) 등Transformers, vLLM
.gguf텐서 + 메타데이터 한 파일없음 (대개 이것 하나로 실행)llama.cpp, Ollama, LM Studio 등

표의 낯선 단어 두 개만 짚습니다. 텐서 는 가중치 숫자들을 여러 차원의 표로 묶은 덩어리(행렬을 일반화한 것)입니다. pickle 은 Python 객체를 통째로 저장하는 방식인데, 파일을 여는 순간 그 안에 숨겨 둔 코드가 실행될 수 있어 출처를 모르는 파일은 위험합니다. 그래서 숫자(텐서)만 담고 코드는 담지 못하게 만든 형식이 safetensors ("안전한 텐서")입니다.

Hugging Face 저장소 (safetensors)          GGUF 한 파일
├─ config.json        ← 구조                ┌─────────────────────────┐
├─ tokenizer.json     ← 토크나이저           │ 헤더 · 메타데이터          │
├─ tokenizer_config.json ← 채팅 템플릿       │  - 구조(층 수, 헤드 수 …)  │
├─ generation_config.json                   │  - 토크나이저 어휘         │
└─ model-0000x-of-0000y.safetensors ← 가중치 │  - 채팅 템플릿             │
                                            │ 텐서(양자화된 가중치) …    │
                                            └─────────────────────────┘

⭐ 0절 축 2입니다. 여러 파일을 맞춰 옮기다가 하나를 빠뜨리는 실수가 사라지고, 폐쇄망 반입 단위가 파일 하나 가 됩니다(1차시 4.2).

1.3 반례 — 이건 아닙니다

오해실제
"GGUF는 양자화 방식이다"❌ GGUF는 그릇(형식) . 안에 FP16도, Q4도 담을 수 있음. 양자화 방식은 이름의 Q4_K_M 부분
"GGUF면 vLLM에서도 똑같이 잘 돈다"⚠️ vLLM의 GGUF 지원은 제한적 · 실험적일 수 있음(버전 확인). vLLM은 보통 safetensors + AWQ/GPTQ/FP8 (19차시)
"GGUF 메타데이터에 템플릿이 있으니 항상 맞다"⚠️ 변환한 사람이 잘못 넣었을 수 있음. 응답이 이상하면 템플릿부터 의심

2. 양자화 이름 읽는 법

2.1 이름의 구조

Q 4 _ K _ M
│ │   │   └ 크기 변형: S(작게) · M(중간) · L(크게) — 중요한 층을 얼마나 높은 비트로 남기는가
│ │   └ K-quant 방식 (그룹 단위 · 층별로 비트를 섞는 개선된 방식)
│ └ 대표 비트 수
└ 양자화(Quantized)

Q8_0처럼 _0이 붙은 것은 K-quant 이전의 단순한 방식(그룹마다 scale 하나)입니다.

2.2 자주 보는 이름들

이름대략의 위치8B 모델 대략 크기 (계산 어림)쓰임
F16 / BF16양자화 없음≈ 16GB기준선, 재양자화 원본
Q8_0원본에 매우 가까움≈ 8.5GBVRAM 여유가 있고 품질 우선
Q6_K거의 차이 없다는 평이 많음≈ 6.5GB품질 쪽 절충
Q5_K_M절충≈ 6GB
⭐ Q4_K_M가장 흔한 기본값≈ 5GBOllama 기본 태그가 이 근처인 경우가 많음 (태그 페이지 확인)
Q3_K_M손실이 보이기 시작≈ 4GBVRAM이 정말 모자랄 때만
Q2_K손실 큼≈ 3GB실험용. 10차시 2.3의 "급격히 무너지는 선" 아래

⚠️ 크기는 파라미터 × 비트 ÷ 8에 그룹 scale과 "중요한 층은 높은 비트로" 몫이 더해진 어림 입니다(10차시 2.2). 정확한 값은 파일 크기 로 확인합니다. IQ4_XS 같은 IQ 계열 이름도 보이는데, 더 정교한 저비트 방식입니다(세부는 llama.cpp 문서 확인).


3. llama.cpp — GGUF를 실행하는 엔진

llama.cpp — [추론 엔진]인데, [ C/C++로 작성되어 GPU 없이 CPU만으로도, 또는 GPU와 CPU를 섞어서도 GGUF 모델을 실행한다 ]는 점에서 GPU · Python 환경을 전제로 하는 Transformers · vLLM과 구별된다.

설치는 공식 저장소의 README(미리 빌드된 파일 또는 CUDA 옵션으로 직접 빌드)를 따릅니다. 시스템 전체에 영향을 주는 CUDA 설치가 필요하면 실행 전 설명을 받고 승인 합니다(README 9장).

3.1 두 개의 명령

# 대화형으로 한 번 실행
llama-cli -m ./Qwen3-8B-Q4_K_M.gguf -ngl 99 -c 8192

# 서버로 띄우기 (OpenAI 호환 API 제공)
llama-server -m ./Qwen3-8B-Q4_K_M.gguf -ngl 99 -c 8192 --port 8080

🔍 읽는 포인트

옵션뜻9차시 예산식에서
-mGGUF 파일 경로첫째 항(가중치)의 크기를 정함
⭐ -ngl 99--n-gpu-layers. GPU에 올릴 층 수. 실제 층 수보다 크게 주면 "전부"첫째 항을 VRAM과 RAM에 어떻게 나눌지
-c 8192컨텍스트 크기둘째 항(KV 캐시)
--port 8080서버 포트—

llama-server를 띄우면 http://localhost:8080/v1/chat/completions가 열립니다. 7차시의 Ollama(11434), 19차시의 vLLM(8000)과 같은 OpenAI 호환 형식 입니다.

앞으로 다시 만납니다 — 20차시에서 같은 클라이언트 코드로 base_url만 바꿔 셋을 갈아 끼웁니다. README 5.1의 축 ② 추상 ↔ 구상 입니다. "OpenAI 호환 API"라는 약속(포트) 하나에 llama.cpp · Ollama · vLLM이라는 구현(어댑터) 이 각각 꽂힙니다. 약속만 지키면 구현은 갈아 끼울 수 있습니다(README 7장 문장 3).


4. ⭐ CPU · GPU 혼합 추론 — VRAM ↔ RAM

4.1 정의와 위치

CPU · GPU 혼합 추론 (부분 오프로드) — [추론 실행 방식]인데, [ 모델의 일부 층만 VRAM에 올리고 나머지 층은 RAM에 두어 CPU가 계산한다 ]는 점에서 전부 GPU에서 계산하는 방식, 전부 CPU에서 계산하는 방식과 구별된다.

-ngl 36 (전부)         -ngl 20 (일부)                      -ngl 0 (없음)
┌──────────┐          ┌──────────┐ ┌──────────┐          ┌──────────┐
│ VRAM     │          │ VRAM     │ │ RAM      │          │ RAM      │
│ 층 1~36  │          │ 층 1~20  │→│ 층 21~36 │          │ 층 1~36  │
│ GPU 계산 │          │ GPU 계산 │ │ CPU 계산 │          │ CPU 계산 │
└──────────┘          └──────────┘ └──────────┘          └──────────┘
 가장 빠름              토큰마다 이 경계를 건넘                가장 느림

(층 수 36은 Qwen3-8B 예시. 모델마다 다름)

4.2 왜 크게 느려지는가

15차시에서 자세히 보지만, Decode(2차시 4절)는 토큰 하나마다 가중치 전체를 메모리에서 읽는 메모리 병목 작업입니다. 그러면 속도는 가장 느린 메모리 가 정합니다.

메모리 대역폭 (대략)
RTX 4090 VRAM≈ 1,000GB/s
일반 데스크톱 RAM (듀얼 채널 DDR5)수십 GB/s ~ 100GB/s 안팎

⭐ RAM 쪽이 열 배 이상 좁은 길 입니다. 층의 1/3만 RAM에 있어도, 토큰마다 그 1/3을 좁은 길로 읽느라 전체 속도가 RAM 쪽에 끌려갑니다. "조금 넘쳤으니 조금 느리겠지"가 아니라 크게 느려지는 이유입니다.

컴퓨터의 스왑 과 같은 구조입니다.

스왑 (swap) — [운영체제의 메모리 관리 방식]인데, [ RAM이 모자랄 때 디스크의 일부를 메모리인 것처럼 빌려 쓴다 ]는 점에서 RAM만 쓰는 정상 상태와 구별된다. 디스크는 RAM보다 훨씬 느리므로, 스왑을 많이 쓰기 시작하면 컴퓨터 전체가 멈춘 것처럼 느려집니다.

오프로드는 VRAM이 모자라 RAM을 쓰는 것이고, 스왑은 RAM이 모자라 디스크를 쓰는 것입니다. 축 ①(빠르지만 작은 쪽 ↔ 크지만 느린 쪽)이 한 칸씩 자리를 옮겨 반복 됩니다.

배율빠른 쪽느린 쪽넘치면
운영체제RAM디스크 (스왑)컴퓨터가 "멈춘 것 같다"
이 차시VRAMRAM (오프로드)생성이 느릿느릿

4.3 그래도 쓰는 경우

경우판단
VRAM보다 큰 모델을 한 번 시험⭕ 품질을 미리 보는 용도로 충분
GPU 없는 노트북 · 서버에서 경량 모델⭕ 1~4B Q4는 CPU만으로도 쓸 만한 경우가 있음 (5절)
상담원 10명이 쓰는 운영 서버❌ 오프로드가 보이면 모델 · 양자화 · 컨텍스트를 다시 고름 (16차시)

4.4 Ollama에서 보이는 모습

Ollama도 내부적으로 GGUF와 llama.cpp 계열 엔진을 씁니다. Ollama는 -ngl을 자동으로 정하고, 결과를 ollama ps의 PROCESSOR 열에 보여줍니다.

PROCESSOR 표시뜻
100% GPU전부 VRAM. 정상
48%/52% CPU/GPU 같은 분할⚠️ 오프로드 중 — 9차시 예산 초과. 컨텍스트(num_ctx)를 늘렸을 때 자주 생김
100% CPUGPU를 못 쓰고 있음 (드라이버 · 설정 확인)

💡 Ollama에도 GPU 층 수를 직접 정하는 옵션(num_gpu)이 있으나 동작은 버전에 따라 다르니 공식 문서를 확인하세요. 대개는 자동 결정에 맡기고 PROCESSOR 열만 감시 하는 편이 안전합니다.


5. Ollama와 GGUF, 그리고 경량 LLM

5.1 GGUF 파일을 Ollama로 가져오기

Hugging Face에서 받은 GGUF 파일을 Ollama 모델로 등록할 수 있습니다. 8차시의 Modelfile과 같은 모양입니다.

# Modelfile
FROM ./Qwen3-8B-Q4_K_M.gguf
PARAMETER num_ctx 8192
PARAMETER temperature 0.2
ollama create munuibot-q4 -f Modelfile
ollama show munuibot-q4 --modelfile    # 템플릿 · 파라미터가 제대로 들어갔는지 확인

🔍 읽는 포인트 : FROM 뒤가 태그 이름(qwen3:8b)이 아니라 파일 경로 입니다. 폐쇄망에서는 이 방식이 ollama pull 대신 쓰는 반입 경로가 됩니다.

⚠️ 채팅 템플릿이 제대로 안 들어가면 모델이 대화 형식을 못 알아듣고 이상한 말을 이어 붙입니다. ollama show --modelfile로 TEMPLATE 부분을 확인하게 하세요.

5.2 경량 LLM — 작은 모델이 맡는 자리

경량 LLM — [언어 모델]인데, [ 1~4B 정도로 작아 저사양 GPU나 CPU에서도 돌아간다 ]는 점에서 8B 이상 중형 모델과 구별된다. ⚠️ 크기(파라미터 수)는 "얼마나 무거운가"의 축이지 "우리 업무를 얼마나 잘하는가"의 축이 아닙니다. 큰 모델이 대체로 더 많은 일을 잘하지만, 업무가 좁고 정해져 있으면 작은 모델로 충분할 수 있습니다. 어느 쪽인지는 평가셋이 정합니다.

업무경량 모델로 충분할 가능성이유
분류 (배송지연 / 교환·반품 / 결제오류 / 상품문의 / 기타)높음정해진 값 몇 개 중 하나만 고르면 됨. 긴 글을 지어내는 생성보다 쉬운 과제
정보 추출 (주문번호 · 연락처)중간형식 강제(29차시)와 함께라면. 숫자 정확도는 평가셋으로 확인
요약중간길이 · 항목 규칙이 명확하면
답변 초안낮음한국어 문장 품질 · 여러 조건 판단 → 8B 이상

⭐ 흔히 쓰는 실전 조합 은 작은 모델이 쉬운 일을 먼저 처리하고, 무거운 일만 큰 모델에 넘기는 구조입니다. 문의봇으로 옮기면 "경량 모델이 분류 · 추출 → 8B 모델이 답변 초안" 이라는 두 단 구조를 후보로 둘 수 있습니다. 경량 모델은 CPU에서 돌려 GPU의 KV 캐시 자리를 아끼는 선택도 가능합니다. 채택 여부는 16차시 결정 절차에서 정합니다.


6. 실습 — 맡기고 검수하기

지시

목표: 같은 GGUF 모델을 -ngl 값만 바꿔 실행하며 속도와 메모리 변화를 관찰한다.
맥락: llama.cpp 공식 저장소 README의 설치 방법을 따르고, 설치 방법(미리 빌드/직접 빌드)과 버전을 먼저 보고해.
      CUDA나 드라이버를 새로 설치해야 하면 실행하지 말고 계획만 보고해(내가 승인).
모델: Hugging Face에서 Qwen3-8B의 Q4_K_M GGUF 파일(저장소 주소를 보고에 포함).
작업:
 1. GGUF 메타데이터에서 층 수, 컨텍스트 길이, 채팅 템플릿 존재 여부를 출력.
 2. -c 4096 고정, 같은 프롬프트, 출력 200토큰 고정으로 -ngl 0, 12, 24, 99 각각 실행.
    (llama.cpp에 포함된 벤치마크 도구가 있으면 써도 됨. 옵션은 --help로 확인)
 3. 각 실행마다 nvidia-smi memory.used와 생성 속도(토큰/초)를 기록. 워밍업 1회 버리고 3회 중앙값.
보고 형식:
| -ngl | GPU 층/전체 층 | nvidia-smi used(GB) | 프롬프트 처리 토큰/초 | 생성 토큰/초 |
추측하지 말고 실행 명령과 출력 원문을 붙여.

받을 증거

  • 설치 방법 · 버전 출력, GGUF 저장소 주소
  • 메타데이터 출력 (층 수가 보이는 부분)
  • -ngl별 실행 명령과 출력 원문, nvidia-smi 출력

내가 직접 볼 것

볼 것이걸로 아는 것
-ngl이 커질수록 nvidia-smi used가 계단식으로 늘어나는가층이 실제로 VRAM으로 옮겨 감 = 축 ①
생성 토큰/초가 -ngl 99에서 다른 값보다 훨씬 큰가4.2절 — 일부라도 RAM에 있으면 크게 느려짐
프롬프트 처리 속도와 생성 속도의 변화 폭이 다른가Prefill(계산 병목) ↔ Decode(메모리 병목)의 차이. 15차시에서 회수
채팅 템플릿이 메타데이터에 있는가5.1절 Ollama 등록 시 템플릿 문제를 미리 앎

부록 A. 스스로 확인하기

#질문답이 있는 곳
1GGUF를 유와 종차로 정의하면? safetensors와 무엇이 다른가?1.1, 1.2
2"GGUF는 양자화 방식이다"가 틀린 이유는?1.3
3Q4_K_M의 Q, 4, K, M은 각각 무엇인가?2.1
4-ngl과 -c는 9차시 예산식의 어느 항을 건드리는가?3.1
5층 일부만 RAM에 있어도 크게 느려지는 이유는?4.2
6오프로드와 운영체제의 스왑은 어떤 점에서 같은 구조인가?4.2
7ollama ps에서 오프로드를 어떻게 알아보는가?4.4
8GGUF 파일을 Ollama에 등록하는 방법과 확인할 것은?5.1
9문의봇에서 경량 LLM이 맡을 수 있는 업무는?5.2

부록 B. 자주 하는 실수

실수바로잡기
"GGUF = 4bit"❌ GGUF는 그릇. F16도 Q8도 담김
"VRAM이 조금 모자라니 조금 느리겠지"❌ RAM 쪽 층이 병목 → 크게 느려짐
ollama ps의 CPU/GPU 분할을 못 보고 "모델이 느리다"⚠️ 모델 탓이 아니라 예산 초과 . 컨텍스트 · 양자화 조정
Modelfile FROM에 GGUF를 넣고 템플릿 확인 안 함⚠️ 대화 형식이 깨질 수 있음. ollama show --modelfile
경량 모델에 답변 초안까지 맡김⚠️ 분류 · 추출부터. 평가셋 으로 범위 결정
GGUF를 vLLM 운영의 기본 형식으로 가정⚠️ vLLM은 보통 safetensors + AWQ/GPTQ/FP8. 문서 확인

부록 C. NotebookLM 복습 프롬프트

이 12차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"GGUF와 safetensors의 차이", "Q4_K_M 이름 읽기", "-ngl과 CPU·GPU 혼합 추론이 느린 이유", "경량 LLM의 쓰임새"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.