7 Eylül 2025 Pazar

Docker Buildx ile Çok Mimarili İmaj Oluşturma ve GitHub Actions ile Otomatik Yayınlama (2025 Rehberi)

Giriş

Apple Silicon (ARM64), Raspberry Pi gibi cihazlarla birlikte “aynı imajı farklı mimarilerde çalıştırma” ihtiyacı günlük hayatın bir parçası oldu. Docker Buildx, tek bir komutla linux/amd64 ve linux/arm64 için çok mimarili (multi-arch) imajlar üretmenizi sağlıyor. Bu rehberde, yerelde Buildx ile derleme, doğru Dockerfile pratikleri, imajı Docker Hub’a itme ve son olarak GitHub Actions ile otomatik yayımlamayı adım adım anlatıyorum.

Önkoşullar

- Docker 24+ veya Docker Desktop (BuildKit varsayılan açık olmalı)
- Docker Hub veya GHCR hesabı (örneklerde Docker Hub kullanacağım)
- GitHub deposu (Actions için)

Buildx Kurulumu ve Kontrolü

Güncel Docker Desktop, buildx ve QEMU emülasyonu ile birlikte gelir. Terminalde aşağıdaki komutlarla Buildx’in aktif olduğunu kontrol edin:

docker buildx version
docker buildx ls

Gerekirse yeni bir builder oluşturabilirsiniz:

docker buildx create --name multiarch --use
docker buildx inspect --bootstrap

“qemu not registered” gibi bir hata alırsanız, Docker Desktop’ı güncelleyin veya Linux için QEMU’yu kurun. Çoğu yeni kurulumda ekstra adım gerekmeyecektir.

Örnek Dockerfile (Go ile statik ikili)

Dil bağımsız olarak çalışabilirsiniz; ancak Go ile statik ikili üretmek multi-arch derlemelerde idealdir. Minimal ve güvenli bir imaj için distroless veya scratch tabanını tercih edin.

# Dockerfile
# 1) Build aşaması
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# CGO kapalı, statik derleme
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$(go env GOARCH) go build -ldflags="-s -w" -o app ./cmd/server

# 2) Minimal çalışma aşaması
FROM gcr.io/distroless/static:nonroot
WORKDIR /app
COPY --from=builder /src/app /app/app
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app/app"]

Not: Go projesinde “./cmd/server” yolu örnektir. Projenize göre düzenleyin. Go dışındaki dillerde (Node.js, Python) multi-stage ve mimariye uygun resmi taban imajları kullanın. .dockerignore dosyasıyla gereksiz dosyaları dışarıda bırakmayı unutmayın.

Yerelde Çok Mimarili İmaj Derleme ve İtme

Önce Docker Hub’a giriş yapın:

docker login

Ardından Buildx ile iki mimariye birden derleyip tek bir çoklu manifest altında toplayın ve push edin:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t KULLANICI_ADI/uygulama:1.0.0 \
  -t KULLANICI_ADI/uygulama:latest \
  --provenance=true --sbom=true \
  --push .

Manifest’i doğrulamak için:

docker buildx imagetools inspect KULLANICI_ADI/uygulama:latest

GitHub Actions ile Otomatik Yayınlama

Her push veya tag ile otomatik imaj üretmek için .github/workflows/docker.yml adında bir iş akışı oluşturun. Aşağıdaki örnek, semantik sürüm etiketlerini otomatik algılar ve iki mimariye birden push eder. Docker Hub kullanıcı adı ve erişim token’ınızı repo Secrets kısmında DOCKERHUB_USERNAME ve DOCKERHUB_TOKEN olarak saklayın.

name: Docker Multi-Arch

on:
  push:
    branches: [ "main" ]
    tags: [ "v*" ]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            ${{ secrets.DOCKERHUB_USERNAME }}/uygulama
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=sha

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          provenance: true
          sbom: true

Bu akışta setup-qemu-action emülasyon için, build-push-action ise derleme ve push için kullanılır. metadata-action, tag yönetimini kolaylaştırır; main branch için “latest” benzeri etiketler ve tag push için semantik sürümler üretir.

OCI Etiketleri, Güvenlik ve İpuçları

- OCI etiketleri (org.opencontainers.image.*) ile kaynak kod, lisans ve açıklama bilgilerini ekleyin. metadata-action bunu otomatik sağlar.
- sbom: true ve provenance: true ile tedarik zinciri görünürlüğünü artırın.
- .dockerignore ile node_modules, build çıktıları, test verileri gibi gereksiz klasörleri dışarıda tutun; imaj boyutu ve gizlilik açısından önemlidir.
- Çok aşamalı (multi-stage) Dockerfile ile sadece gereken dosyaları çalışma imajına kopyalayın.
- Bazı dil ekosistemlerinde mimariye özgü bağımlılıklar olabilir. Özellikle Python’da native modüller içeren paketlerde uygun taban imajını ve derleme araçlarını kullanın.

Yaygın Hatalar ve Çözümleri

- Hata: “no match for platform in manifest” — Kullandığınız baz imaj ilgili mimariyi desteklemiyor. Aynı imajın çok mimarili varyantını (ör. alpine, debian-slim) tercih edin.
- Hata: “exec format error” — Yanlış mimari için derlenmiş ikiliyi çalıştırıyorsunuz. Multi-stage içinde hedef GOARCH/GOOS (veya eşdeğerleri) doğru ayarlanmalı.
- Hata: “qemu not registered” — QEMU emülasyonu kurulu değil. GitHub Actions’ta setup-qemu-action kullanın; yerelde Docker Desktop güncel olsun.
- Hata: “denied: requested access to the resource is denied” — Registry girişiniz veya tag adı hatalı. docker login ve depo adını doğrulayın.

Sonuç

Buildx sayesinde tek bir komutla amd64 ve arm64 için üretim yapabilir, tek bir etiket altında birleştirip dağıtabilirsiniz. GitHub Actions ile bunu CI/CD’ye bağladığınızda yeni sürümleriniz saniyeler içinde Docker Hub’a düşer. Doğru baz imaj, temiz Dockerfile ve önbellekleme stratejileri ile hem derleme sürenizi hem de imaj boyutlarınızı önemli ölçüde iyileştirebilirsiniz.

6 Eylül 2025 Cumartesi

Docker ve OpenTelemetry ile Node.js Uygulamasında Dağıtık İzleme: Adım Adım Kurulum Kılavuzu

Giriş

Modern mikroservis mimarilerinde bir isteğin sistem içinde nasıl yol aldığını anlamak, performans sorunlarını çözmek ve kök neden analizi yapmak için dağıtık izleme artık bir zorunluluk. OpenTelemetry (OTel), dil bağımsız açık standartları ve zengin SDK’ları ile Node.js uygulamalarınızda izleme (tracing) kurulumunu kolaylaştırır. Bu yazıda, Docker + OpenTelemetry Collector + Jaeger kullanarak Node.js tabanlı bir serviste uçtan uca izlemeyi adım adım kuracağız. Amaç, üretime yakın bir geliştirme deneyimi sağlamak, gecikmeleri ölçmek ve bağımlılıkları görünür kılmaktır.

Mimari ve Bileşenler

Kuracağımız basit topolojide üç temel bileşen bulunuyor: 1) Otomatik enstrümantasyonla iz verisi üreten Node.js servisi, 2) OTLP üzerinden iz kabul edip yöneten OpenTelemetry Collector, 3) Sorgulama ve görselleştirme için Jaeger. Collector, gelecekte Grafana Tempo, Honeycomb veya Zipkin gibi hedeflere geçişi kolaylaştıran bir ara katman görevi görür.

Node.js Projesini Hazırlama

Yeni bir proje başlatın ve gerekli bağımlılıkları kurun. Örnek bir Express API üzerinden gideceğiz, fakat otomatik enstrümantasyon HTTP, gRPC, MySQL, Redis gibi birçok paketi destekler.

# Projeyi başlat
npm init -y

# Express ve OpenTelemetry paketleri
npm i express
npm i @opentelemetry/sdk-node @opentelemetry/api @opentelemetry/resources \
@opentelemetry/semantic-conventions @opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-otlp-grpc

Ardından uygulama girişinde OpenTelemetry’yi başlatacak bir dosya oluşturun. Bu dosya, servis adı ve ortam gibi meta bilgileri de ekler.

// tracing.js
'use strict';
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-otlp-grpc');

const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'node-api',
    [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV || 'dev',
  }),
  traceExporter: new OTLPTraceExporter({
    url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://otel-collector:4317'
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start()
  .then(() => console.log('OpenTelemetry başlatıldı'))
  .catch((err) => console.error('OTel hatası:', err));

process.on('SIGTERM', () => {
  sdk.shutdown().finally(() => process.exit(0));
});

Basit bir Express sunucusu ekleyelim. tracing.js, uygulamadan önce yüklenmelidir ki tüm modüller doğru enstrümante edilsin.

// index.js
'use strict';
require('./tracing'); // OTel ön yükleme

const express = require('express');
const app = express();

app.get('/health', (req, res) => {
  res.json({ ok: true, ts: Date.now() });
});

app.get('/slow', async (req, res) => {
  await new Promise(r => setTimeout(r, 300)); // yapay gecikme
  res.send('yavaş yanıt');
});

app.listen(3000, () => console.log('API 3000 portunda'));

OpenTelemetry Collector ve Jaeger ile Docker Compose

Collector, uygulamadan gelen OTLP verilerini alıp Jaeger’a iletecek. Aşağıda temel bir docker-compose yapısı ve Collector konfigürasyonu bulunuyor.

# docker-compose.yml
version: '3.9'
services:
  api:
    build: .
    command: node index.js
    environment:
      NODE_ENV: dev
      OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
      OTEL_TRACES_SAMPLER: parentbased_traceidratio
      OTEL_TRACES_SAMPLER_ARG: '0.5'
    ports:
      - "3000:3000"
    depends_on:
      - otel-collector

  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.103.0
    command: ["--config=/etc/otelcol-config.yaml"]
    volumes:
      - ./otelcol-config.yaml:/etc/otelcol-config.yaml:ro
    ports:
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP (opsiyonel)
    depends_on:
      - jaeger

  jaeger:
    image: jaegertracing/all-in-one:1.57
    ports:
      - "16686:16686" # Jaeger UI

Collector’ın konfigürasyon dosyası, OTLP alıcıyı etkinleştirir ve verileri Jaeger’a yollar. İleride Zipkin, Tempo veya başka hedeflere ek ihracatçılar tanımlayabilirsiniz.

# otelcol-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
      http:

exporters:
  jaeger:
    endpoint: jaeger:14250
    tls:
      insecure: true

processors:
  batch:
    timeout: 1s
    send_batch_size: 512

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger]

Çalıştırma ve Doğrulama

Proje köküne basit bir Dockerfile ekleyin. Node tabanlı minimal bir imaj, üretime giden yolda iyi bir başlangıçtır.

# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

Artık ortamı ayağa kaldırabilirsiniz. Aşağıdaki komut, API, Collector ve Jaeger’ı birlikte çalıştırır.

docker compose up --build

Tarayıcıdan http://localhost:16686 adresine gidip Jaeger UI’ı açın. Service menüsünde “node-api” servis adını göreceksiniz. Ayrıntılı izler için bir iki istek atın:

curl http://localhost:3000/health
curl http://localhost:3000/slow

Jaeger üzerinden isteklerin gecikme dağılımını, span ağaçlarını, endpoint bazlı hataları ve bağımlılık grafini analiz ederek performans darboğazlarını hızla teşhis edebilirsiniz.

En İyi Uygulamalar ve İpuçları

Örnek konfigürasyonda örnekleme oranını yüzde 50 olarak ayarladık. Üretimde, trafik seviyesine göre oranı düşürmek ve belirli endpoint’lerde dinamik örnekleme uygulamak mantıklıdır. Ayrıca, Resource etiketlerine versiyon, bölge ve takım bilgisi eklemek arama ve filtrelemeyi kolaylaştırır. Kolektörde attributes veya transform işlemcileri ile PII verileri kırpma/anonimleştirme adımları ekleyebilirsiniz. Gecikmeleri daha iyi yorumlamak için kritik yerlerde manuel span eklemek (ör. yoğun CPU işlemi, harici API çağrıları) fayda sağlar.

Güvenlik açısından Collector ile uygulama arasındaki trafiği mTLS ile şifrelemek ve dış ağlara ihracatta TLS’i etkinleştirmek önemlidir. Gözlemlenebilirlik verisi de kritiktir; erişim kontrolü, saklama süresi ve maliyet optimizasyonu (ör. örnekleme, toplu gönderim ayarları) planlanmalıdır. CI/CD’de, tracer başlatma hatalarını görünür kılmak için sağlık kontrolleri ve basit duman testleri ekleyin.

Sonuç

OpenTelemetry, Node.js servisleriniz için satıcı bağımsız, geleceğe dönük bir izleme altyapısı kurmanızı sağlar. Docker ile izleme yığınını dakikalar içinde ayağa kaldırabilir, Collector aracılığıyla hedef sistemleri esnekçe değiştirebilir, Jaeger ile sorunları hızla teşhis edebilirsiniz. Bugünkü kurulum, üretime geçişte ihtiyaç duyacağınız dinamik örnekleme, ek işlemciler, metrik ve log toplama gibi yeteneklerin de temelini oluşturur. İlk adımı attınız; şimdi span’ları zenginleştirip gerçek kullanıcı senaryolarını görünür kılma zamanı.

5 Eylül 2025 Cuma

Ollama ile Yerelde LLM Çalıştırma Rehberi: Kurulum, GPU Hızlandırma ve İpuçları

Giriş: Neden Yerelde LLM Çalıştırmalı?

Bulut maliyetlerinin arttığı, veri gizliliğinin ise daha kritik hale geldiği bir dönemde, büyük dil modellerini (LLM) yerel makinenizde çalıştırmak hem hızlı deney imkânı hem de verilerinizi cihazınızdan dışarı çıkarmadan çalışma rahatlığı sağlar. Ollama, GGUF formatındaki modern modelleri tek komutla indirip kullanmanıza olanak veren hafif ve kullanımı kolay bir araçtır. Bu rehberde Windows, macOS ve Linux üzerinde Ollama kurulumunu, GPU hızlandırmasını, performans ayarlarını ve uygulamanıza entegre etmenin pratik yollarını anlatıyorum.

Ön Koşullar ve Donanım Gereksinimleri

LLM’leri yerelde çalıştırırken CPU, RAM ve özellikle GPU VRAM kapasitesi önemlidir. 7B parametreli, 4-bit sıkıştırılmış (quantized) bir model için genellikle 6–8 GB VRAM ve en az 8–16 GB sistem RAM tavsiye edilir. 13B için 12 GB ve üzeri VRAM ideal; 70B gibi devasa modeller ise çoğunlukla masaüstü sınıfını aşar. Yine de Ollama, VRAM yetersizse katmanların bir kısmını CPU’ya taşıyabilir; bu durumda yanıt süresi uzar.

Kurulum: Windows, macOS ve Linux

- Windows: En kolay yol resmi yükleyici veya winget ile kurulumdur. Komut satırına winget install Ollama.Ollama yazın. Kurulum bittiğinde ollama komutuna erişebiliyor olmalısınız.

- macOS: Homebrew kullanıyorsanız brew install ollama yeterlidir. Apple Silicon (M1/M2/M3) üzerinde Metal hızlandırma ile iyi performans alırsınız.

- Linux: Resmi sitedeki script ile kurabilirsiniz: curl -fsSL https://ollama.com/install.sh | sh. Ardından servis otomatik başlatılır ve http://localhost:11434’te API hazır olur.

Model İndirme ve İlk Çalıştırma

Ollama, modelleri depodan çekmek için pull, etkileşimli çalıştırmak için run komutlarını kullanır. Örneğin 8B boyutlu bir Llama 3 varyantını denemek için: ollama pull llama3:8b ve ardından ollama run llama3:8b. İlk indirme birkaç dakika sürebilir. Türkçe için Llama 3 ailesi, Mistral veya Gemma tabanlı GGUF modelleri de tercih edilebilir. Komut satırında sistem yönergeleri (system prompt) verebilir, çıktıyı kısaltmak için Ctrl+C ile durdurabilirsiniz.

GPU Hızlandırma ve İnce Ayar

Uygun sürücüler yüklüyse Ollama GPU’yu otomatik kullanır: Windows/NVIDIA için CUDA, macOS için Metal, Linux/AMD için ROCm desteğiyle çalışır. Performans düşükse modelin kuantizasyon varyantını değiştirin. Örneğin Q4_K_M daha az VRAM kullanır, Q6_K veya Q8_0 kaliteyi artırır ama daha fazla bellek ister. Bazı durumlarda GPU kullanımını sınırlamak için model seçeneklerinde gpu_layers değerini düşürmek yararlı olabilir.

Akıcı diyaloglar için bağlam penceresini artırabilirsiniz. Örnek seçenekler: num_ctx (bağlam uzunluğu), temperature, top_p ve repeat_penalty. Uzun dökümanlarla çalışırken num_ctx’i yükseltmek gerekir; ancak bu bellek kullanımını artırır. Sık tekrarlanan ifadeleri azaltmak için repeat_penalty değerini 1.1–1.2 aralığında deneyebilirsiniz.

API ile Entegrasyon: cURL ve Python

Ollama, varsayılan olarak http://localhost:11434 adresinde REST API sunar. Basit bir metin üretimi için cURL ile örnek istek:

curl -X POST http://localhost:11434/api/generate -d '{ "model": "llama3:8b", "prompt": "Türkçe olarak üç maddede kuantizasyonu açıkla.", "options": { "num_ctx": 4096, "temperature": 0.7 } }'

Python tarafında requests ile akışlı (stream) yanıtlar alabilirsiniz. İstek gövdesine stream: true eklerseniz kelime kelime akan sonuçları terminale yazdırabilirsiniz. Bu sayede sohbet uygulaması kurmak veya web arayüzünde canlı çıktı göstermek kolaylaşır.

Performans İpuçları ve Model Seçimi

- Doğru boyut: 7B–8B modeller, dizüstüler için tatlı noktadır. 13B daha kaliteli yanıtlar verse de masaüstü GPU’ları gerektirebilir.

- Kuantizasyon: Q4 aileleri hızlı ve hafif; Q5–Q8 kaliteyi artırır. Uygulama senaryonuza göre dengeyi bulun.

- Önbellek: Model, bağlam önbelleğini (KV cache) kullanır. Aynı yönergelerle tekrar çalışırken hızlanma görürsünüz. Uzun oturumlarda bağlam yönetimi (önemli kısımları sabitleme) fayda sağlar.

- Türkçe doğruluğu: Modelden Türkçe üretim istemek için yönergenizi açık yazın (örn. “Lütfen Türkçe yanıtla”). Gerekirse sistem mesajına yazım kurallarına uyma ve kısa/uzun yanıt tercihlerinizi ekleyin.

Gizlilik, Ağ Erişimi ve Güvenlik

Varsayılan yapılandırmada API sadece yerel cihaza (localhost) açıktır. Uzaktan erişime açmak istiyorsanız güçlü bir parola/kapsayıcı ağ politikası, ters proxy ve gerekiyorsa VPN kullanın. Yerelde çalıştığınız için metinleriniz buluta gitmez; yine de günlükleri ve uygulama kayıtlarını şirket politikalarına uygun konumlarda saklayın.

Sorun Giderme

- Model yüklenmiyor: Disk alanını ve indirme bütünlüğünü kontrol edin. Gerekirse ollama rm ile modeli silip tekrar indirin.

- VRAM hataları: Daha düşük bir kuantizasyon seçin (Q4), gpu_layers’ı azaltın veya bağlam penceresini küçültün. Ollama çoğu durumda otomatik olarak CPU’ya düşer, ancak bu performansı etkiler.

- Windows’ta sürücü: NVIDIA sürücülerinin güncel olduğundan emin olun. Performans sorunları genellikle eksik ya da eski sürücülerden kaynaklanır.

- Çakışan port: 11434 portunu kullanan başka bir servis varsa kapatın veya Ollama’yı farklı bir portta başlatın.

Sonuç

Ollama, yerelde LLM çalıştırmayı birkaç komuta indirgeyerek hızlı prototipleme ve gizlilik odaklı üretim senaryolarını mümkün kılıyor. Doğru model boyutu ve kuantizasyon seçimiyle dizüstü bilgisayarda dahi tatmin edici Türkçe sonuçlar alabilirsiniz. GPU hızlandırması, bağlam ayarları ve API entegrasyonu ile dakikalar içinde chatbot, özetleyici veya kod asistanı geliştirmek elinizde. Küçük adımlarla başlayın, ölçümleyin ve kullanım amacınıza en uygun yapılandırmayı kademeli olarak bulun.

Passkeys (WebAuthn) ile Şifresiz Giriş: Adım Adım Uygulama Rehberi

Şifrelerle boğuşmanın sonuna gelmek üzereyiz. Passkeys, yani FIDO2/WebAuthn tabanlı şifresiz kimlik doğrulama, hem kullanıcı deneyimini iyileştiriyor hem de oltalama saldırılarına karşı çok daha güçlü bir koruma sağlıyor. Bu rehberde, modern web uygulamalarına passkey desteğini nasıl ekleyebileceğinizi, mimari gereksinimleri ve en iyi uygulamaları sade bir dille anlatıyorum.

Neden Passkeys? Klasik parolalar tahmin edilebilir, tekrar kullanılır ve sızıntılarda kolayca ele geçirilir. Passkeys ise cihaz tabanlı, kök anahtarları donanımda korunan (Secure Enclave/TPM) bir anahtar çifti yaklaşımı kullanır. Özel anahtar cihazda kalır, sunucu yalnızca herkese açık anahtarı saklar. Giriş sırasında sunucu tarafından verilen bir “challenge” imzalanır; bu sayede oltalama siteleri doğru kök bağlamı oluşturamadığı için doğrulama başarısız olur.

Passkey Nedir? Kısa Teknik Özet

Passkeys, WebAuthn API’si ve FIDO2 standartlarının bir birleşimidir. Tarayıcı (veya mobil OS), “platform authenticator” (cihaz üzerindeki biyometri/PIN) ya da “cross-platform authenticator” (USB/NFC güvenlik anahtarı) kullanarak kullanıcıyı doğrular. Uyumlu tarayıcılar: Chrome, Safari, Edge, Firefox (bazı platform kısıtları olabilir). Uyumlu işletim sistemleri: iOS/iPadOS 16+, macOS Ventura+, Android 9+, Windows 10/11 (Güncel) vb.

Mimari ve Gereksinimler

- Zorunlu HTTPS: WebAuthn yalnızca güvenli kökenlerde çalışır. Geliştirme için localhost istisnası vardır.
- Relying Party ID (rpId): Genellikle alan adınız. rpId, kök alanla eşleşmeli ve alt alanlar için doğru yapılandırılmalı.
- Sunucu tarafı saklama: Kullanıcı başına credentialId, publicKey, signCount (veya counter), userHandle gibi alanlar güvenli biçimde saklanmalı.
- Oturum yönetimi: Başarılı doğrulama sonrası session veya JWT üretin. Session sabitleme ve CSRF’ye dikkat edin.

Kayıt (Registration) Akışı

1) Sunucu challenge üretir: Kullanıcı kayıt sayfasında “Passkey oluştur” dediğinde sunucu tek kullanımlık bir challenge (rastgele bayt dizisi) üretir ve front-end’e gönderir. Yanıtınız; rp (name, id), user (id, name, displayName), pubKeyCredParams (örn. -7 ES256), authenticatorSelection (residentKey=required, userVerification=required) gibi parametreleri içermeli.

2) İstemci credential oluşturur: Tarayıcı, navigator.credentials.create({ publicKey: ... }) çağrısıyla cihazın biyometrisi/PIN’i üzerinden kullanıcıyı doğrular ve bir credential üretir. Kullanıcı rızası alınır ve işlem OS düzeyinde güvenlidir.

3) Sunucu doğrular ve kaydeder: İstemciden dönen attestation ve clientDataJSON, sunucuda doğrulanır. Güvenilir bir kütüphane ile (Node.js: @simplewebauthn/server; Java: WebAuthn4J; Python: webauthn) kontrol edebilirsiniz. Başarılıysa credentialId, publicKey ve signCount veritabanına yazılır. Attestation politikasını “none” tutarak gizliliği artırabilir veya kurumsal senaryolarda belirli üreticileri zorunlu kılabilirsiniz.

Giriş (Authentication) Akışı

1) Sunucu challenge üretir: Giriş düğmesine basıldığında sunucu yeni bir challenge üretir ve istemciye gönderir. allowCredentials ile kayıtlı credentialId’leri listeleyebilir veya “discoverable credentials” kullanıyorsanız listeyi boş bırakabilirsiniz.

2) İstemci imza oluşturur: navigator.credentials.get({ publicKey: ... }) çağrısı yapılır. Kullanıcı biyometri/PIN ile onay verir ve cihaz challenge’ı imzalar.

3) Sunucu imzayı doğrular: clientDataJSON ve authenticatorData içindeki rpIdHash, origin, flags (UP, UV), signCount ve signature doğrulanır. counter artışı kontrol edilerek tekrar oynatma (replay) engellenir. Başarılıysa oturum başlatılır.

Senkrone ve Cihaza Bağlı Passkeys

- Senkrone Passkeys: Apple, Google ve Microsoft ekosistemlerinde aynı hesabın bağlı cihazları arasında uçtan uca şifreli senkronizasyon yapılır. Kullanıcı için harika UX, ancak kurumsal ortamlarda veri politikaları gözden geçirilmeli.
- Cihaza Bağlı (Device-bound): Anahtar yalnızca oluşturulduğu cihazda bulunur. Daha sıkı güvenlik isteyen sektörlerde tercih edilir. Gerekirse ikisi bir arada desteklenebilir.

UX İpuçları ve Koşullu UI

- Koşullu UI: Chrome ve Safari, giriş formu odaklandığında otomatik passkey önerisi sunabilir. Bu, “parola yerine passkey” mesajını doğal şekilde yerleştirir.
- Adım adım benimsetme: İlk girişte kullanıcıya “Şifresiz giriş ekle (önerilir)” çağrısı yapın. Zorunlu kılmayın, alternatif bırakın.
- Geri dönüş planı: Kullanıcı cihazını kaybedebilir. E-posta/OTP veya destek kanalını yalnızca hesap kurtarma için sunun; normal girişte passkey’i önceliklendirin.
- Platform/cross-platform seçimi: Dizüstü kullanıcıları için platform authenticator yeterli olabilir; saha ekipleri için güvenlik anahtarları (USB/NFC) mantıklı.

Güvenlik ve Uyum

- Phishing direnci: rpId ve origin eşlemesi, yanlış etki alanıyla giriş yapılmasını engeller.
- Gizlilik: Attestation’ı çoğunlukla “none” tutarak cihaz damgalanmasını önleyin.
- Sertleştime: HSTS, COOP/COEP, güçlü TLS ayarları, zaman senkronizasyonu. Sunucu saat sapması doğrulamayı bozabilir.
- Uyumluluk: En güncel tarayıcı/OS sürümlerini hedefleyin. Eski cihazlar için parola + 2FA yedek planı bulundurun.

Uygulama İskeleti: Hızlı Kontrol Listesi

- Alan adınızı ve rpId’nizi netleştirin, HTTPS zorunludur.
- Veritabanında kullanıcı tablo şemasına credentialId (base64url), publicKey (COSE), signCount, createdAt, lastUsed alanlarını ekleyin.
- Kayıt ve giriş için ayrı endpoint’ler tanımlayın; her ikisi de nonce/challenge üretmeli ve kısa süreli saklamalı.
- Kütüphane seçin: Node.js için @simplewebauthn, Java için WebAuthn4J, Python için webauthn gibi olgun çözümler kullanın.
- Test: Chrome DevTools “Virtual Authenticator” ile farklı senaryoları (resident key, UV required) test edin.
- Telemetri: Başarı/başarısızlık oranlarını, tarayıcı/OS kırılımını izleyin; eğitim içerikleriyle dönüşümü artırın.

Sık Karşılaşılan Hatalar

- origin/rpId uyuşmazlığı: www ve çıplak alanı karıştırmayın; üretimde tek bir kök alan belirleyin.
- HTTP yerine HTTPS: Geliştirme dışında çalışmaz; sertifikayı doğru kurun.
- Yanlış COSE algoritması: Sunucu ve istemci aynı algoritmaları kabul etmeli (ör. ES256).
- Counter tutarsızlığı: signCount geriye düşerse cihaza güveni düşürün ve yeniden kayıt isteyin.

Özetle, passkeys hem güvenlik hem de kullanıcı deneyimi açısından önümüzdeki yılların standardı olacak. Doğru mimariyle kurguladığınızda, kullanıcılarınızın parolaları hatırlamasını istemez, oltalama riskini azaltır ve destek taleplerini düşürürsünüz. Küçük bir PoC ile başlayın, slayt yerine gerçek kullanıcı akışı tasarlayın ve dönüşüm metriklerini yakından takip edin. Bir kez oturduğunda, “Şifremi unuttum” döneminin kapandığını hissedeceksiniz.

4 Eylül 2025 Perşembe

Passkey (WebAuthn) ile Parolasız Giriş: Node.js ve SimpleWebAuthn ile Adım Adım Entegrasyon

Passkey (WebAuthn) ile Parolasız Giriş: Neden ve Nasıl?

Parolasız giriş dünyasında Passkey teknolojisi (WebAuthn/FIDO2) hızla standart hâline geliyor. Kimlik avı direnci, cihazlar arası senkronizasyon ve hızlı kullanıcı deneyimi sayesinde klasik parolaların yerini alıyor. Bu yazıda, Node.js ve @simplewebauthn kütüphanesini kullanarak bir web uygulamasına Passkey tabanlı kimlik doğrulamayı nasıl entegre edeceğinizi adım adım anlatıyorum. Rehber, modern tarayıcılar (Chrome, Safari, Edge) ve platformlar (iOS, Android, macOS, Windows) ile uyumludur.

Ön Koşullar ve Genel Mimari

Başlamadan önce Node.js 18+ sürümü, HTTPS ile çalışan bir alan adı (localhost için self-signed sertifika), temel Express.js bilgisi ve veri saklamak için bir veritabanı (ör. PostgreSQL, MongoDB veya basit bir bellek deposu) gerekli. Mimari olarak iki akış vardır: Kayıt (Registration) ve Giriş (Authentication). Kayıtta sunucu, kullanıcıya bir challenge üretir ve tarayıcı navigator.credentials.create() ile güvenli bir anahtar çifti oluşturur. Girişte ise sunucu yeni bir challenge üretir ve tarayıcı navigator.credentials.get() ile imza üretip doğrulatır.

Proje Kurulumu

mkdir passkey-demo && cd passkey-demo komutlarıyla klasörü oluşturun. Ardından npm init -y ve npm i express @simplewebauthn/server cors cookie-session komutlarını çalıştırın. Geliştirme için npm i -D typescript ts-node @types/express @types/cookie-session ekleyebilirsiniz. HTTPS için bir ters proxy ya da self-signed sertifika kullanın; WebAuthn çoğu senaryoda güvenli köken (https) ister.

Sunucu Tarafı: Temel Ayarlar

Express uygulamasında kök alan adınızı rpID olarak tanımlayın (ör. example.com). origin değeri tam protokol ve alan adını içermeli (ör. https://example.com). Kullanıcı oturumunda veya Redis gibi bir depoda challenge saklayın.

import express from 'express';
import { generateRegistrationOptions, verifyRegistrationResponse, generateAuthenticationOptions, verifyAuthenticationResponse } from '@simplewebauthn/server';
import session from 'cookie-session';

const app = express();
app.use(express.json());
app.use(session({ name: 'sess', keys: ['secret'], maxAge: 600000 }));

const rpID = 'example.com';
const origin = 'https://example.com';

Kayıt Akışı (Registration)

1) Options uç noktası: Kullanıcı kayıt olurken sunucu challenge üretir ve istemciye gönderir. Kullanıcı tanımlayıcısını (user.id) kalıcı bir değerden oluşturun.

app.post('/register/options', async (req, res) => {
  const { username, displayName } = req.body;
  const userId = 'user-' + username; // Örnek amaçlı
  const options = await generateRegistrationOptions({
    rpName: 'Passkey Demo',
    rpID,
    userID: userId,
    userName: username,
    userDisplayName: displayName || username,
    attestationType: 'none',
  });
  req.session.challenge = options.challenge;
  res.json(options);
});

2) Doğrulama uç noktası: İstemci, navigator.credentials.create() sonucunu bu uç noktaya gönderir. Sunucu doğrular, credential’ı veritabanına kaydeder.

app.post('/register/verify', async (req, res) => {
  const body = req.body; // client response
  const expectedChallenge = req.session.challenge;
  const verification = await verifyRegistrationResponse({
    response: body,
    expectedChallenge,
    expectedOrigin: origin,
    expectedRPID: rpID,
  });
  if (!verification.verified) return res.status(400).json({ ok: false });
  // credential kaydet: id, publicKey, counter, transports
  res.json({ ok: true });
});

Giriş Akışı (Authentication)

1) Options uç noktası: Sunucu, kullanıcıya bağlı mevcut credential’lara göre allowCredentials ile bir challenge üretir.

app.post('/login/options', async (req, res) => {
  const { username } = req.body;
  const userCreds = await loadUserCredentials(username); // DB'den çekin
  const options = await generateAuthenticationOptions({
    rpID,
    allowCredentials: userCreds.map(c => ({ id: c.id, type: 'public-key' })),
  });
  req.session.challenge = options.challenge;
  res.json(options);
});

2) Doğrulama uç noktası: İstemciden gelen imzayı doğrulayın, sayaç değerini güncelleyin ve oturumu başlatın.

app.post('/login/verify', async (req, res) => {
  const body = req.body;
  const expectedChallenge = req.session.challenge;
  const user = await findUserByCredentialId(body.rawId);
  const verification = await verifyAuthenticationResponse({
    response: body,
    expectedChallenge,
    expectedOrigin: origin,
    expectedRPID: rpID,
    authenticator: user.authenticator, // publicKey & counter
  });
  if (!verification.verified) return res.status(401).json({ ok: false });
  // counter güncelle, session başlat
  res.json({ ok: true });
});

İstemci Tarafı: WebAuthn API Kullanımı

Kayıt sırasında sunucudan aldığınız PublicKeyCredentialCreationOptions nesnesini navigator.credentials.create() içine verin. Tarayıcı, platform anahtarı (ör. iCloud Anahtar Zinciri, Google Password Manager) veya güvenlik anahtarı (YubiKey) ile cihaz üzerinde anahtar üretir.

const opts = await fetch('/register/options', { method: 'POST', body: JSON.stringify({ username }) }).then(r => r.json());
const cred = await navigator.credentials.create({ publicKey: opts });
await fetch('/register/verify', { method: 'POST', body: toJSON(cred) });

Girişte navigator.credentials.get() çağrısı yapılır. Sunucunun sağladığı PublicKeyCredentialRequestOptions ile imza üretilir ve doğrulama uç noktasına gönderilir.

const opts = await fetch('/login/options', { method: 'POST', body: JSON.stringify({ username }) }).then(r => r.json());
const assertion = await navigator.credentials.get({ publicKey: opts });
await fetch('/login/verify', { method: 'POST', body: toJSON(assertion) });

Test, Hata Ayıklama ve Uyumluluk

Geliştirmede https zorunludur; aksi takdirde tarayıcı çağrıları reddedebilir. Mobil cihazlarda test için aynı ağda çalışan https bir endpoint kullanın veya tünelleme (ngrok, Cloudflare Tunnel) tercih edin. Safari’de rpID uyumsuzluğu sık görülür; alan adınız ile origin’iniz birebir eşleşsin. Hata mesajlarını ayrıntılarıyla log’layın; özellikle challenge uyuşmazlığı, origin hatası ve RP ID hataları en yaygın sorunlardır.

Güvenlik ve UX İpuçları

- Challenge değerlerini tek kullanımlık ve kısa ömürlü saklayın; oturum veya Redis idealdir.

- Kullanıcı başına birden fazla credential kaydına izin verin; cihaz değişimlerinde deneyimi iyileştirir.

- resident key ve user verification politikalarını ihtiyaca göre ayarlayın; güçlü güvenlik için required tercih edin.

- Geriye dönük uyumluluk için geçici olarak sihirli bağlantı (magic link) veya tek kullanımlık kodları sunabilirsiniz.

- Üretimde anahtar materyalini ve sayaç değerlerini güvenilir bir veritabanında şifreli saklayın; yedeklemeleri planlayın.

Sonuç

Passkey (WebAuthn/FIDO2) ile parolasız giriş, hem güvenliği hem de kullanıcı deneyimini ileriye taşır. Node.js ve @simplewebauthn ile kurulum birkaç uç nokta ve doğru yapılandırma ile tamamlanabilir. Doğru rpID/origin eşleşmesi, güvenli challenge yönetimi ve çoklu credential desteği ile modern, kimlik avına dayanıklı ve hızlı bir giriş akışı elde edersiniz. Ürününüz büyüdükçe; cihaz senkronizasyonu, kurtarma stratejileri ve kurumsal güvenlik anahtarları ile çözümü olgunlaştırabilirsiniz.

3 Eylül 2025 Çarşamba

Tarayıcıda WebGPU ile ONNX Runtime Web Kullanarak YOLOv8 Nesne Tanıma: Adım Adım Kurulum ve Performans İpuçları

Giriş

Tarayıcıda çalışan yapay zeka uygulamaları artık sadece demolarla sınırlı değil. WebGPU ve ONNX Runtime Web sayesinde, YOLOv8 gibi modern nesne tanıma modellerini doğrudan kullanıcıların cihazlarında, sunucuya ihtiyaç duymadan ve düşük gecikmeyle çalıştırmak mümkün hale geldi. Bu yazıda, YOLOv8 modelini ONNX formatına dönüştürüp WebGPU yürütücüsüyle tarayıcıda nasıl çalıştırabileceğinizi, performans odaklı pratik ipuçlarıyla adım adım anlatıyorum.

Neden WebGPU + ONNX Runtime Web?

WebGPU, modern GPU mimarilerine daha yakın bir API sunduğu için WebGL/Canvas tabanlı yaklaşımlara göre çok daha yüksek paralellik ve verimlilik sağlar. ONNX Runtime Web ise modelleri tarayıcıda WebGPU ya da WASM yürütücüleri ile çalıştırır. Bu ikili; hız, taşınabilirlik ve gizlilik avantajlarını aynı anda sunar: veriler tarayıcıdan çıkmaz, gecikme düşer, CDN üzerinden servis edilen statik dosyalarla ölçeklenebilir bir dağıtım sağlanır.

Ön Koşullar

Güncel bir Chromium tabanlı tarayıcı (Chrome/Edge 121+), WebGPU desteği açık bir ortam (HTTPS zorunlu), Node.js 18+ ve temel TypeScript/JavaScript bilgisi yeterli. Geliştirme için Vite ile hafif bir proje yapısı kuracağız.

Modeli Hazırlama (YOLOv8 → ONNX)

Ultralytics YOLOv8 modelini ONNX’e aktarmak için Python tarafında şu adımı izleyebilirsiniz: pip install ultralytics komutuyla paketi kurun ve ardından yolo export model=yolov8n.pt format=onnx opset=12 imgsz=640 komutunu çalıştırın. Bu işlem sonunda yolov8n.onnx dosyasını elde edersiniz. Alternatif olarak resmi depolardan hazır ONNX sürümlerini indirebilir ve doğrudan statik olarak sunabilirsiniz.

Projeyi Kurma (Vite + TypeScript)

Yeni bir proje başlatmak için şu komutu çalıştırın: npm create vite@latest onnx-webgpu -- --template vanilla-ts. Proje klasörüne geçip npm i onnxruntime-web komutuyla ONNX Runtime Web’i ekleyin. Modeli ve etiket dosyalarını public/models klasörüne kopyalayın. Geliştirme sunucusunu başlatmak için npm run dev yeterli olacaktır.

WebGPU Yürütücü ile İnferans

Tarayıcı tarafında WebGPU yürütücüsünü etkinleştirmek için modülü içeri aktarın: import 'onnxruntime-web/webgpu' ve ardından import { InferenceSession, Tensor } from 'onnxruntime-web'. Oturum oluştururken yürütücüyü belirtebilirsiniz: const session = await InferenceSession.create('/models/yolov8n.onnx', { executionProviders: ['webgpu'], graphOptimizationLevel: 'all' }). Eğer cihazda WebGPU uygun değilse bir yakalama bloğunda ['wasm'] ile geriye dönük destek sunmak mümkündür.

Görüntüyü tensöre dönüştürmek için bir <canvas> referansı yeterli. Görüntünün 640x640 boyutuna mektup kutusu (letterbox) ile ölçeklenmesi, ardından piksel verisinin Float32 tensöre [1, 3, H, W] düzeninde (RGB, kanal-öncelikli) aktarılması gerekir. Normalizasyon için genellikle 0–1 aralığı ve gerekiyorsa modelin beklediği ortalama/sapma değerleri kullanılır. Örnek akış: görüntüyü canvas’a çiz, getImageData ile veriyi al, Float32Array’e yaz ve new Tensor('float32', data, [1,3,640,640]) oluştur. Ardından await session.run({ images: inputTensor }) ile çıktıları alabilirsiniz.

YOLOv8 ONNX çıkışında genellikle [1, N, 84] benzeri bir matris döner (ilk 4 değer kutu, takip eden skorlar/sınıflar). Sonuçları yorumlarken skor eşiğini (örneğin 0.25) ve IoU tabanlı NMS adımını uygulayın. Basit bir döngü ile her satırı okuyup en yüksek sınıf skorunu, kutu koordinatlarını ölçekleyerek orijinal görüntü boyutuna geri projekte edebilirsiniz.

Performans ve Optimizasyon İpuçları

Isınma (warm-up): Uygulama açılışında bir kez sahte bir tensörle session.run yaparak JIT derleme/önbellek süreçlerini tetikleyin. Bu, ilk gerçek karedeki gecikmeyi ciddi ölçüde azaltır.

WASM geri dönüşü: WebGPU desteklenmeyen cihazlarda otomatik olarak WASM’a düşmek kullanıcı kapsamını artırır. executionProviders: ['webgpu', 'wasm'] sıralaması pratik bir stratejidir.

Kantizasyon ve hafif modeller: INT8 kantize edilmiş ONNX modelleri bellek ve bant genişliği tüketimini düşürür. Eğer doğruluk kabul edilebilir seviyede kalıyorsa yolov8n veya yolov8s gibi küçük türevleri tercih edin.

Web Worker / OffscreenCanvas: Ön işleme ve NMS’i Web Worker’a taşıyarak ana iş parçacığını serbest bırakabilir, kare atlamalarını azaltabilirsiniz. Destek varsa OffscreenCanvas ile piksel işlemlerini işçi tarafında yapın.

Toplu işleme ve kadans kontrolü: Canlı kamera akışında her kareyi çalıştırmak yerine zamanlayıcıyla kadansı sınırlayın (ör. 30 FPS yerine 15 FPS). Sabit görüntü yükleme senaryolarında, aynı anda birden fazla resmi işlemek yerine küçük partiler halinde ilerleyin.

Bellek yönetimi: Tekrar kullanılan tensör ve arabellekleri yeniden oluşturmak yerine mümkün olduğunca yeniden kullanın. Büyük Float32Array tahsislerinden kaçınmak çöp toplayıcı baskısını azaltır.

Sık Karşılaşılan Hatalar ve Çözümler

GPUUnavailableError: Tarayıcıda chrome://flags altında WebGPU kapalı olabilir veya sayfa HTTPS üzerinden servis edilmiyor olabilir. Yerel geliştirme için localhost genellikle güvenilir sayılır.

Model uyumsuzluğu: ONNX opset sürümü çok düşük/yüksek olduğunda düğümler çözümlenmeyebilir. Çoğu güncel senaryoda opset 12–13+ güvenlidir; export sırasında opseti açıkça belirtin.

Çapraz kaynak sorunları: Model dosyaları farklı bir origin’den yükleniyorsa CORS başlıklarını doğru ayarlayın. Üretimde model ve varlıkları aynı domain/CDN kökünden sunmak en pratik yoldur.

Sonuç

WebGPU ve ONNX Runtime Web ile YOLOv8’i tarayıcıda çalıştırmak, gerçek zamanlı nesne tanımayı istemci tarafında güvenli ve hızlı bir şekilde sunmanıza olanak verir. Doğru ön işleme, hafif model seçimi ve ısınma/optimizasyon teknikleri ile orta seviye cihazlarda bile akıcı deneyim elde edebilirsiniz. Bu yaklaşım; gizlilik, ölçeklenebilirlik ve kullanıcı deneyimi açısından modern web uygulamalarına güçlü bir kapı aralıyor. Birkaç küçük adımla siz de modelinizi WebGPU üzerinde hayata geçirebilirsiniz.

2 Eylül 2025 Salı

Yerelde RAG Kurulumu: Ollama ve FAISS ile Belgelerinizden Akıllı Arama

RAG nedir, neden yerel çalıştırmalıyım?

Büyük dil modelleri etkileyici cevaplar üretebiliyor ancak kaynaklara dayanmayan “halüsinasyon” üretme eğilimleri var. Retrieval-Augmented Generation (RAG), modelin yanıtlarını gerçek belgelerinizden çekilen parçalarla destekleyerek bu sorunu azaltır. Yerel RAG, tüm süreci bilgisayarınızda çalıştırarak gizlilik, düşük gecikme ve maliyet avantajı sağlar. Bu yazıda Ollama + FAISS ikilisiyle, PDF’leriniz, notlarınız veya wiki sayfalarınız üzerinde çalışan pratik bir yerel RAG kurulumunun yolunu göstereceğim.

Mimari bileşenler

1) LLM (Yanıtlayıcı): Yerelde çalıştırmak için Ollama üzerinden Llama 3, Mistral veya benzeri açık modellerden birini seçebilirsiniz. Kuantize edilmiş sürümler (ör. Q4_K_M) düşük donanımda bile kabul edilebilir hız sunar.

2) Vektörleştirici (Embedding): Metni sabit boyutlu vektörlere dönüştürür. Türkçe desteği güçlü olan bge veya e5 tabanlı modeller iyi sonuç verir. Embedding modeli LLM’den ayrı olabilir; bu esneklik performansı artırır.

3) Vektör Veritabanı (FAISS): Belgelerinizin vektörlerini indeksleyip en benzer parçaları hızla getirir. FAISS hafif, açık kaynak ve yerel kurulum için idealdir.

4) Orkestrasyon: Basit bir RAG için ek çerçeve şart değil. Sıra; sorguyu vektörleştir, FAISS’ten en yakın doküman parçalarını getir, bu parçaları bağlam olarak LLM’e ver ve yanıtı oluştur şeklinde ilerler. İsterseniz LangChain veya LlamaIndex kullanabilirsiniz; ancak bu yazı minimal ve anlaşılır yaklaşımı tercih ediyor.

Adım adım kurulum

Önkoşullar: 8–16 GB RAM, modern bir CPU yeterli. GPU varsa daha hızlı olur. İşletim sistemi olarak macOS, Windows (WSL dahil) veya Linux uygundur.

1) Ollama’yı kurun: Ollama resmi sitesinden sisteminize uygun kurulum paketini indirin ve kurun. Terminalde “ollama run llama3” gibi bir komutla modeli test edebilirsiniz. İlk çalıştırmada model indirilecektir.

2) Embedding modelini hazırlayın: Python ortamı kurup sentence-transformers gibi bir kütüphane ile bge veya e5 tabanlı çok dilli bir modeli indirin. Türkçe metinler için bu aileler genellikle dengeli sonuç verir. Üretimde aynı tokenizer ve model sürümünü koruyarak tutarlılık sağlayın.

3) Belgeleri içe aktarın ve parçalara bölün: PDF, Markdown veya HTML kaynaklarınızı metne dönüştürün. Chunking stratejinizi belirleyin: 400–800 kelime aralığı ve %10–20 örtüşme (overlap) çoğu senaryo için iyi bir başlangıçtır. Başlık, bölüm, sayfa numarası gibi meta verileri saklamayı unutmayın.

4) FAISS ile indeks oluşturun: Her parçayı embedding modele verip vektörünü alın ve FAISS’e ekleyin. Büyük veri için IVF+PQ gibi yapılandırmalar disk ve bellek kullanımını dengeler. Küçük veri setlerinde düz L2 veya kosinüs benzerliği yeterli olur.

5) Sorgu akışı: Kullanıcı sorusunu embedding’e çevirin, FAISS’ten top-k (ör. k=5) en yakın parçayı çekin. Bu parçaları bir “bağlam” şablonunda birleştirip Ollama’ya aktarın. Prompt içinde “Sadece aşağıdaki bağlamdan yararlan” gibi net yönergeler verin. Yanıtı kaynak bağlantılarıyla birlikte sunmak güven yaratır.

6) Hafif bir API ekleyin: FastAPI gibi bir çerçeveyle tek uç noktalı bir servis hazırlayabilirsiniz. İstek geldiğinde sorguyu vektörleştirir, FAISS’ten bağlamı getirir, Ollama’ya iletir ve akışlı yanıtı geri döndürür. Böylece masaüstü, web veya mobil istemciler kolayca entegre olur.

7) Değerlendirme ve iyileştirme: Kaliteyi ölçmek için sık sorulan 20–30 soruluk bir test seti hazırlayın. Cevap doğruluğu, kaynak kapsama (coverage) ve ilk token gecikmesi gibi metrikleri izleyin. Top-k, chunk boyutu, MMR (çeşitlilik odaklı getirme) ve sıcaklık (temperature) ayarlarını kademeli değiştirerek A/B testleri yapın.

Performans ve pratik ipuçları

Kuantizasyon: LLM’i Q4 seviyesinde çalıştırmak performans/kalite dengesini iyileştirir. CPU’da dahi kabul edilebilir yanıt hızları elde edilir.

Prompt mühendisliği: Türkçe bağlam sağladığınızda, talimatları da Türkçe verin. “Kaynaklardan alıntı yap, emin değilsen belirt” gibi yönlendirmeler halüsinasyonu azaltır.

Önbellekleme: Sık soruların embedding ve arama sonuçlarını disk üzerinde önbelleğe alın. Bu, hem gecikmeyi hem de CPU yükünü düşürür.

Filtreler: FAISS yanında meta veri filtreleri tutarak tarih, yazar, kategori gibi sınırlamalarla daha doğru sonuçlar alabilirsiniz.

Türkçe desteği: Embedding modelinin Türkçe kapsaması kritiktir. İlk denemelerde Türkçe/multilingual modelleri karşılaştırın; bazen küçük ama iyi eğitilmiş bir embedding modeli büyük bir fark yaratır.

Gizlilik, güvenlik ve bakım

Yerel RAG’in en büyük artısı, belgelerinizin makine dışına çıkmamasıdır. Yine de PII içeren veri setlerini şifreli depolamak, cihazınızda tam disk şifreleme kullanmak ve indeks dosyalarına erişimi kısıtlamak önemlidir. Modelleri ve bağımlılıkları düzenli güncelleyin; embedding modelini değiştirdiğinizde indeksinizi yeniden oluşturmanız gerektiğini unutmayın.

Sorun giderme

İndeks tutarsızlığı: Farklı embedding model veya sürüm değişikliği, alakasız sonuçlar doğurur. Tek sürüm standardı belirleyin.

Dil karışması: Çok dilli veri setlerinde karışık diller zayıf eşleşmeye yol açabilir. Belgeleri dil bazında ayrı indekslemek kaliteyi yükseltir.

Kaynak tüketimi: RAM yetmiyorsa daha agresif chunking veya IVF+PQ yapılandırmasına geçin. LLM tarafında daha küçük bir model deneyin.

Sonuç

Ollama ve FAISS ile kurulan yerel RAG, gizliliğe duyarlı ortamlarda hızlı ve güvenilir bir bilgi erişim katmanı sunar. Doğru embedding seçimi, iyi bir chunking stratejisi ve disiplinli değerlendirmeyle; şirket içi dokümantasyondan akademik arşivlere kadar pek çok kullanım senaryosunda arama ve soru-cevap kalitesini belirgin biçimde artırabilirsiniz. Küçük adımlarla başlayın, metriklerle ölçün ve yapı taşlarını gerektikçe büyütün; kısa sürede günlük iş akışınızda fark yaratacaktır.