Skip to content

FurkanSay/kai-tr-embedding-eval

Repository files navigation

kai-tr-embedding-eval

Türkçe RAG için embedding modeli karşılaştırma harness'i.

Tek bir soruya deneysel cevap arar: ana platformda (enterprise-ai-assistant) hangi embedding modeline geçmeliyiz? Mevcut prod modeli (fastembed BGE-Base 768d) ile yeni adaylar (bge-m3, Qwen3-Embedding) kendi Türkçe corpus'umuz üzerinde recall / MRR / NDCG ile kıyaslanır. "Qwen3 global MMTEB lideri" demek yeterli değil — karar körlemesine değil, bizim verimizdeki ölçümle verilir.

Bu repo bilinçli olarak ana repo'dan ayrıdır. Ana repo'da kararın gerekçesi olarak sadece buraya bir link bırakılır; eval gürültüsü PR akışına girmez.


Neden ayrı bir eval? — 2.0 re-index kuralı

Embedding modeli değiştirmek ucuz bir konfig değişikliği değildir:

2.0 re-index kuralı: Embedding modeli değişti → eski vektörler hiçbir işe yaramaz. Boyut (768 vs 1024) ya da vektör dağılımı farklıdır; eski ve yeni vektörler aynı uzayda karşılaştırılamaz / karıştırılamaz. Geçiş = tüm corpus'u sıfırdan yeniden embed etmek (re-index).

Maliyeti yüksek ve geri dönüşü zahmetli olduğu için, geçişten önce kendi verimizde ölçüp emin olmak gerekir. Bu repo o ölçümü yapar.


Karşılaştırılan modeller (ilk tur)

Anahtar Model Boyut Not
bge-m3 BAAI/bge-m3 1024 Çok dilli, dense (sentence-transformers)
qwen3-0.6b Qwen/Qwen3-Embedding-0.6B 1024 2026 MMTEB lideri; query'de instruction prompt'u
baseline-bge-base BAAI/bge-base-en-v1.5 768 Mevcut prod baseline (fastembed). İngilizce-odaklı; Türkçede düşük çıkması beklenir

Yeni model eklemek = eval/providers.py içindeki REGISTRY'ye tek satır.

Baseline model id'si prod ile birebir aynı olmalı. enterprise-ai-assistant tarafındaki fastembed model adını teyit edip gerekirse REGISTRY'yi güncelle.


Altın küme (golden set)

Altın küme, sahibinin yüksek lisans tezinden üretilmiştir — bildiğimiz bir konu olduğu için doğru cevap (relevant) etiketlemesi güvenilirdir.

  • corpus (golden_set/corpus.jsonl): tez PDF'i scripts/build_golden_set.py ile temizlenip ~700 karakterlik pasajlara bölünür ({id, text, source}). Üst bilgi/sayfa numaraları atılır; kapak, içindekiler, dizinler ve kaynakça hariç tutulur.
  • queries (golden_set/queries.jsonl): Türkçe factual sorular ({q_id, query, relevant_ids[]}). relevant_ids, cevabı doğrudan içeren chunk(lar)dır ve tek tek corpus'ta okunarak doğrulanmıştır.
  • Etiketleme politikası: Bir chunk, soruyu kendi başına karşılayacak kadar açık cevap içeriyorsa relevant sayılır (özet/sonuç + ilgili bölüm gövdesi). Türkçe sorularda Türkçe kaynak chunk'lar hedeflenir.

Gizlilik: Tez savunma öncesi olduğundan bu repo private tutulur. Ham PDF (Only_tez.pdf) commit edilmez (.gitignore); yalnızca chunk'lanmış metin corpus'ta yer alır. corpus'u yeniden üretmek için ham PDF'i repo köküne koyup build_golden_set.py çalıştır.


Türkçe normalizasyon

corpus ve query aynı normalizasyondan geçer (tutarlılık şart). Varsayılan: NFC + whitespace sadeleştirme + Türkçe-doğru lowercase.

Türkçe lowercase tuzağı: "I".lower()"i" (İngilizce). Doğrusu I → ı ve İ → i. eval/normalize.py bunu .lower() öncesi elle çevirir. Örn. "IMU" → "ımu"; corpus ve query aynı şekilde dönüştüğü için eşleşme bozulmaz. --no-lowercase ile cased ham metni de deneyebilirsin.


Metrikler (kısa kavram)

  • recall@k — doğru kaynak, ilk k sonuç içinde mi? (kaynak bulma oranı)
  • MRR — ilk doğru kaynağın sırası ne kadar üstte? (1/rank ortalaması)
  • NDCG@10 — sıralama kalitesi; doğru kaynaklar ne kadar üstteyse o kadar yüksek.

RAG için recall@1 (ilk sıraya doğru kaynağı koymak) ve NDCG@10 (sıralama) birlikte bakılması gereken iki ana sinyaldir.


Kurulum & çalıştırma

uv ile, Python 3.12:

uv sync

# Tüm modeller + tüm metrikler, tek komut (modeller ilk koşuda iner):
bash scripts/run-all.sh
# veya doğrudan:
uv run python -m eval run \
  --corpus golden_set/corpus.jsonl \
  --queries golden_set/queries.jsonl \
  --models bge-m3,qwen3-0.6b,baseline-bge-base

Sonuç results/summary.md (insan-okur tablo + kazanan + baseline'a göre delta) ve results/raw.json olarak yazılır.

"Anlamı gözle gör" alıştırması

Embedding'in kelime değil anlam yakaladığını somut görmek için:

uv run python scripts/sanity_cosine.py            # bge-m3

Paraphrase çifti ("Toplantı yarına ertelendi" / "Görüşme bir gün sonraya alındı") yüksek; alakasız çift düşük cosine vermeli. Ortak kelime olmadan yüksek benzerlik = modelin anlamı kavradığının kanıtı.


Sonuçlar

İlk tur (2026-05-29): 234 chunk corpus, 22 soru, Türkçe lowercase açık, topk=10. bge-m3 yerel Ollama'dan (F16), Qwen3 + baseline sentence-transformers/fastembed (full precision). Tam tablo + delta: results/summary.md.

Model recall@1 recall@5 recall@10 MRR NDCG@10
bge-m3 0.4242 0.6061 0.7045 0.7835 0.6552
qwen3-0.6b 0.1894 0.4015 0.4621 0.4422 0.3687
baseline-bge-base 0.0909 0.2424 0.3333 0.1966 0.2153

Kazanan: bge-m3 — NDCG@10'da baseline'a göre +0.44, Qwen3'e göre +0.29. recall@1 baseline'ın ~4.6 katı (0.09 → 0.42).

Yorum

  • Migrasyon kararı net: mevcut prod modeli (fastembed BGE-Base 768d, İngilizce-odaklı) Türkçe corpus'ta en zayıfı. bge-m3'e geçiş büyük kazanç.
  • Sürpriz: Qwen3-Embedding (2026 MMTEB global lideri) burada bge-m3'ün yarısı kadar. Yani global sıralama Türkçe'ye doğrudan transfer olmadı — körlemesine Qwen3'e geçmek yanlış olurdu. Eval'in amacı tam da buydu.
  • Adil olmak için caveat'lar (Qwen3 aleyhine olabilecekler):
    1. Test edilen en küçük varyant (0.6B); MMTEB lideri skorlar 4B/8B'den. bge-m3 (568M) ise boyutça yakın ve özellikle çok dilli eğitilmiş.
    2. Türkçe lowercase açıktı. --no-lowercase ablasyonu koşuldu (results/ablation-nolowercase.md): lowercase tüm cased modellere hafif zarar veriyor, en çok Qwen3'e (+0.056 NDCG@10). Ama Qwen3 no-lowercase'de bile (0.42) bge-m3'ün (0.69) çok altında — confound kararı değiştirmiyor.
    3. Query instruction'ı generic İngilizce; Qwen3 instruction'a duyarlıdır.

Sonuç: bu corpus ve dağıtılabilir 0.6B boyutunda bge-m3 açık tercih. Qwen3 düşünülecekse 4B/8B varyantı + instruction/normalize ablasyonu ile tekrar ölçülmeli; "MMTEB lideri" varsayımına güvenilmemeli. Ayrıca prod'da Türkçe için lowercase'i kapatmak küçük ama tutarlı bir kazanç sağlıyor.

Yeniden üretmek için:

uv run python -m eval run --models bge-m3-ollama,qwen3-0.6b,baseline-bge-base
# tam ST (Ollama yerine) için: --models bge-m3,qwen3-0.6b,baseline-bge-base

Yapı

eval/        harness: normalize, providers (REGISTRY), embed, retrieve, score, __main__
golden_set/  corpus.jsonl + queries.jsonl (tezden üretilmiş)
scripts/     build_golden_set.py, run-all.sh, sanity_cosine.py
tests/       fixtures/ + test_smoke.py (CI: gerçek modellerle uçtan uca)
results/     summary.md (insan-okur), raw.json (gitignore)

CI (.github/workflows/smoke.yml): minik fixture üzerinde üç modeli de koşturup metriklerin non-zero olduğunu doğrular.

Lisans

MIT — bkz. LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors