CoolFace
Datasetpublic

nyzmemre/turkce-tibbi-rag-vektor-db

Türkçe Tıbbi Makaleler — Vektör Arama Veri Tabanı Türkçe hastane sağlık rehberi makalelerinden oluşturulmuş, benzerlik eşiğiyle filtrelenen bir vektör arama sistemi. Cevabı dokümanlarda bulunmayan sorularda sistem içerik döndürmez. Kaynak veri: umutertugrul/turkish-hospital-medical-articles (erişim onayı gerektirir), atlas bölümü — 130 makale. Veri tablosu chunks.parquet dosyası şu kolonları içerir: Kolon Tip Açıklama url string Parçanın alındığı… See the full description on the dataset page: https://huggingface.co/datasets/nyzmemre/turkce-tibbi-rag-vektor-db.

sourceHugging Facecc-by-4.0updated 2mo agoView on Hugging Face
0likes38downloads
Dataset Card

Türkçe Tıbbi Makaleler — Vektör Arama Veri Tabanı

Türkçe hastane sağlık rehberi makalelerinden oluşturulmuş, benzerlik eşiğiyle filtrelenen bir vektör arama sistemi. Cevabı dokümanlarda bulunmayan sorularda sistem içerik döndürmez.

Kaynak veri: umutertugrul/turkish-hospital-medical-articles (erişim onayı gerektirir), atlas bölümü — 130 makale.

Veri tablosu

chunks.parquet dosyası şu kolonları içerir:

KolonTipAçıklama
urlstringParçanın alındığı makalenin kaynak bağlantısı
chunk_textstringParçalanmış metin içeriği
chunk_vectorlist[float]768 boyutlu vektör temsili
chunk_idstringParça kimliği
parent_idstringParçanın ait olduğu makale (parent-child ilişkisi)
titlestringMakale başlığı
chunk_indexintParçanın makale içindeki sırası

Toplam 1.010 parça, 130 makaleden üretildi (makale başına ortalama 7,8 parça).

Chunking stratejisi

Veriyi incelemeden bir yöntem seçmek yerine önce metinlerin yapısına bakıldı ve iki gözlem belirleyici oldu:

Birincisi, makalelerde \n\n ayracı hiç bulunmuyor. Satırlar tek \n ile ayrılmış ve bu satırlar hem gerçek paragrafları hem de - Ameliyat Kararı Ne Zaman Verilir? gibi kısa ara başlıkları içeriyor. Bu nedenle klasik paragraf bölme bu veride doğrudan uygulanamıyor.

İkincisi, 130 makalenin 98'i İçindekiler satırı ve ardından gelen bağlantı listesiyle başlıyor. Bu blok yalnızca başlıklardan oluştuğu için parçalandığında içerik taşımayan bir vektör üretiyor ve aramada gürültü yaratıyordu; temizlik adımında kaldırıldı.

Seçilen yöntem karma (mixed) parçalama:

  1. 1.Metin önce doğal sınırlarından birimlere ayrılır — önce satır, hedef uzunluğu aşan satırlar ayrıca cümle sonlarından.
  2. 2.Birimler, hedef uzunluğa ulaşana kadar birleştirilir.
  3. 3.Komşu parçalar arasında örtüşme bırakılır: önceki parçanın son cümleleri yeni parçanın başına taşınır.
  4. 4.Tek başına anlam taşımayacak kadar kısa artıklar bir öncekine eklenir.

Parametreler: hedef 800 karakter, örtüşme 150 karakter, en kısa parça 120 karakter. Sonuçta parça uzunlukları 127–1197 karakter aralığında, medyan 668 karakter.

Neden bu yöntem: sabit token bölme cümleyi ortasından keser ve tanımlar yarım kalır. Saf satır bölme ise 30–40 karakterlik başlık parçaları üretir; bunlar tek başına vektörleştirildiğinde aramada anlamsız eşleşmelere yol açar. Karma yöntem, parçaların hem anlamlı bir bütünlük taşımasını hem de birbirine yakın boyutta olmasını sağlıyor. Örtüşme ise bir tanımın parça sınırında ikiye bölünüp her iki parçada da eksik kalması riskini azaltıyor.

Embedding modeli

Kullanılan model: `magibu/embeddingmagibu-200m`, vektör boyutu 768.

Değerlendirilen alternatifler ve seçim gerekçesi:

ModelBoyutVektörNot
magibu/embeddingmagibu-200m430 MB7688192 token bağlam, Türkçe odaklı
trmteb/turkish-embedding-model444 MB768BERT tabanlı
ytu-ce-cosmos/turkish-e5-large2,3 GB1024
BAAI/bge-m34,6 GB1024çok dilli

Seçimde üç ölçüt etkili oldu. Model Türkçe odaklı; bu çalışmadaki sorular günlük hasta diliyle yazıldığı için dilin kendi kalıplarını tanıması gerekiyordu. Bağlam penceresi 8192 token, yani 800 karakterlik parçalar hiçbir koşulda kırpılmıyor — daha dar pencereli bir modelde uzun parçaların sonu sessizce atılabilirdi. Son olarak 430 MB ile listedeki en hafif seçenek; embedding üretimi Apple M2 üzerinde MPS ile 1.010 parça için 121 saniye sürdü, ayrı bir GPU gerekmedi.

Vektörler birim uzunluğa normalize ediliyor. Böylece nokta çarpımı doğrudan kosinüs benzerliğine eşit oluyor ve veritabanının mesafe hesabıyla raporlanan skorlar birbiriyle tutarlı kalıyor.

Aynı model hem parçaları hem soruları vektörleştiriyor. Farklı modeller farklı vektör uzaylarına yazdığı için karışık kullanım skorları anlamsız hale getirirdi.

Vektör veritabanı

ChromaDB, kosinüs uzaklığı ile yapılandırıldı. Tek bir dizinde çalışan gömülü bir veritabanı olduğu için ek altyapı gerektirmiyor. PGVector alternatifi ayrıca bir PostgreSQL sunucusu kurmayı ve yönetmeyi gerektirirdi; bu ölçekte (1.010 parça) böyle bir yükün karşılığı yok.

Test kümesi

30 soru: 20 pozitif, 10 negatif (`test_sorulari.json`).

Sorular bilinçli olarak günlük hasta diliyle yazıldı. "Topuk dikeni nedir?" biçiminde bir soru, "Topuk Dikeni Nedir? Belirtileri ve Tedavisi" başlıklı makaleyle birebir kelime örtüşmesi kurar; bu, aramanın değil kelime tekrarının başarısıdır. Bunun yerine "Sabah yataktan kalkıp ilk adımı attığımda topuğumun altında keskin bir ağrı hissediyorum" gibi, makalenin anahtar kelimesini hiç içermeyen sorular tercih edildi.

Negatif soruların seçimi tahminle yapılmadı. İlk aday listesindeki bazı sorular ölçüldüğünde elendi:

Aday negatif soruSkorElenme sebebi
Hepatit B aşısı kaç dozda tamamlanır?0,650Veride "Hepatit Nedir?" makalesi var
Böbrek taşı düşürmek için ne yapılmalı?0,602Böbrek cerrahisi makalesi anlamsal olarak yakın
Kist hidatik nasıl bulaşır?0,597"Araknoid Kistler" makalesiyle ortak kavram
Yemek borumdan zor yemek geçiyor0,546"Akalazya - Yutma Güçlüğü" makalesi var

Buradaki ders, kelime taramasının yeterli olmadığı: bir terim veride hiç geçmiyor olabilir, ama anlamsal komşusu bulunuyorsa vektör araması onu yine de yakalar. Negatif sorular ancak ölçülerek doğrulanabildi.

Eşik analizi

Eşik değeri tahminle değil, test kümesinin skor dağılımı taranarak seçildi.

Skor dağılımı

pozitif (20 soru) : min 0,398   medyan 0,635   maks 0,842
negatif (10 soru) : min 0,359   medyan 0,428   maks 0,471

Eşik taraması

EşikKabul edilen pozitifKaçırılan pozitifSızan negatifKesinlikDuyarlılıkF1
0,4519140,8260,9500,884
0,4719110,9500,9500,950
0,4818201,0000,9000,947
0,5017301,0000,8500,919
0,5515501,0000,7500,857
0,6011901,0000,5500,710

Seçilen eşik: 0,48

F1 skoru en yüksek değer 0,47 (0,950). Buna rağmen 0,48 tercih edildi, çünkü 0,47'de bir negatif soru sızıyor: "Hapşurduğumda gıdıklanıyorum. neden olur" (0,471). Tıbbi içerikte cevabı olmayan bir soruya alakasız bir makale döndürmek, cevabı olan bir soruyu kaçırmaktan daha ağır bir hata. Bu nedenle kesinliğin 1,000 olduğu ilk değer seçildi.

0,48 eşiğinde kaçırılan iki pozitif sorunun hangileri olduğu ayrıca incelendi:

0,398   "Diyet yapıyorum. Diyette nelere dikkat etmem lazım"
0,476   "Vücudumdaki şişlikler zararsız. ama estetik açıdan kötü görünüyor..."

Her ikisi de test kümesinde beklenen_makale alanı boş bırakılan sorular. Birincisi tek bir makaleye oturmayacak kadar genel, ikincisinin konusu (iyi huylu deri altı şişlikleri) bu 130 makalede işlenmiyor. Yani sistem bu sorularda hata yapmıyor; karşılığı olmayan içeriği zorlamak yerine doğru biçimde eliyor.

Eşiğin üzerinde kalan 0,50–0,60 bandı da denendi. Kesinlik değişmiyor, ancak duyarlılık 0,850'den 0,550'ye düşüyor: cevabı veride bulunan sorular da elenmeye başlıyor. 0,48 bu iki hata türü arasındaki en dengeli nokta.

Getirme doğruluğu

Filtrelemeden ayrı olarak, eşiği geçen soruların doğru makaleyi getirip getirmediği de ölçüldü. beklenen_makale tanımlı 15 sorunun 15'inde beklenen makale ilk üç sonuç içinde yer aldı.

Bu iki ölçümü ayırmak gerekiyor: yüksek benzerlik skoru tek başına doğru cevap anlamına gelmez. Test hazırlığı sırasında 0,585 skorla eşiği geçen bir soru, konusuyla ilgisi olmayan bir makaleyi getirmişti. Yalnızca skora bakılsaydı sistem olduğundan iyi görünecekti.

Kullanım

bash
pip install -r requirements.txt

python hazirla.py          # makale -> parça -> vektör -> ChromaDB + parquet
python degerlendir.py      # 30 soruluk test, eşik taraması
python ara.py "Sabah ilk adımda topuğum ağrıyor, sebebi ne olabilir?"

Eşiğin altında kalan sorularda çıktı:

Bu sorunun cevabı dokümanlarımda yer almamaktadır.

Dosyalar

Dosyaİçerik
chunks.parqueturl / chunktext / chunkvector tablosu
test_sorulari.json20 pozitif + 10 negatif test sorusu
esik_analizi.jsonTüm soruların skorları ve eşik taraması çıktısı
hazirla.pyİndeksleme hattı
ara.pyArama ve eşik kontrolü
degerlendir.pyEşik analizi ve değerlendirme
rag/veri.pyVeri indirme ve temizlik
rag/chunk.pyParçalama
rag/embed.pyEmbedding üretimi
rag/vektor_db.pyChromaDB katmanı