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 | shmacOS'ta brew ile de kurulabilir:
brew install ollamaKurulumdan sonra bir model çekmek yeterli:
ollama pull codellama:13b
# ya da daha güncel ve küçük bir model
ollama pull qwen2.5-coder:7bOllama 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-lmModel 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.stdoutBu 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:
- Ollama ile
qwen2.5-coder:7bvestarcoder2:3bmodellerini çalıştır - Continue eklentisini VS Code'a kur; autocomplete için 3B, chat için 7B modeli ata
- Proje dokümanlarını ChromaDB'ye indeksle, RAG pipeline'ını aktif et
- 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.