@sedatdemirAra

Yerel LLM ile kod asistanı: Ollama ve MLX karşılaştırması

Yerel LLM ile kod asistanı: Ollama ve MLX karşılaştırması

Geçen ay GitHub Copilot faturasını gördükten sonra bir hesap yaptım: ayda 19 dolar bireysel, takım planı kişi başı 39 dolar. Yılda bir geliştirici için 228-468 dolar arası. Peki M2/M3/M4 Mac'lerdeki unified memory ve modern GPU'lar bu işi bedavaya getirebilir mi? Son üç aydır yerel modelleri günlük geliştirme akışımda deniyorum. Sonuç, beklediğimden hem daha iyi hem daha kötü çıktı.

Neden yerel LLM?

Bulut tabanlı çözümlerde üç sıkıntı var. Birincisi maliyet: takım büyüdükçe fatura katlanıyor. İkincisi gizlilik: şirket içi kod, kapalı bir API'ye gönderiliyor. Üçüncüsü gecikme: internet bağlantısına bağımlılık, VPN arkasındaki ortamlarda timeout'lar. Yerel çalıştırma bu üçünü de ortadan kaldırıyor, ama kendi sorunlarını getiriyor.

Ollama kurulumu ve ilk izlenim

Ollama, macOS, Linux ve Windows'ta çalışan bir model çalıştırma aracı. Kurulumu tek komut:

curl -fsSL https://ollama.com/install.sh | sh

macOS'ta brew ile de kurulabilir:

brew install ollama

Kurulumdan sonra bir model çekmek yeterli:

ollama pull codellama:13b
# ya da daha güncel ve küçük bir model
ollama pull qwen2.5-coder:7b

Ollama arka planda bir HTTP sunucusu başlatıyor. Varsayılan port 11434. Herhangi bir istemciden REST API ile konuşabilirsiniz:

curl http://localhost:11434/api/generate -d '{
  "model": "qwen2.5-coder:7b",
  "prompt": "TypeScript'te bir debounce fonksiyonu yaz",
  "stream": false
}'

Bu basitlik Ollama'nın en güçlü yanı. VS Code eklentileri (Continue, Cody), terminal araçları ve özel scriptler doğrudan bu endpoint'e bağlanabiliyor.

MLX: Apple Silicon'a özel çözüm

MLX, Apple'ın kendi makine öğrenmesi framework'ü. Apple Silicon'daki unified memory mimarisini doğrudan kullanıyor; CPU ve GPU arasında veri kopyalama yok. Bu, özellikle büyük modellerde bellek darboğazını azaltıyor.

Kurulum Python üzerinden:

pip install mlx-lm

Model indirme ve çalıştırma:

from mlx_lm import load, generate

model, tokenizer = load("mlx-community/Qwen2.5-Coder-7B-Instruct-4bit")

prompt = "Write a React custom hook that fetches data with AbortController"
response = generate(
    model,
    tokenizer,
    prompt=prompt,
    max_tokens=512
)
print(response)

MLX'in Ollama'dan farkı: daha düşük seviyeli, daha az soyutlama var. HTTP sunucusu yok (kendiniz yazmanız gerekiyor), eklenti ekosistemi zayıf. Ama token/saniye performansı Apple Silicon'da Ollama'yı geçiyor.

Performans karşılaştırması

M3 Pro (18 GB RAM) üzerinde Qwen2.5-Coder 7B (4-bit quantized) modeliyle yaptığım ölçümler:

Metrik Ollama MLX
İlk token süresi ~1.2 saniye ~0.8 saniye
Token/saniye (üretim) 28-32 tok/s 38-45 tok/s
Bellek kullanımı ~5.1 GB ~4.3 GB
Kurulum zorluğu Düşük Orta

MLX, Apple Silicon'da token üretim hızında %30-40 civarında avantajlı. Ollama ise llama.cpp tabanlı; Metal backend kullanıyor ama ek soyutlama katmanı bir miktar performans maliyeti getiriyor.

13B modellere geçtiğinizde 18 GB RAM sınırı hissediliyor. 32 GB RAM'li bir M4 Pro'da 13B modeller rahat çalışırken, 18 GB'da sayfa takası (swap) başlıyor ve token/saniye 8-12'ye düşüyor.

Hangi modeller kod için işe yarıyor?

Üç aydır denediğim modeller arasında net bir sıralama oluştu.

Qwen2.5-Coder 7B/14B: TypeScript, Python, Go için en tutarlı sonuçlar. 7B versiyonu bile JSX üretiminde mantıklı çıktılar veriyor. 14B, fonksiyon düzeyinde refactoring önerilerinde kullanılabilir seviyede.

DeepSeek-Coder-V2-Lite (16B): Çok dilli projelerde iyi. Ama 16B olması 18 GB RAM'de sıkıntı yaratıyor.

CodeLlama 13B: 2023 ortası modeli; güncel API'leri (React 19 hook'ları, Zod v4 gibi) bilmiyor. React 19 use() hook gibi yeni API'leri sordunuzda hallüsinasyon üretiyor.

StarCoder2 7B: Kod tamamlama (infill) görevinde iyi, ama sohbet formatında zayıf.

Benim günlük kullanımım Qwen2.5-Coder 7B'de sabitlendi. 14B'yi yalnızca karmaşık refactoring isteklerinde açıyorum.

VS Code entegrasyonu: Continue eklentisi

Yerel modeli editöre bağlamadan kullanmak pek pratik değil. Continue eklentisi, Ollama ve MLX ile uyumlu çalışan açık kaynak bir çözüm. Kurulumdan sonra .continue/config.json dosyasında modeli tanımlıyorsunuz:

{
  "models": [
    {
      "title": "Qwen2.5 Coder 7B",
      "provider": "ollama",
      "model": "qwen2.5-coder:7b",
      "apiBase": "http://localhost:11434"
    }
  ],
  "tabAutocompleteModel": {
    "title": "StarCoder2 3B",
    "provider": "ollama",
    "model": "starcoder2:3b"
  }
}

Burada iki ayrı model kullanıyorum: satır tamamlama için küçük ve hızlı StarCoder2 3B, sohbet ve açıklama için Qwen2.5-Coder 7B. Bu ayrım performans açısından fark yaratıyor; 7B modeli her tuş vuruşunda çalıştırmak gereksiz gecikme üretir.

RAG ekleme: yerel modelin bilgi sınırını aşmak

Yerel modellerin en büyük dezavantajı bilgi kesim tarihi. Model, eğitim verisinde görmediği kütüphane API'lerini bilmiyor. Zod v4'ün yeni API'leri ya da Drizzle ORM'in son sürümü hakkında soru sorduğunuzda ya eski bilgi veriyor ya da uydurma yapıyor.

Bunu çözmenin yolu Retrieval-Augmented Generation (RAG). Proje dokümanlarını, kütüphane README'lerini ve changelog dosyalarını vektör veritabanına yükleyip, sorgudan önce ilgili parçaları prompt'a ekliyorsunuz.

Basit bir yerel RAG kurulumu:

import chromadb
from sentence_transformers import SentenceTransformer
import subprocess
import json

# Embedding modeli (yerel, 80 MB)
embedder = SentenceTransformer("all-MiniLM-L6-v2")

# ChromaDB yerel koleksiyonu
client = chromadb.PersistentClient(path="./rag_db")
collection = client.get_or_create_collection("project_docs")

def index_file(filepath: str):
    with open(filepath, "r") as f:
        content = f.read()
    # 500 karakterlik parçalara böl
    chunks = [content[i:i+500] for i in range(0, len(content), 400)]
    embeddings = embedder.encode(chunks).tolist()
    ids = [f"{filepath}_chunk_{i}" for i in range(len(chunks))]
    collection.add(documents=chunks, embeddings=embeddings, ids=ids)

def query_with_rag(question: str, model: str = "qwen2.5-coder:7b"):
    q_embedding = embedder.encode([question]).tolist()
    results = collection.query(query_embeddings=q_embedding, n_results=3)
    context = "\n---\n".join(results["documents"][0])

    prompt = f"""Aşağıdaki dokümantasyona dayanarak soruyu yanıtla.

Dokümantasyon:
{context}

Soru: {question}"""

    result = subprocess.run(
        ["ollama", "run", model, prompt],
        capture_output=True, text=True
    )
    return result.stdout

Bu scriptte all-MiniLM-L6-v2 embedding modeli yaklaşık 80 MB; tamamen yerel çalışıyor. ChromaDB de yerel bir vektör veritabanı. Böylece hiçbir veri dışarıya çıkmıyor.

Projenizdeki README.md, CHANGELOG.md, docs/ klasörü ve hatta kaynak kodun kendisini indeksleyebilirsiniz. Deneyimlerime göre, kütüphane dokümanlarını indeksledikten sonra modelin hallüsinasyon oranı belirgin şekilde düşüyor.

MCP ile bağlam sağlama

RAG'ın alternatifi veya tamamlayıcısı olarak MCP (Model Context Protocol) kullanılabilir. Bir MCP sunucusu yazıp proje dosyalarını, veritabanı şemasını ya da API tanımlarını doğrudan modele bağlam olarak sunabilirsiniz. Claude Code'un custom skills mantığına benzer bir yapı, yerel modeller için de kurulabilir.

Ne için yeterli, ne için değil?

Üç ay boyunca yerel modelleri şu görevlerde kullandım ve bir değerlendirme tablosu çıkardı:

Görev Yeterli mi? Notlar
Satır tamamlama (autocomplete) Evet StarCoder2 3B, Copilot'a yakın hız ve kalitede
Fonksiyon gövdesi yazma Kısmen Basit CRUD, utility fonksiyonlar iyi; karmaşık iş mantığı zayıf
Hata açıklama Evet Stack trace verince çoğunlukla doğru yönlendirme yapıyor
Refactoring önerisi Kısmen 7B'de yüzeysel, 14B'de kullanılabilir seviyede
Test yazma Evet Özellikle birim test; entegrasyon testlerinde context eksikliği sorun
Mimari karar Hayır Genel kalıpları biliyor ama proje bağlamını anlamıyor
Yeni API'lerle çalışma RAG ile evet RAG olmadan hallüsinasyon kaçınılmaz

Kısacası: yerel modeller, mekanik ve tekrarlayan kodlama görevlerinde işe yarıyor. "Bu fonksiyonun testini yaz", "Bu interface'den mock data üret", "Bu hata ne anlama geliyor" gibi sorularda günlük kullanıma uygun. Ama "bu projeyi nasıl yapılandırayım" ya da agentic coding tarzı plan-subagent-review döngüleri için bulut modelleri (Claude Opus, GPT-4o) hâlâ çok önde.

Maliyet hesabı

Donanım maliyetini bir kenara bırakıyorum (Mac zaten var varsayımıyla). Yerel çalıştırmanın operasyonel maliyeti sıfır: elektrik dışında ek ödeme yok. M3 Pro, model çalışırken yaklaşık 15-25W çekiyor. 8 saat günlük kullanımda aylık elektrik maliyeti 1-2 dolar civarı.

Copilot Business'ın aylık 19 dolarlık faturasıyla karşılaştırınca, 5 kişilik bir takımda yıllık 1140 dolar tasarruf mümkün. Ama burada gizli maliyet var: kurulum, bakım, model güncelleme, RAG pipeline bakımı. Bunu yapacak birinin zamanı da bir maliyet.

Pratik kurulum önerisi

Benim yerleştiğim düzen şu:

  1. Ollama ile qwen2.5-coder:7b ve starcoder2:3b modellerini çalıştır
  2. Continue eklentisini VS Code'a kur; autocomplete için 3B, chat için 7B modeli ata
  3. Proje dokümanlarını ChromaDB'ye indeksle, RAG pipeline'ını aktif et
  4. Karmaşık görevlerde (mimari kararlar, büyük refactoring) bulut modeline geç

Bu hibrit yaklaşım, günlük işlerin %60-70'ini yerel modelle, kalanını bulut ile karşılamamı sağlıyor.

Yerel mi, bulut mu?

Kesin bir "yerel her şeyi çözer" iddiası gerçekçi değil. 7B parametre ile Claude Opus 4 veya GPT-4o arasında belirgin bir kalite farkı var, özellikle uzun bağlam gerektiren görevlerde. Ama her istek için bulut API'sine para ödemenin de gerekmediğini gördüm. Autocomplete, test üretimi, basit fonksiyon yazımı gibi günlük görevlerin büyük kısmı 7B modelle halledilebiliyor. Gizlilik gereksiniminiz varsa veya internet erişimi kısıtlıysa yerel model tek seçenek zaten. RAG pipeline'ı eklediğinizde bilgi eksikliği sorunu da büyük ölçüde azalıyor. Doğru soru "hangisi daha iyi" değil, "hangi görev için hangisi yeterli"; cevap da çoğu zaman ikisini birlikte kullanmak.