llama.cpp dan GGUF Quantization: Deploy LLM Secara Lokal
Pendahuluan
Menjalankan Large Language Model (LLM) secara lokal tanpa bergantung pada cloud API adalah impian banyak developer dan organisasi. Dengan llama.cpp, hal ini menjadi kenyataan. llama.cpp adalah framework inference LLM yang ditulis dalam C/C++ murni, dirancang untuk menjalankan model-model besar secara efisien di hardware consumer, termasuk laptop biasa.
Format GGUF (GPT-Generated Unified Format) adalah format model yang dioptimalkan untuk llama.cpp, mendukung berbagai level quantization yang memungkinkan Anda menukar antara kualitas model dan penggunaan memori sesuai kebutuhan hardware Anda.
Dalam tutorial ini, kita akan mempelajari cara menginstal llama.cpp, mendownload model GGUF dari HuggingFace, memahami level quantization, dan membangun chatbot lokal yang fully functional.
Prasyarat
- Komputer dengan minimal 8GB RAM (16GB+ direkomendasikan)
- Storage minimal 10GB free space
- Python 3.8 atau lebih baru
- Git dan CMake (untuk build dari source)
- Opsional: GPU NVIDIA dengan CUDA atau Apple Silicon untuk akselerasi
Instalasi llama.cpp
Metode 1: Build dari Source (Direkomendasikan)
# Clone repository
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
Build dasar (CPU only)
make
Atau menggunakan CMake
mkdir build && cd build
cmake ..
cmake --build . --config Release
Build dengan GPU Acceleration
# CUDA (NVIDIA GPU)
make GGMLCUDA=1
Atau via CMake
mkdir build && cd build
cmake .. -DGGMLCUDA=ON
cmake --build . --config Release
Metal (Apple Silicon / macOS)
make GGMLMETAL=1
Atau via CMake
mkdir build && cd build
cmake .. -DGGMLMETAL=ON
cmake --build . --config Release
Vulkan (cross-platform GPU)
make GGMLVULKAN=1
Metode 2: Instalasi via pip (Python Bindings)
# Instalasi dasar (CPU only)
pip install llama-cpp-python
Dengan CUDA support
CMAKEARGS="-DGGMLCUDA=on" pip install llama-cpp-python
Dengan Metal support (macOS)
CMAKEARGS="-DGGMLMETAL=on" pip install llama-cpp-python
Dengan Vulkan support
CMAKEARGS="-DGGMLVULKAN=on" pip install llama-cpp-python
Force reinstall jika upgrade
pip install llama-cpp-python --force-reinstall --no-cache-dir
Verifikasi Instalasi
# Untuk build dari source
./llama-cli --version
Untuk Python
python -c "from llamacpp import Llama; print('llama-cpp-python installed successfully')"
Memahami Format GGUF dan Level Quantization
Apa itu GGUF?
GGUF adalah format file yang dirancang khusus untuk menyimpan model LLM yang telah di-quantize. Format ini menggantikan format GGML sebelumnya dan menawarkan:
- Backward dan forward compatibility yang lebih baik
- Metadata yang lebih lengkap (tokenizer info, parameter model, dll)
- Loading yang lebih cepat
- Dukungan untuk berbagai arsitektur model
Level Quantization
Quantization adalah proses mengurangi presisi numerik dari parameter model untuk menghemat memori dan meningkatkan kecepatan, dengan trade-off pada kualitas output.
| Quantization | Bits | Ukuran Model (7B) | RAM Needed | Kualitas | Use Case |
|-------------|------|-------------------|------------|----------|----------|
| F16 | 16 | ~14 GB | ~16 GB | Terbaik | Referensi, evaluasi |
| Q80 | 8 | ~7.5 GB | ~10 GB | Sangat Baik | Produksi (jika RAM cukup) |
| Q6K | 6 | ~5.5 GB | ~8 GB | Baik Sekali | Balance kualitas/performa |
| Q5KM | 5 | ~5.0 GB | ~7.5 GB | Baik | Rekomendasi umum |
| Q5KS | 5 | ~4.8 GB | ~7 GB | Baik | Sedikit lebih kecil |
| Q4KM | 4 | ~4.0 GB | ~6.5 GB | Cukup Baik | Paling populer |
| Q4KS | 4 | ~3.8 GB | ~6 GB | Cukup | RAM terbatas |
| Q3KM | 3 | ~3.3 GB | ~5.5 GB | Menurun | Hanya jika RAM sangat terbatas |
| Q2K | 2 | ~2.7 GB | ~5 GB | Rendah | Eksperimen saja |
Rekomendasi:- Q4KM: Best balance antara ukuran dan kualitas (paling populer)
- Q5KM: Untuk kualitas lebih baik dengan sedikit tambahan RAM
- Q80: Jika RAM bukan masalah, kualitas mendekati F16
Naming Convention GGUF
model-name-{size}-{type}.{quantization}.gguf
Contoh:
- Meta-Llama-3-8B-Instruct-Q4KM.gguf
- mistral-7b-instruct-v0.3-Q5KM.gguf
- phi-3-mini-4k-instruct-Q80.gguf
Download Model GGUF dari HuggingFace
Menggunakan huggingface-cli
# Install huggingfacehub
pip install huggingfacehub
Download model spesifik
huggingface-cli download \
TheBloke/Llama-2-7B-Chat-GGUF \
llama-2-7b-chat.Q4KM.gguf \
--local-dir ./models
Download dari bartowski (source GGUF populer)
huggingface-cli download \
bartowski/Meta-Llama-3.1-8B-Instruct-GGUF \
Meta-Llama-3.1-8B-Instruct-Q4KM.gguf \
--local-dir ./models
Menggunakan Python
from huggingfacehub import hfhubdownload
Download model
modelpath = hfhubdownload(
repoid="bartowski/Meta-Llama-3.1-8B-Instruct-GGUF",
filename="Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
localdir="./models"
)
print(f"Model downloaded to: {modelpath}")
Model Populer yang Direkomendasikan
# Llama 3.1 8B (Meta, general purpose)
huggingface-cli download bartowski/Meta-Llama-3.1-8B-Instruct-GGUF \
Meta-Llama-3.1-8B-Instruct-Q4KM.gguf --local-dir ./models
Mistral 7B (Mistral AI, efficient)
huggingface-cli download TheBloke/Mistral-7B-Instruct-v0.2-GGUF \
mistral-7b-instruct-v0.2.Q4KM.gguf --local-dir ./models
Phi-3 Mini (Microsoft, compact)
huggingface-cli download bartowski/Phi-3.5-mini-instruct-GGUF \
Phi-3.5-mini-instruct-Q4KM.gguf --local-dir ./models
Qwen2 7B (Alibaba, multilingual)
huggingface-cli download Qwen/Qwen2-7B-Instruct-GGUF \
qwen2-7b-instruct-q4km.gguf --local-dir ./models
Penggunaan CLI llama.cpp
Inference Dasar
# Text completion
./llama-cli -m ./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf \
-p "Jelaskan apa itu machine learning dalam 3 kalimat:" \
-n 256 \
--temp 0.7
Interactive chat mode
./llama-cli -m ./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf \
--interactive \
--color \
-n -1 \
--temp 0.7 \
--top-p 0.9 \
--repeat-penalty 1.1
Parameter Penting CLI
./llama-cli -m model.gguf \
-p "prompt text" \
-n 512 # Max tokens to generate
--temp 0.7 # Temperature (0.0 = deterministic, 1.0 = creative)
--top-p 0.9 # Top-p sampling
--top-k 40 # Top-k sampling
--repeat-penalty 1.1 # Penalti pengulangan
-c 4096 # Context length
-t 8 # Jumlah CPU threads
-ngl 35 # Jumlah layer di GPU (untuk GPU offloading)
--seed 42 # Random seed untuk reproducibility
GPU Offloading
# Offload semua layer ke GPU
./llama-cli -m model.gguf -ngl 999 -p "Hello"
Offload sebagian layer ke GPU (untuk GPU dengan VRAM terbatas)
./llama-cli -m model.gguf -ngl 20 -p "Hello"
Cek berapa layer model
./llama-cli -m model.gguf --verbose-prompt -p "test" -n 1
Python Bindings: llama-cpp-python
Penggunaan Dasar
from llamacpp import Llama
Load model
llm = Llama(
model
path="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
nctx=4096, # Context window
nthreads=8, # CPU threads
ngpulayers=35, # GPU layers (0 untuk CPU only)
verbose=False
)
Text completion
output = llm(
"Jelaskan apa itu neural network:",
maxtokens=256,
temperature=0.7,
topp=0.9,
stop=["###", "\n\n\n"]
)
print(output["choices"][0]["text"])
Chat Completion (Format OpenAI-Compatible)
from llamacpp import Llama
llm = Llama(
model
path="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
nctx=4096,
ngpulayers=-1, # -1 = semua layer ke GPU
chatformat="llama-3" # Format chat sesuai model
)
Single turn
response = llm.createchatcompletion(
messages=[
{"role": "system", "content": "Kamu adalah asisten AI yang membantu."},
{"role": "user", "content": "Apa keuntungan menjalankan LLM secara lokal?"}
],
maxtokens=512,
temperature=0.7
)
print(response["choices"][0]["message"]["content"])
Streaming Response
from llamacpp import Llama
llm = Llama(
modelpath="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
nctx=4096,
ngpulayers=-1
)
Streaming output
stream = llm.createchatcompletion(
messages=[
{"role": "system", "content": "Kamu adalah asisten AI."},
{"role": "user", "content": "Tulis puisi pendek tentang programming"}
],
maxtokens=256,
stream=True
)
for chunk in stream:
delta = chunk["choices"][0]["delta"]
if "content" in delta:
print(delta["content"], end="", flush=True)
print() # Newline di akhir
Multi-turn Conversation
from llamacpp import Llama
llm = Llama(
modelpath="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
nctx=4096,
ngpulayers=-1
)
Simpan history percakapan
conversationhistory = [
{"role": "system", "content": "Kamu adalah asisten AI yang ahli dalam Python programming."}
]
def chat(usermessage):
conversationhistory.append({"role": "user", "content": usermessage})
response = llm.createchatcompletion(
messages=conversationhistory,
maxtokens=512,
temperature=0.7
)
assistantmessage = response["choices"][0]["message"]["content"]
conversationhistory.append({"role": "assistant", "content": assistantmessage})
return assistantmessage
Percakapan multi-turn
print(chat("Apa itu list comprehension di Python?"))
print(chat("Berikan 3 contoh penggunaannya"))
print(chat("Bagaimana performanya dibanding for loop biasa?"))
OpenAI-Compatible Server
llama.cpp menyediakan server yang kompatibel dengan OpenAI API, sehingga Anda bisa menggunakan model lokal sebagai drop-in replacement untuk OpenAI.
Menjalankan Server
# Dari build source
./llama-server \
-m ./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf \
--host 0.0.0.0 \
--port 8080 \
-c 4096 \
-ngl 35 \
--embedding
Atau via Python
python -m llamacpp.server \
--model ./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf \
--host 0.0.0.0 \
--port 8080 \
--nctx 4096 \
--ngpulayers 35
Menggunakan dengan OpenAI Python SDK
from openai import OpenAI
Point ke server lokal
client = OpenAI(
baseurl="http://localhost:8080/v1",
apikey="not-needed" # API key tidak diperlukan untuk server lokal
)
Chat completion (sama persis dengan OpenAI API)
response = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain quantum computing in simple terms"}
],
maxtokens=512,
temperature=0.7
)
print(response.choices[0].message.content)
Streaming
stream = client.chat.completions.create(
model="local-model",
messages=[
{"role": "user", "content": "Write a Python function to sort a list"}
],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
Menggunakan dengan curl
# Chat completion
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
],
"maxtokens": 256,
"temperature": 0.7
}'
Text embedding
curl http://localhost:8080/v1/embeddings \
-H "Content-Type: application/json" \
-d '{
"input": "Machine learning is fascinating",
"model": "local-model"
}'
Kebutuhan Memori dan Performance Benchmarks
Estimasi Kebutuhan RAM
Formula: RAM = (Model Size in GB) + (Context Length 0.5MB per 1K tokens) + 1GB overhead
Contoh untuk Llama 3.1 8B Q4KM:
- Model size: ~4.5 GB
- Context 4096 tokens: ~2 GB
- Overhead: ~1 GB
- Total: ~7.5 GB RAM
Contoh untuk Llama 3.1 70B Q4KM:
- Model size: ~40 GB
- Context 4096 tokens: ~4 GB
- Overhead: ~2 GB
- Total: ~46 GB RAM
Benchmark Performa (Approximate)
| Hardware | Model | Quantization | Speed (tokens/s) |
|----------|-------|-------------|------------------|
| M2 MacBook Air | Llama 3 8B | Q4KM | ~30-40 |
| M2 Pro | Llama 3 8B | Q4KM | ~45-55 |
| RTX 3060 12GB | Llama 3 8B | Q4KM | ~50-70 |
| RTX 4090 | Llama 3 8B | Q4KM | ~100-130 |
| CPU (i7-12700) | Llama 3 8B | Q4KM | ~8-15 |
| RTX 4090 | Llama 3 70B | Q4KM | ~15-25 |
Mengukur Performa
import time
from llamacpp import Llama
llm = Llama(
modelpath="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
nctx=2048,
ngpulayers=-1,
verbose=True # Akan menampilkan statistik performa
)
Benchmark
prompt = "Explain the theory of relativity in detail:"
starttime = time.time()
output = llm(prompt, maxtokens=256)
elapsed = time.time() - starttime
tokensgenerated = output["usage"]["completiontokens"]
tokenspersecond = tokensgenerated / elapsed
print(f"Tokens generated: {tokensgenerated}")
print(f"Time elapsed: {elapsed:.2f}s")
print(f"Speed: {tokenspersecond:.1f} tokens/s")
Contoh Praktis: Membangun Chatbot Lokal
Mari kita bangun chatbot interaktif yang berjalan sepenuhnya di mesin lokal.
import sys
from llamacpp import Llama
class LocalChatbot:
def init(self, modelpath, systemprompt=None):
print("Loading model... (this may take a moment)")
self.llm = Llama(
modelpath=modelpath,
nctx=4096,
ngpulayers=-1,
verbose=False
)
self.systemprompt = systemprompt or (
"Kamu adalah asisten AI yang cerdas dan membantu. "
"Jawab dalam bahasa yang sama dengan pertanyaan user. "
"Berikan jawaban yang informatif namun ringkas."
)
self.conversation = [
{"role": "system", "content": self.systemprompt}
]
print("Model loaded. Ready to chat!\n")
def chat(self, userinput):
self.conversation.append({"role": "user", "content": userinput})
response = self.llm.createchatcompletion(
messages=self.conversation,
maxtokens=1024,
temperature=0.7,
topp=0.9,
repeatpenalty=1.1,
stream=True
)
fullresponse = ""
for chunk in response:
delta = chunk["choices"][0]["delta"]
if "content" in delta:
token = delta["content"]
print(token, end="", flush=True)
fullresponse += token
print() # Newline
self.conversation.append({"role": "assistant", "content": fullresponse})
# Trim conversation jika terlalu panjang
if len(self.conversation) > 20:
self.conversation = [self.conversation[0]] + self.conversation[-10:]
return fullresponse
def reset(self):
self.conversation = [
{"role": "system", "content": self.systemprompt}
]
print("Conversation reset.\n")
def run(self):
print("=" 50)
print("LOCAL AI CHATBOT")
print("=" 50)
print("Commands: /reset (reset conversation), /quit (exit)")
print("=" 50)
while True:
try:
userinput = input("\nYou: ").strip()
if not userinput:
continue
if userinput.lower() == "/quit":
print("Goodbye!")
break
if userinput.lower() == "/reset":
self.reset()
continue
print("\nAI: ", end="")
self.chat(userinput)
except KeyboardInterrupt:
print("\n\nGoodbye!")
break
Jalankan chatbot
if name == "main":
bot = LocalChatbot(
modelpath="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
systemprompt=(
"Kamu adalah asisten AI untuk perusahaan teknologi. "
"Bantu user dengan pertanyaan tentang programming, "
"data science, dan teknologi secara umum. "
"Jawab dengan bahasa yang mudah dipahami."
)
)
bot.run()
Chatbot dengan FastAPI Web Interface
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from llamacpp import Llama
from fastapi.responses import StreamingResponse
import json
app = FastAPI(title="Local LLM Chatbot API")
app.addmiddleware(
CORSMiddleware,
alloworigins=[""],
allowmethods=[""],
allowheaders=["*"],
)
Load model saat startup
llm = Llama(
modelpath="./models/Meta-Llama-3.1-8B-Instruct-Q4KM.gguf",
nctx=4096,
ngpulayers=-1,
verbose=False
)
class ChatRequest(BaseModel):
messages: list
maxtokens: int = 512
temperature: float = 0.7
stream: bool = False
@app.post("/v1/chat")
async def chat(request: ChatRequest):
if request.stream:
return StreamingResponse(
streamresponse(request),
mediatype="text/event-stream"
)
response = llm.createchatcompletion(
messages=request.messages,
maxtokens=request.maxtokens,
temperature=request.temperature
)
return {
"response": response["choices"][0]["message"]["content"],
"usage": response["usage"]
}
async def streamresponse(request):
stream = llm.createchatcompletion(
messages=request.messages,
maxtokens=request.maxtokens,
temperature=request.temperature,
stream=True
)
for chunk in stream:
delta = chunk["choices"][0]["delta"]
if "content" in delta:
data = json.dumps({"content": delta["content"]})
yield f"data: {data}\n\n"
yield "data: [DONE]\n\n"
@app.get("/health")
async def health():
return {"status": "ok", "model": "loaded"}
Jalankan dengan: uvicorn chatbotapi:app --host 0.0.0.0 --port 8000
Tips Optimasi dan Troubleshooting
Optimasi Performa
# 1. Gunakan jumlah thread yang tepat (biasanya = jumlah performance cores)
./llama-cli -m model.gguf -t 8 -p "test"
2. Sesuaikan context length (lebih kecil = lebih cepat)
./llama-cli -m model.gguf -c 2048 -p "test"
3. Gunakan batch size yang optimal
./llama-cli -m model.gguf -b 512 -p "test"
4. Enable memory mapping (default on)
./llama-cli -m model.gguf --mmap -p "test"
Troubleshooting Umum
# Error: "not enough memory"
Solusi: Gunakan quantization lebih rendah atau kurangi context length
llm = Llama(
modelpath="model-Q4KM.gguf", # Gunakan Q4 bukan Q8
nctx=2048, # Kurangi context
ngpulayers=0 # CPU only jika GPU VRAM penuh
)
Error: "CUDA out of memory"
Solusi: Offload sebagian layer saja ke GPU
llm = Llama(
modelpath="model.gguf",
ngpulayers=20 # Bukan -1 (semua), tapi sebagian saja
)
Error: "model file not found"
Solusi: Gunakan absolute path
import os
modelpath = os.path.abspath("./models/model.gguf")
llm = Llama(modelpath=modelpath)
Slow performance di CPU
Solusi: Compile ulang dengan optimasi AVX2/AVX512
make clean && make LLAMAAVX2=1
Kesimpulan
llama.cpp dan format GGUF telah merevolusi cara kita menjalankan LLM secara lokal. Dengan quantization yang tepat, Anda bisa menjalankan model-model canggih bahkan di laptop biasa tanpa GPU dedicated.
Poin-poin penting yang perlu diingat:
- Pilih quantization yang tepat: Q4KM untuk balance terbaik, Q5KM untuk kualitas lebih, Q80 jika RAM cukup
- Manfaatkan GPU: Offloading ke GPU memberikan peningkatan performa yang signifikan
- Gunakan OpenAI-compatible server: Memudahkan integrasi dengan aplikasi yang sudah ada
- Sesuaikan context length: Semakin kecil context, semakin cepat dan hemat memori
- Python bindings: llama-cpp-python membuat integrasi ke aplikasi Python sangat mudah
- Perhatikan kebutuhan RAM: Pastikan hardware Anda sesuai dengan model yang dipilih
Dengan menguasai llama.cpp, Anda memiliki kemampuan untuk menjalankan AI yang powerful secara privat, tanpa biaya API, dan tanpa batasan rate limit.
Referensi
- Repository llama.cpp: https://github.com/ggerganov/llama.cpp
- llama-cpp-python: https://github.com/abetlen/llama-cpp-python
- HuggingFace GGUF Models: https://huggingface.co/models?library=gguf
- GGUF Specification: https://github.com/ggerganov/ggml/blob/master/docs/gguf.md