
Mon Aug 24 2026

Selam! 👋
Ben de geçenlerde tek bir soru için saçma sapan bir durum yaşadım: "Bu PDF'i özetle" diyerek 50 sayfalık bir sözleşmeyi bir bulut modeline yolladım. Sonuç? 15 dakika bekledim, fatura şişti, ve verim şirket sunucularından geçti. 😅
O an düşündüm: "Ya bunu yerel modelimle yapsaydım?" Yerel model 3 saniyede cevap verirdi, veri hiç çıkmayacak, maliyet sıfır olacaktı. Ama... o karmaşık bir hukuki analiz isteseydim? Yerel model takılır, bulut modeli ise parlardı ✨.
İşte hibrit AI ajansları tam bu noktada devreye giriyor.
Kısaca: Doğru işi, doğru modele, doğru anda yönlendiren bir orkestratör.
| 🎭 Rol | 🏠 Yerel (Local) Modeller | ☁️ Bulut (Cloud) Modeller |
|---|---|---|
| Gizlilik | Veri asla makineni terk etmez | Veri sağlayıcıya gider |
| Maliyet | Tek seferlik donanım + elektrik | Token başına ödeme (birikir!) |
| Gecikme | Saniyeler, hatta milisaniyeler | Ağ + kuyruk + işlem süresi |
| Güç | Basit/orta görevlerde yeterli | Karmaşık rasyonelleme, kod, analiz |
Hibrit ajan bu ikisini akıllı bir router gibi birleştirir:
Sana pratik bir çerçeve veriyorum, theory değildir:
HybridRouter sınıfı + test senaryolarıollama run llama3 yazıp modelin hazır olması kadar basit 🛠Bu yazıyı bitirdiğinde:
Hadi ilk adımı atalım: routing stratejinizi nasıl tasarlarsınız? ➡️
Ben de bu duvarlara çarptım, hatta birden fazla kez. 🎯 Hem sadece bulut hem de sadece yerel model seçtiklerinde yaşadığım sıkıntıları paylaşayım; belki siz de benzer bir hikaye yaşıyorsunuzdur.
Veri gizliliği riski 🔐
Token maliyeti 💸
Gecikme (latency) ⏱
Donanım sınırlamaları 🛠
Model kapasitesi 📉
Bakım ve güncelleme yükü 🔁
| Senaryo | Sadece Bulut | Sadece Yerel | Benim Deneyimim |
|---|---|---|---|
| Finansal fraud detection | Veri gizliliği ihlali riski, yüksek token maliyeti | GPU yok → inference 2 sn, gerçek zamanlı engellenemez | Hem gizlilik hem gecikme sorunu yaşadım, hibrit çözüm aradım |
| Hasta takip sistemi (IoT) | Ağ kesintisinde alarm gecikiyor | Edge cihazda 1 B model → düşük doğruluk | Cihazda hafif model + bulut fallback kombinasyonu kurtardı |
| İçerik moderasyon (Sosyal medya) | Milyonlarca gönderi → fatura patlıyor | CPU‑only sunucuda 5 sn/gönderi | Batch‑processing + önbellekleme ile maliyet %60 düştü |
Bir sonraki bölümde bu hibrit mimariyi nasıl kuracağımızı, hangi araçları kullanacağımızı ve “nasıl başlarım?” sorusuna cevap arayacağız. 🚀
Hibrit bir LLM sistemini kurarken üç temel bileşen birbirine bağlanır. Her birinin ne yaptığını, nasıl konuştuğunu ve veri nasıl aktığını kısaca gözden geçirelim 👇
Client → [Router] ──► (eğer yerel uygun) ──► [Ollama / vLLM] ──► Yanıt
│
└─► (aksi halde) ──► [Cloud LLM API] ──► Yanıt
Aşağıdaki docker-compose.yml dosyası Ollama’yı, port映射, veri kalıcılığı ve basit bir healthcheck ile çalıştırır. Dosyayı proje köküne koyup docker compose up -d derseniz servis hazır 🚀
version: "3.9"
services:
ollama:
image: ollama/ollama:latest
container_name: ollama-local
restart: unless-stopped
ports:
- "11434:11434" # HTTP API portu
volumes:
- ollama-data:/root/.ollama # Modeller ve cache kalıcı
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes:
ollama-data:
Ne oluyor burada?
ports: Host 11434 → Container 11434 (Ollama REST endpoint).volumes: Modeller indirildikçe ollama-data adlı named volume’de saklanır, container yeniden başlasa bile kaybolmaz.healthcheck: Her 30 saniyede bir /api/tags endpoint’ine istek atar; 3 ardışık başarısızlıkta container unhealthy işaretlenir ve restart politikası devreye girer.| Bileşen | Protokol | Ne Zaman Kullanılır? |
|---|---|---|
| Yerel LLM | HTTP / gRPC | Gizli veri, düşük maliyet, düşük gecikme |
| Bulut LLM | HTTPS (REST) | Büyük model gerektiğinde, hızlı prototip |
| Router | HTTP / gRPC (her iki taraf) | Política motoru, logging, fallback |
Bu üç taş hibrit mimarinin kalbini oluşturur. Router sayesinde “doğru model, doğru yerde, doğru maliyetle” çalışırsınız. 🎯
Hazırsan bu üç pattern'i tek tek inceleyelim. Her birinin avantaj/dezavantaj, kullanım senaryosu ve basit bir akış şeması açıklaması olacak. Kod kısmında da hepsini bir arada tutan bir HybridRouter sınıfı hazırladım 🎯.
Mantık:
Önce yerel (local) model çalıştırılır. Güven skoru (confidence) eşik değerinin altına düşerse istek bulut (cloud) modeline yönlendirilir.
Avantajlar ✅
Dezavantajlar ❌
Kullanım Senaryosu 🛠
Akış Şeması (metin)
İstek → Yerel Model → Güven ≥ Eşik? → Evet → Cevap Dön
↓ Hayır
Bulut Modeli → Cevap Dön
Not: Cascade benim favorim çünkü çoğu günlük sorguyu yerel model çözüyor ve maliyet/gecikme dengesi çok iyi oluyor. 😊
Mantık:
Aynı isteği her iki modele de gönderirsin. Dönen cevapları birleştirirsin (ör. oylama, weighted merge, en yüksek güvenli olanı seçme).
Avantajlar ✅
Dezavantajlar ❌
Kullanım Senaryosu 🛠
Akış Şeması (metin)
İstek → Yerel Model ──┐
├──→ Birleştirme (Oylama / Weighted Merge) → Nihai Cevap
İstek → Bulut Model ──┘
Mantık:
Birincil model (genelde bulut) çalışır. Hata (timeout, 5xx, boş cevap) oluşursa ikincil model (yerel veya daha küçük bir bulut modeli) devreye girer.
Avantajlar ✅
Dezavantajlar ❌
Kullanım Senaryosu 🛠
Akış Şeması (metin)
İstek → Birincil Model → Başarılı? → Evet → Cevap Dön
↓ Hayır (Hata/Timeout)
İkincil Model → Cevap Dön
Aşağıda üç pattern’i de içeren minimal bir HybridRouter sınıfı var. Gerçek projede local_model, cloud_model ve confidence hesaplama mantığını doldurman yeterli.
class HybridRouter:
def __init__(self, local_model, cloud_model, confidence_threshold=0.75):
self.local_model = local_model
self.cloud_model = cloud_model
self.threshold = confidence_threshold
# ---------- Cascade ----------
def cascade(self, prompt: str) -> str:
"""Önce yerel, güven düşükse buluta yönlendir."""
local_resp, confidence = self.local_model.predict(prompt)
if confidence >= self.threshold:
return local_resp
# Güven yetersiz → bulut
cloud_resp, _ = self.cloud_model.predict(prompt)
return cloud_resp
# ---------- Ensemble ----------
def ensemble(self, prompt: str, strategy: str = "vote") -> str:
"""Her iki modelden cevap al, birleştir."""
local_resp, local_conf = self.local_model.predict(prompt)
cloud_resp, cloud_conf = self.cloud_model.predict(prompt)
if strategy == "vote":
# Basit oylama: güven yüksek olan kazanır
return local_resp if local_conf >= cloud_conf else cloud_resp
elif strategy == "weighted":
# Ağırlıklı birleştirme (örnek)
# Gerçek implementasyonda metinleri merge edebilirsin
return local_resp if local_conf * 0.6 + cloud_conf * 0.4 > 0.5 else cloud_resp
else:
raise ValueError(f"Bilinmeyen strateji: {strategy}")
# ---------- Fallback ----------
def fallback(self, prompt: str) -> str:
"""Birincil model hata verirse ikincil modeli dene."""
try:
# Varsayılan: bulut birincil
primary_resp, _ = self.cloud_model.predict(prompt)
return primary_resp
except Exception as exc:
# Logla, sonra yerel modeli dene
print(f"[Fallback] Birincil model hata: {exc}")
secondary_resp, _ = self.local_model.predict(prompt)
return secondary_resp
Bu sayede ne oluyor?
cascade() → maliyet/gecikme dengesi.ensemble() → doğruluk artışı (maliyet artışıyla).fallback() → hizmet kesintisizliği.Hangi pattern projen için uygun? Küçük bir tablo yapıp karşılaştırıp karar verelim 👇 (sonraki bölümde detaylandıracağız).
Hazırsan FastAPI ile tek dosyalık, kopyala‑yapıştır çalışan bir hybrid router yazalım 🚀
İstersen kendi projene uyarlayıp, yerel Ollama ile bulut OpenAI arasında akıllı yönlendirme yaparsın.
pip install fastapi uvicorn httpx pydantic python-dotenv
.envdosyasınaOPENAI_API_KEYeklemeyi unutma ❗️
main.py# main.py
import os
import logging
from typing import Literal
import httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from dotenv import load_dotenv
# -------------------------------------------------
# 1️⃣ Ortam & Logging
# -------------------------------------------------
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434/api/generate") # varsayılan yerel endpoint
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)-8s | %(message)s",
)
logger = logging.getLogger(__name__)
# -------------------------------------------------
# 2️⃣ Pydantic Modelleri
# -------------------------------------------------
class RouteRequest(BaseModel):
task: str = Field(..., description="Yapılacak görev (ör. 'code', 'summary')")
latency_budget_ms: int = Field(..., ge=0, description="Maksimum tolerans süresi (ms)")
sensitivity: Literal["low", "medium", "high"] = Field(..., description="Veri hassasiyeti")
class RouteResponse(BaseModel):
model_used: Literal["ollama", "openai"]
answer: str
latency_ms: int
# -------------------------------------------------
# 3️⃣ Karar Fonksiyonu – Basit Heuristic
# -------------------------------------------------
def decide_model(req: RouteRequest) -> Literal["ollama", "openai"]:
"""
Basit kural:
- Hassas veri (high) → yerel Ollama
- Çok düşük latency budget (<200 ms) → yerel
- Aksi halde bulut OpenAI
"""
if req.sensitivity == "high":
logger.info("Yüksek hassasiyet → Ollama seçildi")
return "ollama"
if req.latency_budget_ms < 200:
logger.info("Latency budget düşük → Ollama seçildi")
return "ollama"
logger.info("Standart istek → OpenAI seçildi")
return "openai"
# -------------------------------------------------
# 4️⃣ Model İstemcileri
# -------------------------------------------------
async def call_ollama(prompt: str) -> str:
payload = {"model": "llama3", "prompt": prompt, "stream": False}
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post(OLLAMA_URL, json=payload)
resp.raise_for_status()
return resp.json().get("response", "")
async def call_openai(prompt: str) -> str:
headers = {"Authorization": f"Bearer {OPENAI_API_KEY}"}
payload = {
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 512,
}
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post("https://api.openai.com/v1/chat/completions", json=payload, headers=headers)
resp.raise_for_status()
return resp.json()["choices"][0]["message"]["content"]
# -------------------------------------------------
# 5️⃣ FastAPI Uygulaması
# -------------------------------------------------
app = FastAPI(title="Hybrid Router Demo")
@app.post("/route", response_model=RouteResponse)
async def route_request(req: RouteRequest):
start = __import__("time").perf_counter()
model = decide_model(req)
try:
if model == "ollama":
answer = await call_ollama(req.task)
else:
answer = await call_openai(req.task)
except httpx.HTTPStatusError as exc:
logger.error("Model çağrısı hata verdi: %s", exc)
raise HTTPException(status_code=502, detail="Model servisine ulaşılamadı")
except Exception as exc: # genel yakalama
logger.exception("Beklenmeyen hata")
raise HTTPException(status_code=500, detail="İç sunucu hatası")
latency_ms = int((__import__("time").perf_counter() - start) * 1000)
logger.info("Yanıt süresi: %d ms | Model: %s", latency_ms, model)
return RouteResponse(model_used=model, answer=answer, latency_ms=latency_ms)
# -------------------------------------------------
# 6️⃣ Çalıştırma (CLI)
# -------------------------------------------------
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
# 1️⃣ .env dosyası oluştur
echo "OPENAI_API_KEY=sk-..." > .env
# OLLAMA_URL varsayılan localhost:11434, farklıysa .env'e ekle
# 2️⃣ Sunucuyu başlat
uvicorn main:app --reload
Artık http://localhost:8000/route endpoint’ine POST atabilirsin:
{
"task": "Python ile fibonacci fonksiyonu yaz",
"latency_budget_ms": 150,
"sensitivity": "low"
}
Yanıt örneği:
{
"model_used": "ollama",
"answer": "def fib(n):\n a, b = 0, 1\n for _ in range(n):\n a, b = b, a + b\n return a",
"latency_ms": 112
}
model alanından değiştirerek farklı yerel modeller dene.gpt-4o-mini yerine gpt-4o veya gpt-3.5-turbo yapabilirsin.DEBUG yaparak akışları daha detaylı izle.httpx.AsyncClient) – CI/CD pipeline’ına ekle 🚦Bu dosyayı kopyala, .env’ı doldur, uvicorn main:app --reload de ve hybrid router’ın canlıya gelmesini izle! ✨
Hazırsan başlayalım 🚀 — maliyeti ölçmek, optimize etmek ve takip etmek aslında küçük adımların birikimi. İşte benim günlük hayatta kullandığım yöntemler ve bir de basit bir Bash script 🎯.
| Yaklaşım | Nasıl Hesaplanır? | Avantaj | Dezavantaj |
|---|---|---|---|
| Bulut token maliyeti | Token Sayısı × $/1K token (ör. GPT‑4 ≈ $0.03/1K) |
Ölçeklenebilir, donanım yok | Uzun vadede pahalı |
| Yerel donanım amortisman | (GPU fiyatı + elektrik + soğutma) / Ömür (gün) × Günlük token |
Tek seferlik yatırım, veri gizliliği | Başlangıç maliyeti yüksek, bakım sizin |
Küçük bir kural: Günlük token kullanımınız 10 M üzerindeyse bulut genelde daha ucuz; altındaysa yerel donanımları değerlendirin 🤔.
Prompt Caching 🔁
Aynı sistem/yardımcı mesajları tekrar göndermiyorsunuz. Önbellekte tutup %30‑%50 token tasarrufu yakalayabilirsiniz.
Quantization 📦
Model Distillation 🎓
Büyük model (teacher) → Küçük model (student).
Örnek: 70B → 7B, %90 performans, %10 maliyet.
| Metrik | Eşik | Aksiyon |
|---|---|---|
| Günlük token | 8 M | Uyarı e‑postası gönder |
| Günlük maliyet (bulut) | $120 | Otomatik scaling durdur |
| GPU kullanım oranı | 85 % | Yeni batch kuyruğa al |
| Model latency (p95) | 350 ms | Quantization / caching tetikle |
Bu sayılar benim iş yüküme göre; siz kendi trafiğinize göre %10‑%20 play yapabilirsiniz ⚙️.
#!/usr/bin/env bash
# -------------------------------------------------
# daily_token_cost.sh
# Günlük token kullanımını loglar, maliyet tahmini yapar
# ve eşik aşıldığında uyarı maili atar.
# -------------------------------------------------
# ---- AYARLAR ----
LOG_DIR="/var/log/llm_cost"
mkdir -p "$LOG_DIR"
DATE=$(date +%F)
TOKEN_LOG="${LOG_DIR}/tokens_${DATE}.log"
COST_PER_1K=0.03 # $/1K token (bulut fiyatı)
THRESHOLD_TOKENS=8000000 # 8 M token
THRESHOLD_COST=120 # $120
ALERT_EMAIL="ops@example.com"
# ---- YARDIMCI FONKSİYON ----
send_alert() {
local subject="$1"
local body="$2"
echo "$body" | mail -s "$subject" "$ALERT_EMAIL"
}
# ---- ANA AKİŞ ----
# 1. Günlük token sayısını topla (örnek: API yanıtındaki usage.total_tokens)
# Burada `jq` ile JSON loglarını parse ediyoruz.
total_tokens=$(jq -s 'map(.usage.total_tokens) | add' /var/log/llm_api/*.json 2>/dev/null || echo 0)
# 2. Logla
echo "${DATE} ${total_tokens}" >> "$TOKEN_LOG"
# 3. Maliyet hesapla
cost=$(echo "scale=2; $total_tokens / 1000 * $COST_PER_1K" | bc)
# 4. Konsola özet
echo "🗓 ${DATE} | Token: ${total_tokens} | Tahmini Maliyet: \$${cost}"
# 5. Eşik kontrolü
if (( total_tokens > THRESHOLD_TOKENS )); then
send_alert "⚠️ Token Eşiği Aşıldı (${DATE})" \
"Günlük token kullanımı ${total_tokens} (eşik: ${THRESHOLD_TOKENS})."
fi
if (( $(echo "$cost > $THRESHOLD_COST" | bc -l) )); then
send_alert "💰 Maliyet Eşiği Aşıldı (${DATE})" \
"Tahmini maliyet \$${cost} (eşik: \$${THRESHOLD_COST})."
fi
Nasıl çalışıyor?
jq ile tüm API yanıt loglarından usage.total_tokens toplar.tarih token satırı yazar.bc ile basit bir çarpım yapar → tahmini maliyet.mail komutu ile ops ekibine uyarı atar.İpucu: Cron’a
0 1 * * * /usr/local/bin/daily_token_cost.shekleyerek her gece 01:00’de otomatik çalıştırın ⏰.
logrotate) bağlayın, disk dolmasın.Hadi şimdi scripti sunucunuza atın, cron’a ekleyin ve maliyetleriniz kontrol altında kalsın 🎉. Herhangi bir sorunda yanınızdayım!
Hibrit mimarilerde routing kararı alırken hassas verinin buluta sızmaması kritiktir 🚦.
Basit bir kural: PII (Kişisel Tanımlayıcı Bilgi) tespit edilirse, istek on‑premise kalmalı.
*** ile değiştirimport re
def mask_pii(text: str) -> str:
"""
Basit regex tabanlı PII maskeleme.
- E‑posta, TC Kimlik No, telefon (TR) ve kredi kartı numaralarını maskeleyerek döner.
"""
# E‑posta
text = re.sub(r'\b[\w\.-]+@[\w\.-]+\.\w{2,}\b', '***@***.***', text)
# TC Kimlik No (11 haneli, başta 0 olmaz)
text = re.sub(r'\b[1-9]\d{9}\b', '***********', text)
# Türk telefon (05xx xxx xx xx veya +90 5xx xxx xx xx)
text = re.sub(r'(\+90\s?)?0?5\d{2}\s?\d{3}\s?\d{2}\s?\d{2}', '*** *** ** **', text)
# Kredi kartı (16 hane, boşluk/çizgi ile)
text = re.sub(r'\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b', '**** **** **** ****', text)
return text
Nasıl çalışıyor?
text içindeki her bir pattern için re.sub çağrılır.*** / *********** gibi sabit maskeyle değiştirilir.Not: Gerçek ortamda Presidio, spaCy NER veya cloud‑native DLP servisleri daha kapsamlı sonuç verir. Bu fonksiyon hızlı prototip veya düşük hacimli işler için yeterlidir ✅.
| Adım | Ne Kaydedilir? | Neden? |
|---|---|---|
| Maskeleme öncesi hash (SHA‑256) | Orijinal verinin hash’i (veri kendisi değil) | KVKK 12. maddesi – veri işlenme kanıtı |
| Maskeleme sonrası metin | Maskelemeli metin | GDPR 30. madde – işlem kayıtları |
| Routing kararı | on_premise / cloud + timestamp |
Denetim izi & incident response |
| Kullanıcı / servis kimliği | user_id, service_name |
Sorumluluk zinciri |
mask_pii() ile anında güvenli hale getirBu akışı CI/CD pipeline’ınıza da ekleyebilirsiniz: test → mask → log → route 🎯.
Hazırsanız bir sonraki bölümde policy engine (OPA / Kyverno) ile bu kararları nasıl otomatikleştireceğimize bakalım!
Merhaba! 📚 Hazırsan başlayalım ve biraz pratik yapalım. Küçük bir pilot projeyle başlamak, hem motivasyonunu yüksek tutar hem de beklenmedik sürprizlerle karşılaşmazsın.
Neler yapabilirsin?
Basit bir akış 🔁
“Siz de deneyin!” ✅ Kendi projeniz için ilham almak isterseniz aşağıdaki adımları deneyebilirsiniz:
# Örnek: InternalDocBot (basit bir Python servisi)
- Kullanılan kütüphaneler: fastapi, langchain, pypdf2
- Depo linki: https://github.com/yourorg/InternalDocBot
- Discord geliştirici kanalı: https://discord.gg/yourorg-dev
Sonuçlar neler olur? ❗️
GitHub depoları
Discord/Discord sunucuları
Blog yazıları ve rehberler
Siz de deneyin, sonuçları paylaşın! 🚀 Birkaç içerik ile nasıl başardığınızı, karşılaştığınız zorlukları ve elde ettiğiniz kazanımları bize bildirin. Her pilot projenin bir sonucu olur ve topluluk hepimizi ilerletir.
Bakalım senin projen neler getirecek? 🎉
(Umarım fikir verici oldu. Bir dahaki sefere başka bir öneri ile görüşürüz!)
Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.
All rights reserved