Vektör Veritabanı etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Vektör Veritabanı etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

4 Şubat 2026 Çarşamba

Docker Compose ile Yerel Bir RAG (Retrieval-Augmented Generation) Ortamı Kurulumu: PostgreSQL + pgvector + API Katmanı

RAG Nedir ve Neden Yerelde Kurulur?

RAG (Retrieval-Augmented Generation), bir dil modelinin cevabı “uydurmak” yerine önce güvenilir bir kaynaktan ilgili içerikleri bulup (retrieval), ardından bu içeriklerle zenginleştirilmiş bir yanıt üretmesi yaklaşımıdır. Son dönemde kurum içi dokümanlarla çalışan asistanlar, teknik arama kutuları ve destek botları RAG ile daha tutarlı sonuçlar verebiliyor. Yerel (local) kurulum ise hem gizlilik hem de maliyet açısından önemli: veriniz üçüncü taraf servislere gitmez, altyapı kontrolü sizde olur ve test/deneme döngüsü hızlanır.

Bu yazıda Docker Compose kullanarak güncel ve pratik bir RAG altyapısının çekirdeğini kuracağız: PostgreSQL üzerinde pgvector eklentisi ile vektör arama, ve bu veritabanına bağlanan örnek bir API katmanı. Amaç; doküman parçalarını (chunk) vektör olarak saklamak, benzerlik araması yapmak ve uygulamalar için tekrar kullanılabilir bir iskelet oluşturmaktır.

Mimari: Hangi Parçalar Var?

Kurulum üç ana parçadan oluşur: (1) PostgreSQL + pgvector: embedding’leri saklar ve benzerlik araması yapar. (2) API: doküman ekleme ve arama uçlarını sunar. (3) İsterseniz ileride LLM entegrasyonu: burada odak veritabanı ve retrieval tarafı olduğu için LLM kısmını opsiyonel bırakıyoruz. Bu iskelet, ister kendi LLM’inizle ister bir harici model API’si ile kolayca genişletilebilir.

Ön Koşullar

Bilgisayarınızda Docker ve Docker Compose kurulu olmalı. Windows’ta Docker Desktop, macOS’ta Docker Desktop, Linux’ta Docker Engine + Compose eklentisi yeterlidir. Ayrıca komut satırı kullanımı ve temel PostgreSQL kavramlarına aşinalık işinizi kolaylaştırır.

1) Docker Compose Dosyasını Hazırlama

Projeniz için bir klasör açın (ör. rag-local) ve içine docker-compose.yml dosyası oluşturun. Aşağıdaki yapı PostgreSQL’i pgvector etkin şekilde başlatır ve örnek bir API servisini ayağa kaldırır. API tarafını kendi projenize göre değiştirebilirsiniz; burada amaç, servislerin bir arada çalıştığı “omurga”yı kurmak.

docker-compose.yml içeriği:

Not: Aşağıdaki bloğu olduğu gibi ekleyebilirsiniz.

YAML:

version: "3.9"
services:
  db:
    image: pgvector/pgvector:pg16
    container_name: rag_db
    environment:
      POSTGRES_USER: rag
      POSTGRES_PASSWORD: ragpass
      POSTGRES_DB: ragdb
    ports:
      - "5432:5432"
    volumes:
      - rag_pgdata:/var/lib/postgresql/data
  api:
    image: node:20-alpine
    container_name: rag_api
    working_dir: /app
    volumes:
      - ./api:/app
    environment:
      DATABASE_URL: postgres://rag:ragpass@db:5432/ragdb
    command: sh -c "npm i && npm run dev"
    depends_on:
      - db
    ports:
      - "3000:3000"
volumes:
  rag_pgdata:

Burada kritik kısım, veritabanı imajının pgvector destekli olmasıdır. Böylece ayrı bir eklenti kurma süreciyle uğraşmadan vektör tiplerini ve indeksleri kullanabilirsiniz. API servisi için Node.js seçtik; ancak aynı yaklaşımı Python/FastAPI ya da Go ile de uygulayabilirsiniz.

2) Veritabanında Tablo ve İndeks Oluşturma

Şimdi PostgreSQL tarafında pgvector’ı etkinleştirelim ve RAG için temel bir tablo kuralım. Terminalden Compose’u başlatın:

Komut: docker compose up -d

Ardından veritabanı kabuğuna girip SQL çalıştırın:

Komut: docker exec -it rag_db psql -U rag -d ragdb

SQL adımları:

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE IF NOT EXISTS documents (
  id BIGSERIAL PRIMARY KEY,
  source TEXT NOT NULL,
  chunk TEXT NOT NULL,
  embedding vector(768),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Benzerlik araması için ivfflat indeks (embedding dolduktan sonra daha verimli olur)
CREATE INDEX IF NOT EXISTS documents_embedding_idx
ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

Burada vector(768) boyutu örnek bir değerdir. Kullandığınız embedding modeline göre 384, 768, 1024 gibi farklı boyutlar seçebilirsiniz. Boyut ile model çıktısı tutarlı olmak zorunda; aksi halde insert sırasında hata alırsınız.

3) API Katmanını Hızlıca Ayağa Kaldırma

Proje kökünde api adlı klasör oluşturun. İçine basit bir Node.js API koyarak iki uç hazırlayacağız: /ingest (doküman ekleme) ve /search (benzerlik araması). Örnek olması açısından sade tutuldu; prod ortamda doğrulama, rate limit, kuyruk (queue) ve gözlemlenebilirlik eklemek gerekir.

api/package.json:

{
  "name": "rag-api",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "node index.js"
  },
  "dependencies": {
    "express": "^4.19.2",
    "pg": "^8.12.0"
  }
}

api/index.js:

import express from "express";
import pg from "pg";

const app = express();
app.use(express.json({ limit: "2mb" }));

const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });

// ingest: { source, chunk, embedding: [..] }
app.post("/ingest", async (req, res) => {
  const { source, chunk, embedding } = req.body;
  if (!source || !chunk || !Array.isArray(embedding)) {
    return res.status(400).json({ error: "source, chunk ve embedding (array) zorunlu" });
  }
  const emb = `[${embedding.join(",")}]`;
  await pool.query(
    "INSERT INTO documents(source, chunk, embedding) VALUES ($1, $2, $3::vector)",
    [source, chunk, emb]
  );
  res.json({ ok: true });
});

// search: { embedding: [..], topK: 5 }
app.post("/search", async (req, res) => {
  const { embedding, topK = 5 } = req.body;
  if (!Array.isArray(embedding)) {
    return res.status(400).json({ error: "embedding (array) zorunlu" });
  }
  const emb = `[${embedding.join(",")}]`;
  const { rows } = await pool.query(
    `SELECT id, source, chunk,
      1 - (embedding <=> $1::vector) AS score
      FROM documents
      ORDER BY embedding <=> $1::vector
      LIMIT $2`,
    [emb, topK]
  );
  res.json({ results: rows });
});

app.listen(3000, () => console.log("RAG API 3000 portunda çalışıyor"));

Bu API, embedding üretmez; embedding’i dışarıdan bekler. Böylece hangi embedding modelini kullanacağınızı (yerel bir model, bir CLI aracı veya bir bulut servisi) siz belirlersiniz. RAG projelerinde bu ayrım pratik bir avantaj sağlar: depolama/arama altyapısı sabit kalırken model katmanı kolay değişir.

4) Test: Veri Ekleme ve Arama

Servisler ayaktayken basit bir test yapabilirsiniz. Örnek olarak 768 boyut yerine kısa bir vektörle test etmek istiyorsanız tablo boyutunu da ona göre ayarlamanız gerekir. Gerçek kullanımda modelin ürettiği boyutla aynı vektörü göndermelisiniz. Uygulamada tipik akış şudur: (1) dokümanı parçalara böl, (2) her parça için embedding üret, (3) /ingest ile kaydet, (4) kullanıcı sorusu için embedding üret, (5) /search ile en alakalı parçaları çek, (6) bu parçaları LLM’e bağlam olarak ver.

Benzerlik metriklerinde en sık kullanılan seçenekler cosine ve L2’dir. Burada vector_cosine_ops ve <=> operatörü ile cosine mesafesine dayalı sıralama yapıyoruz. Sonuçtaki score alanı basit bir dönüştürme ile “yakınlık” hissi verir; uygulamanızda eşik (threshold) tanımlayarak düşük skorlu sonuçları elemek iyi bir pratik olabilir.

Performans ve Üretim Notları

Yerel RAG ortamı hızlı sonuç verir ama birkaç noktaya dikkat etmek gerekir. ivfflat indeks, veri büyüdükçe anlamlı hale gelir; küçük veri setlerinde tam tarama bazen daha tutarlı sonuç verebilir. Ayrıca ivfflat için ANALYZE çalıştırmak ve “lists” parametresini veri boyutuna göre ayarlamak önemlidir. Daha ileri seviyede hnsw gibi indeks türlerini ve PostgreSQL ayarlarını (work_mem, maintenance_work_mem) incelemek performansı ciddi şekilde artırabilir.

Güvenlik tarafında ise API’ye kimlik doğrulama eklemek, veritabanı şifresini .env dosyasına almak, ağ izolasyonu yapmak ve logları izlemek temel gereksinimlerdir. Bu iskeleti kendi projelerinize uyarlarken en büyük kazanım, retrieval katmanını standardize etmeniz olur; çünkü RAG projelerinde asıl fark genellikle doğru chunking, iyi embedding seçimi ve doğru indeks/parametre kombinasyonunda ortaya çıkar.

29 Ocak 2026 Perşembe

Claude 3, GPT-4o ve Llama 3 ile RAG (Retrieval-Augmented Generation) Kurulumu: Üretim Odaklı Adım Adım Rehber

RAG Nedir ve Neden 2026’da Hâlâ En İyi Yaklaşımlardan Biri?

Büyük dil modelleri (LLM) tek başına güçlü olsa da, her zaman güncel veriye erişemez ve kurumsal dokümanlarınız gibi özel içerikleri “doğrudan” bilemez. RAG (Retrieval-Augmented Generation), modeli harici bir bilgi kaynağıyla besleyerek bu açığı kapatır: Önce doğru doküman parçaları (chunk) aranır, sonra bu parçalar modele bağlam olarak verilerek yanıt ürettirilir. Böylece halüsinasyon riski düşer, cevaplar kaynaklı ve izlenebilir hâle gelir, ayrıca model güncellemeden veri güncellenebilir.

Bu yazıda, ileri seviye ama uygulanabilir bir RAG mimarisini ele alacağız: parça stratejisi, embedding seçimi, vektör veritabanı, filtreleme, yeniden sıralama (reranking) ve üretim tarafında prompt tasarımı. Hedefimiz “demo” değil, üretim ortamına yakın bir kurulum mantığı vermek.

Mimari Genel Bakış: 5 Katmanlı RAG

Sağlam bir RAG sistemi genellikle 5 bileşenden oluşur: (1) Veri hazırlama (temizleme, bölümleme), (2) Embedding (vektörleştirme), (3) Vektör indeks (arama), (4) Yeniden sıralama (en alakalı parçaları seçme), (5) Üretim (LLM ile yanıt oluşturma). Bu yapı, “LLM’ye her şeyi verelim” yaklaşımından daha az maliyetli ve daha tutarlıdır.

1) Veri Hazırlama: Chunk Stratejisi ve Metadata

RAG kalitesi, çoğu zaman modelden önce chunk stratejinizle belirlenir. PDF’lerden, wiki sayfalarından veya ticket kayıtlarından gelen içerik düzensiz olabilir. Pratikte iyi çalışan yaklaşım: 500–900 token arası chunk boyutu ve 70–150 token overlap kullanmaktır. Çok küçük chunk, bağlamı parçalar; çok büyük chunk ise arama isabetini düşürür.

Her chunk’a mutlaka metadata ekleyin: kaynak doküman adı, URL (dahili olabilir), bölüm başlığı, tarih, erişim yetkisi, ürün/servis etiketi gibi alanlar. Üretimde asıl farkı yaratan kısım burasıdır; çünkü sonradan “sadece X ürününe ait, son 6 ayın dokümanlarını tara” gibi filtreleri metadata ile yaparsınız.

2) Embedding Seçimi: Doğru Vektör Doğru Sonuç

Embedding modeli, metni sayısal vektöre dönüştürür ve benzerlik aramasının temelini oluşturur. Türkçe içerikte embedding kalitesi kritiktir. Seçerken şu kriterlere bakın: çok dilli başarı, uzun metin performansı, maliyet ve gecikme. Kurumsal senaryoda aynı anda hem İngilizce hem Türkçe doküman varsa, çok dilli embedding genellikle daha güvenli tercihtir.

Ek bir ipucu: Embedding üretirken metni “ham” basmak yerine, başlık + bölüm + içerik şeklinde birleştirmek arama isabetini artırır. Örneğin: “Başlık: … | Bölüm: … | Metin: …” gibi küçük bir şablon, özellikle benzer kavramların çok geçtiği dokümanlarda yardımcı olur.

3) Vektör Veritabanı ve İndeks Ayarları

Vektör veritabanı seçiminde popüler seçenekler arasında FAISS (self-host), Milvus, Qdrant, Weaviate ve bulut tabanlı servisler bulunur. Üretimde dikkat edilmesi gerekenler: HNSW gibi indeks türleri, filtreli arama performansı, replikasyon/backup ve erişim kontrolüdür.

HNSW tabanlı aramada temel ayar mantığı şöyledir: daha yüksek doğruluk için arama parametreleri yükselir ama gecikme artar. Bu yüzden arama katmanını iki fazlı düşünmek iyi çalışır: önce hızlı bir aday havuzu (ör. top-50) çıkarın, sonra daha pahalı bir reranking ile top-5/top-8’e düşürün.

4) Reranking: “En Yakın” Parça Her Zaman “En Alakalı” Değildir

Embedding benzerliği, semantik yakınlığı yakalar ama her zaman kullanıcı sorusuna en alakalı parçayı seçmeyebilir. Özellikle teknik dokümanlarda aynı terimler farklı bağlamlarda geçebilir. Burada reranker devreye girer: Soru ile aday chunk’ları daha “dikkatli” karşılaştırıp yeniden sıralar.

Üretimde yaygın ve etkili bir desen: top-50 vektör araması → top-10 rerank → top-4 bağlam. Reranking maliyetli olabilir; bu yüzden sadece gerekli olduğunda açmak için basit bir eşik kullanabilirsiniz (örneğin, en iyi sonucun benzerlik skoru düşükse rerank uygula).

5) Üretim (LLM) Katmanı: Prompt Tasarımı ve Kaynak Gösterme

RAG’in “G” kısmı, yani generation tarafı, çoğu zaman yanlış anlaşılır: LLM’den mucize beklemek yerine ona disiplin kazandırmak gerekir. İyi çalışan prompt ilkeleri: (1) Modeli sadece verilen bağlamla cevap vermeye zorlamak, (2) Yetersiz bağlam varsa “bilmiyorum” demesini istemek, (3) Cevabı madde madde ve adım adım ürettirmek, (4) Mümkünse kaynak chunk referansı döndürmek.

Kısa bir örnek yönerge mantığı: “Aşağıdaki bağlam parçalarını kullan. Bağlam dışında tahmin yürütme. Yanıtın sonunda ‘Kullanılan Kaynaklar’ altında parça kimliklerini yaz.” Bu yaklaşım, özellikle denetim ve uyumluluk isteyen ekiplerde RAG’i güvenilir kılar.

Kalite Ölçümü: RAG’i “Hissetmek” Yerine Test Etmek

RAG sistemleri, “birkaç soru sorup iyi gibi” diyerek üretime alınmamalı. Basit ama etkili bir yöntem: 30–100 adet gerçek kullanıcı sorusunu toplayın, her soru için “beklenen kaynak doküman” düşünün ve şu metrikleri izleyin: retrieval recall (doğru kaynak top-k içinde mi), answer faithfulness (cevap bağlamla tutarlı mı), latency (uçtan uca gecikme) ve maliyet. Bu ölçümlerle chunk boyutu, top-k, reranking aç/kapa ve prompt ayarlarını kontrollü biçimde optimize edebilirsiniz.

Üretim İçin Pratik İpuçları (Sık Yapılan Hatalar)

1) Yetkilendirme yok sayılmasın: Kullanıcının görmemesi gereken dokümanı retrieval katmanında filtrelemezseniz, LLM yanlışlıkla sızdırabilir. Metadata’ya erişim seviyeleri ekleyin ve arama sorgusuna mutlaka uygulayın.

2) “Tek indeks her şeye yeter” yanılgısı: Destek kayıtları, teknik kılavuzlar ve release notları aynı dilde olsa bile farklı karakterdedir. Bazen iki ayrı koleksiyon/indeks, tek dev koleksiyondan daha iyi sonuç verir.

3) Güncelleme akışı planlayın: Dokümanlar değiştikçe embedding’lerin güncellenmesi gerekir. En azından günlük incremental indeksleme ve silinen içerik için “tombstone” mantığı kurun.

4) Caching kullanın: Sık sorulan sorular ve popüler retrieval sonuçları için cache, maliyeti ciddi düşürür. Ayrıca aynı sorunun farklı yazımları için basit bir normalizasyon (küçük harf, noktalama temizliği) bile kazanç sağlar.

Sonuç: RAG’i Bir “Özellik” Değil, Bir Sistem Olarak Kurun

RAG, doğru kurgulandığında LLM’leri kurumsal bilgiyle güvenli şekilde birleştirmenin en pratik yoludur. Başarı; modelden çok, chunk stratejisi, metadata disiplini, filtreleme, reranking ve ölçüm altyapısının birlikte çalışmasına bağlıdır. Bu yazıdaki adımları temel alıp kendi verinize göre ayarladığınızda, hem daha doğru yanıtlar alır hem de maliyeti ve gecikmeyi kontrol edebilirsiniz.