Tüm yazılarAll posts

llama.cpp ile Yerel LLM: VRAM-Aware Model Routing

Local LLM with llama.cpp: VRAM-Aware Model Routing

8 GB VRAM'de 7B, 24 GB'de 70B model çalıştırmak için Strata'nın routing algoritmasını anlatıyorum. OpenAI-uyumlu API ile sıfır kod değişikliğiyle geçiş.

Here's Strata's routing algorithm to run a 7B model on 8GB VRAM and a 70B on 24GB. OpenAI-compatible API for zero code-change migration.

VRAM-aware model routing: GPU router at top with flowing arrows to 7B, 13B, 70B model cards showing different VRAM sizes

Bulut LLMi neden bıraktım

İlk production LLM uygulamam OpenAI API üzerindeydi. GPT-4 ile başladım. Fatura geldiğinde midem bulanmıştı: günde 40$, ayda 1200$, sadece bir demo için. Bir kullanıcı yoğunlaştığında maliyet katlanıyor. Gizlilik sorunu da cabası: müşteri verisi ABD'ye gidiyor, KVKK ihlali riski.

Çözüm: yerel LLM. llama.cpp sayesinde quantized modelleri (Q4_K_M, Q5_K_M) GPU'da veya CPU'da çalıştırabiliyorsun. OpenAI API'ye sıfır kod değişikliğiyle geçiş yapabiliyorsun. Tek problem: VRAM yönetimi.

llama.cpp temelleri

llama.cpp, Meta'nın LLaMA modelini CPU ve GPU'da verimli inference yapmak için yazılmış bir C++ kütüphanesi. Quantization (Q4_K_M gibi) sayesinde 7B modeli 5GB VRAM'e, 13B'yi 9GB'a, 70B'yi 40GB'a sığdırabiliyorsun. Python binding'i llama-cpp-python ile kolay kullanılıyor.

# pip install llama-cpp-python
from llama_cpp import Llama
llm = Llama(
    model_path="./models/llama-3-8b-instruct.Q4_K_M.gguf",
    n_ctx=4096,        # context window
    n_gpu_layers=35,   # GPU'ya kaç layer (VRAM'e göre)
    n_threads=8        # CPU thread
)
output = llm("Explain quantum computing in 3 sentences", max_tokens=200)
print(output["choices"][0]["text"])

Çalıştırmak bu kadar kolay. Zor kısım VRAM'e göre doğru modeli seçmek.

VRAM hesabı

Quantized model boyutunu hesaplamak için basit bir formül var:

# Model VRAM (GB) ≈ (params × bits_per_weight) / (8 × 1024³)
def estimate_vram_gb(params_b, quant='Q4_K_M'):
    bits = {'Q4_K_M': 4.5, 'Q5_K_M': 5.5, 'Q8_0': 8.0}.get(quant, 4.5)
    return (params_b * 1e9 * bits) / (8 * 1024**3)

# Örnekler:
# 7B  Q4_K_M:  3.5 GB
# 13B Q4_K_M:  6.5 GB
# 70B Q4_K_M:  39.3 GB

Ama modelin kendisi tek başına yetmiyor. Context window için de VRAM lazım: her token ~1KB. 4K context = 4MB. 32K context = 32MB. Önemli ama model boyutunun yanında küçük.

KV cache (attention için) daha büyük: 2 × layers × hidden_size × seq_len × 2 bytes. 7B model, 4K context'te ~250MB ekstra. 70B, 32K context'te ~5GB.

Routing algoritması

Strata'nın en önemli kısmı bu. Mevcut VRAM'i ölçüp, uygun modeli seçiyor. nvidia-smi veya torch.cuda.mem_get_info() ile anlık free VRAM öğreniliyor:

import subprocess, re
def get_free_vram_gb():
    out = subprocess.check_output(
        ['nvidia-smi', '--query-gpu=memory.free', '--format=csv,noheader,nounits']
    ).decode()
    return int(out.strip().split()[0]) / 1024  # MB → GB

def pick_model(available_gb, model_catalog):
    """En büyük modeli seç ama sınırın %75'ini aşmasın (overhead için)"""
    safe_budget = available_gb * 0.75
    candidates = [m for m in model_catalog if m['vram_gb'] <= safe_budget]
    return max(candidates, key=lambda m: m['params_b']) if candidates else None

catalog = [
    {'name': '7B',  'params_b': 7,  'vram_gb': 4.5,  'path': '...'},
    {'name': '13B', 'params_b': 13, 'vram_gb': 8.5,  'path': '...'},
    {'name': '70B', 'params_b': 70, 'vram_gb': 39.0, 'path': '...'},
]
model = pick_model(get_free_vram_gb(), catalog)
print(f"Selected: {model['name']} ({model['vram_gb']}GB)")

8GB VRAM'de 7B, 12GB'de 13B, 24GB'de 70B (Q3_K_S quantization ile) çalışıyor. Kullanıcı yeni GPU eklerse otomatik daha büyük model yükleniyor.

OpenAI-uyumlu API

En güzel kısım: llama-cpp-python'un OpenAI uyumlu HTTP server'ı var. Tek komutla ayağa kalkıyor:

python -m llama_cpp.server \
  --model ./models/llama-3-8b-instruct.Q4_K_M.gguf \
  --host 0.0.0.0 \
  --port 8000

Artık http://localhost:8000/v1/chat/completions adresinde OpenAI API'sinin aynısı var. Mevcut uygulamadaki base URL'i değiştirmen yeterli:

# OpenAI
client = openai.OpenAI(api_key="sk-...")
# Strata
client = openai.OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed"  # lokal, auth yok
)

Hiçbir prompt değişikliği, hiçbir fonksiyon imzası değişikliği yok. Production'da OpenAI kullanırken, offline'a düştüğünde veya gizlilik istediğinde Strata'ya yönlendir.

Sonuçlar

Strata'yı 3 ay kullandım. Bulgular:

  • Maliyet: OpenAI'ye giden $1,200/ay sıfırlandı. Sadece elektrik: ~$5/ay.
  • Gizlilik: Müşteri verisi artık hiç dışarı çıkmıyor. KVKK uyumlu.
  • Latency: Lokalde 7B model ~150ms/token, 13B ~80ms/token. OpenAI'ye internet roundtrip'tan kaçtığım için toplam response time 2-3x hızlandı.
  • Kalite: 7B quantized model GPT-3.5 seviyesinde. 13B quantized GPT-4'e yakın. 70B çoğu görev için GPT-4'ü geçiyor.

Çıkarımlar

Birincisi: quantization çok ilerledi. Q4_K_M artık production kalitesinde. 2024'te Q4 hâlâ "kabul edilemez" di, 2026'da çoğu kullanım senaryosunda yeterli.

İkincisi: context window tradeoff. 70B modeli 32K context'te çalıştırmak 80GB+ VRAM istiyor. 4K'ya düşürürsen 50GB'a iniyor. Çoğu kullanım senaryosu 8K context'ten fazlasını gerektirmiyor.

Üçüncüsü: OpenAI-uyumlu API hayat kurtarıyor. Bu sayede hybrid strateji uygulayabiliyorsun: önce lokal dene, başarısız olursa OpenAI'ye fallback. Maliyet dramatik düşüyor, performans artıyor, gizlilik korunuyor.

Why I dropped cloud LLMs

My first production LLM app ran on the OpenAI API. I started with GPT-4. When the bill came in, my stomach dropped: $40/day, $1,200/month, just for a demo. As a user grew, cost scaled linearly. Add the privacy problem: customer data leaving for the US, GDPR risk.

Solution: local LLM. llama.cpp lets you run quantized models (Q4_K_M, Q5_K_M) on GPU or CPU. Migrate from OpenAI with zero code changes. Single problem: VRAM management.

llama.cpp basics

llama.cpp is a C++ library for efficient LLaMA inference on CPU/GPU. Thanks to quantization, you can fit a 7B model in 5GB VRAM, 13B in 9GB, 70B in 40GB. The Python binding llama-cpp-python makes it easy to use.

# pip install llama-cpp-python
from llama_cpp import Llama
llm = Llama(
    model_path="./models/llama-3-8b-instruct.Q4_K_M.gguf",
    n_ctx=4096,        # context window
    n_gpu_layers=35,   # how many layers to GPU (depends on VRAM)
    n_threads=8        # CPU threads
)
output = llm("Explain quantum computing in 3 sentences", max_tokens=200)
print(output["choices"][0]["text"])

Running is that simple. The hard part is picking the right model for your VRAM.

VRAM math

Quantized model size has a simple formula:

# Model VRAM (GB) ≈ (params × bits_per_weight) / (8 × 1024³)
def estimate_vram_gb(params_b, quant='Q4_K_M'):
    bits = {'Q4_K_M': 4.5, 'Q5_K_M': 5.5, 'Q8_0': 8.0}.get(quant, 4.5)
    return (params_b * 1e9 * bits) / (8 * 1024**3)

# Examples:
# 7B  Q4_K_M:  3.5 GB
# 13B Q4_K_M:  6.5 GB
# 70B Q4_K_M:  39.3 GB

But the model alone isn't enough. The context window also needs VRAM: ~1KB per token. 4K context = 4MB. 32K context = 32MB. Significant but small next to the model.

KV cache (for attention) is larger: 2 × layers × hidden_size × seq_len × 2 bytes. 7B at 4K context: ~250MB extra. 70B at 32K context: ~5GB.

Routing algorithm

This is the most important part of Strata. It measures available VRAM and picks the appropriate model. Use nvidia-smi or torch.cuda.mem_get_info() for instant free VRAM:

import subprocess, re
def get_free_vram_gb():
    out = subprocess.check_output(
        ['nvidia-smi', '--query-gpu=memory.free', '--format=csv,noheader,nounits']
    ).decode()
    return int(out.strip().split()[0]) / 1024  # MB → GB

def pick_model(available_gb, model_catalog):
    """Pick the biggest model but stay under 75% of the budget (overhead)"""
    safe_budget = available_gb * 0.75
    candidates = [m for m in model_catalog if m['vram_gb'] <= safe_budget]
    return max(candidates, key=lambda m: m['params_b']) if candidates else None

catalog = [
    {'name': '7B',  'params_b': 7,  'vram_gb': 4.5,  'path': '...'},
    {'name': '13B', 'params_b': 13, 'vram_gb': 8.5,  'path': '...'},
    {'name': '70B', 'params_b': 70, 'vram_gb': 39.0, 'path': '...'},
]
model = pick_model(get_free_vram_gb(), catalog)
print(f"Selected: {model['name']} ({model['vram_gb']}GB)")

8GB VRAM runs 7B, 12GB runs 13B, 24GB runs 70B (with Q3_K_S). When a user adds a bigger GPU, the bigger model loads automatically.

OpenAI-compatible API

The nicest part: llama-cpp-python ships with an OpenAI-compatible HTTP server. Single command to launch:

python -m llama_cpp.server \
  --model ./models/llama-3-8b-instruct.Q4_K_M.gguf \
  --host 0.0.0.0 \
  --port 8000

Now http://localhost:8000/v1/chat/completions exposes the same API as OpenAI. You only change the base URL in your existing app:

# OpenAI
client = openai.OpenAI(api_key="sk-...")
# Strata
client = openai.OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed"  # local, no auth
)

No prompt changes, no function signature changes. In production you use OpenAI; when offline or when you need privacy you route to Strata.

Results

I've used Strata for three months. Findings:

  • Cost: $1,200/month to OpenAI became $0. Just electricity: ~$5/month.
  • Privacy: Customer data never leaves the machine. GDPR-compliant by design.
  • Latency: 7B model locally ~150ms/token, 13B ~80ms/token. Without the internet roundtrip to OpenAI, total response time is 2-3x faster.
  • Quality: 7B quantized ≈ GPT-3.5. 13B quantized ≈ GPT-4. 70B beats GPT-4 on most tasks.

Takeaways

First: quantization has come a long way. Q4_K_M is now production quality. In 2024, Q4 was still "unacceptable"; in 2026, it's enough for most use cases.

Second: context window trade-off. Running a 70B model with 32K context wants 80GB+ VRAM. Drop to 4K and you need 50GB. Most use cases don't need more than 8K context.

Third: the OpenAI-compatible API is a lifesaver. With it you can run a hybrid: try local first, fall back to OpenAI on failure. Cost drops dramatically, performance goes up, privacy is preserved.

ÖA
Ömer Faruk Aydın
Computer Programmer · AI Integrator · Full-Stack Developer · İstanbul
Computer Programmer · AI Integrator · Full-Stack Developer · Istanbul