sedayzc/turkish-medical-rag
🩺 Turkish Medical RAG Hierarchical Parent–Child Retrieval-Augmented Generation for Turkish Medical Documents 📌 Proje Hakkında Bu proje, Türkçe tıbbi dokümanlar üzerinde çalışan uçtan uca bir Retrieval-Augmented Generation (RAG) sistemi geliştirmek amacıyla hazırlanmıştır. Sistem bir kullanıcı sorusu aldığında önce doküman koleksiyonundaki küçük ve anlamsal olarak odaklı parçalar (child chunks)… See the full description on the dataset page: https://huggingface.co/datasets/sedayzc/turkish-medical-rag.
🩺 Turkish Medical RAG
<p align="center"> <strong>Hierarchical Parent–Child Retrieval-Augmented Generation for Turkish Medical Documents</strong> </p>
<p align="center"> <a href="https://github.com/ssedayzc/turkish-medical-rag"> <img src="https://img.shields.io/badge/GitHub-Source%20Code-181717?logo=github&logoColor=white" alt="GitHub"> </a> <a href="https://huggingface.co/datasets/sedayzc/turkish-medical-rag"> <img src="https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Dataset-FFD21E" alt="Hugging Face Dataset"> </a> <a href="https://huggingface.co/spaces/sedayzc/turkish-medical-rag-demo"> <img src="https://img.shields.io/badge/%F0%9F%9A%80%20Live%20Demo-Gradio%20Space-FF7C00" alt="Live Demo"> </a> </p>
<p align="center"> <img src="https://img.shields.io/badge/Python-3.11-blue?logo=python"> <img src="https://img.shields.io/badge/Embedding-Qwen3--Embedding--0.6B-purple"> <img src="https://img.shields.io/badge/Vector%20DB-ChromaDB-orange"> <img src="https://img.shields.io/badge/Similarity-Cosine-green"> <img src="https://img.shields.io/badge/Threshold-0.57-red"> <img src="https://img.shields.io/badge/RAG-Parent--Child-teal"> </p>
📌 Proje Hakkında
Bu proje, Türkçe tıbbi dokümanlar üzerinde çalışan uçtan uca bir Retrieval-Augmented Generation (RAG) sistemi geliştirmek amacıyla hazırlanmıştır.
Sistem bir kullanıcı sorusu aldığında önce doküman koleksiyonundaki küçük ve anlamsal olarak odaklı parçalar (child chunks) üzerinde dense vector retrieval gerçekleştirir.
En iyi retrieval sonucunun cosine similarity değeri daha önce benchmark üzerinden belirlenen eşik değerinin altındaysa sistem dokümanlarda yeterli kanıt olmadığını kabul eder ve doğrudan:
Bu sorunun cevabı dokümanlarımda yer almamaktadır
cevabını üretir.
Eşik değerini geçen sorgularda ise bulunan child chunk'ın ait olduğu daha geniş parent chunk modele context olarak verilir ve cevap yalnızca elde edilen dokümanlara dayanılarak üretilir.
Bu sayede sistem iki farklı problemi birlikte çözmeyi amaçlar:
- doğru dokümanı yüksek hassasiyetle bulmak,
- koleksiyonda bulunmayan sorulara modelin kendi bilgisinden cevap uydurmasını engellemek.
📊 Temel Proje İstatistikleri
Benchmark sonuçları yalnızca oluşturulan 30 soruluk test seti üzerindeki performansı ifade eder ve sistemin tüm olası kullanıcı sorgularında %100 doğruluk sağlayacağı anlamına gelmez.
📚 Veri Seti
Kaynak olarak Hugging Face üzerindeki:
umutertugrul/turkish-hospital-medical-articlesveri setinin Memorial hastane içeriklerini içeren bölümü kullanılmıştır.
Kaynak dosya:
memorial.parquetTemizleme sonrasında kullanılabilir 5,264 doküman içerisinden sabit random seed kullanılarak 500 makale seçilmiştir.
RANDOM_SEED = 42Oluşturulan temel veri seti:
data/articles_500.parquetşeklinde saklanmaktadır.
Her makale için temel olarak şu bilgiler korunmuştur:
parent_id
url
title
text
publish_date
update_date
scrape_date
sourceBu seçim ile sistem hem yeterince geniş bir tıbbi konu çeşitliliğine sahip olurken hem de lokal ortamda tekrar üretilebilir ve deney yapılabilir bir koleksiyon boyutunda tutulmuştur.
✂️ Chunking Stratejisi
Neden klasik fixed-size chunking kullanılmadı?
RAG sistemlerinde çok büyük chunk'lar kullanıldığında retrieval sonucuna gereksiz metinler dahil olabilir.
Çok küçük chunk'lar kullanıldığında ise doğru metin bulunmasına rağmen cevap üretmek için gereken bağlam parçalanabilir.
Bu projede bu iki problemin birlikte azaltılması amacıyla Hierarchical Parent–Child Chunking yaklaşımı kullanılmıştır.
Parent–Child Yaklaşımı
Her doküman iki farklı seviyede parçalanmaktadır:
Child Chunk
Child chunk'lar retrieval için kullanılır.
Daha küçük olmaları nedeniyle kullanıcının sorusuyla ilgili spesifik cümle veya paragrafları daha hassas şekilde temsil ederler.
Maximum child size : 320 token
Minimum target : 80 tokenChild chunk'lar embedding modeline gönderilir ve ChromaDB içerisinde indekslenir.
Parent Chunk
Parent chunk'lar doğrudan vector search için kullanılmaz.
Bir child chunk başarılı şekilde retrieve edildiğinde, ilgili child'ın bağlı olduğu daha geniş parent chunk modele context olarak gönderilir.
Maximum parent size : 1200 token
Minimum target : 200 tokenBöylece:
küçük chunk → daha hassas retrieval
büyük parent → daha zengin generation contextavantajları birlikte kullanılmaktadır.
Chunk Sınırları
Chunking yalnızca karakter sayısına göre yapılmamıştır.
Öncelikle:
- paragraf yapıları,
- cümle sınırları,
- soru-cevap blokları,
- liste yapıları,
- anlamsal bölümler
korunmaya çalışılmıştır.
Child seviyesinde gerektiğinde 1 semantic unit overlap kullanılmaktadır.
Parent chunk'larda ise overlap kullanılmamaktadır.
Parent overlap : 0
Child overlap : 1 semantic unitChunk Tokenizer
Chunk geometrisini ölçmek için:
BAAI/bge-m3tokenizer'ı kullanılmıştır.
Bu model burada embedding üretmek amacıyla değil, yalnızca metinlerin token uzunluğunu güvenilir biçimde ölçmek amacıyla kullanılmıştır.
Retrieval embedding'leri daha sonraki aşamada ayrı olarak Qwen3-Embedding-0.6B ile üretilmiştir.
Chunk tokenizer ile embedding tokenizer'ın farklı olması bir problem değildir; kritik gereksinim document ve query embedding'lerinin aynı embedding modeliyle üretilmesidir.
Bu projede her ikisi de:
Qwen/Qwen3-Embedding-0.6Bile üretilmektedir.
Chunk Temizleme
Web tabanlı tıbbi makalelerde menüler, tekrar eden başlıklar ve navigation blokları bulunduğu için chunking öncesinde ve sırasında ek temizleme uygulanmıştır.
Uygulanan işlemler arasında:
- consecutive duplicate segment temizleme,
- adjacent phrase duplicate temizleme,
- chunk boundary duplicate temizleme,
- navigation / table-of-contents bloklarının temizlenmesi,
- gereksiz tekrarların kaldırılması
bulunmaktadır.
Bununla birlikte gerçek FAQ ve doktor soru listelerinin yanlışlıkla silinmemesi için agresif global deduplication uygulanmamıştır.
Final chunk sonucu:
500 article
895 parent chunk
3259 child chunkolarak elde edilmiştir.
🧠 Embedding Modeli
Retrieval embedding modeli olarak:
Qwen/Qwen3-Embedding-0.6Bkullanılmıştır.
Model çıktısı:
1024 dimensiondense embedding vektörlerinden oluşmaktadır.
Neden Qwen3-Embedding-0.6B?
Model seçiminde yalnızca model büyüklüğü değil aşağıdaki kriterler dikkate alınmıştır:
- çok dilli retrieval desteği,
- Türkçe metinlerle çalışabilmesi,
- retrieval odaklı embedding mimarisi,
- instruction-aware query embedding desteği,
- lokal GPU üzerinde çalıştırılabilmesi,
- embedding kalitesi / kaynak tüketimi dengesi.
Daha büyük embedding modelleri daha yüksek kaynak tüketimine neden olduğundan bu proje için 0.6B sürümü performans ve donanım gereksinimi açısından dengeli bir tercih olarak değerlendirilmiştir.
Document ve Query Embedding
Dokümanlar doğrudan encode edilmektedir.
embedding_model.encode(
chunk_texts,
normalize_embeddings=True
)Query tarafında ise modelin retrieval query prompt'u kullanılmaktadır:
embedding_model.encode(
question,
prompt_name="query",
normalize_embeddings=True
)Bu ayrım modelin sorgu ve doküman rollerini daha doğru temsil etmesini sağlar.
L2 Normalization
Tüm embedding'ler float32 formatına dönüştürülmüş ve ayrıca NumPy ile tekrar L2 normalize edilmiştir.
Sonuç olarak vektör normları yaklaşık:
mean = 1.000000seviyesindedir.
Normalize embedding kullanımı cosine similarity hesaplarının daha tutarlı olmasını sağlar.
🗄️ Vector Database
Vector database olarak:
ChromaDBkullanılmıştır.
Collection:
turkish_medical_chunksolarak oluşturulmuştur.
Distance metric:
cosineşeklindedir.
ChromaDB içerisine embedding'ler tekrar hesaplanmadan doğrudan eklenmiştir.
Her child için:
child_id
chunk_vector
chunk_text
parent_id
article_id
title
urlbilgileri saklanmaktadır.
Parent metinleri ise tekrar tekrar Chroma metadata içerisinde tutulmak yerine Parquet dosyasından parent_id kullanılarak alınmaktadır.
Bu nedenle sistemde:
ChromaDB → retrieval index
Parquet → document / parent storeayrımı bulunmaktadır.
🎯 Threshold Analizi
RAG sisteminin en önemli parçalarından biri, vector search her zaman bir "en yakın" doküman döndürdüğü için bu sonucun gerçekten alakalı olup olmadığını belirlemektir.
Örneğin koleksiyonda otomobil bilgisi bulunmamasına rağmen:
Toyota Corolla'nın motor hacmi kaç cc?sorgusu için Chroma yine matematiksel olarak en yakın tıbbi chunk'ı döndürmektedir.
Bu nedenle yalnızca Top-1 document almak yeterli değildir.
Benchmark
Threshold belirlemek için toplam 30 soru hazırlanmıştır:
20 positive
10 negativePositive
Cevabı mevcut tıbbi doküman koleksiyonunda bulunan sorular:
Angelman sendromunun belirtileri nelerdir?
Bradikardi nedir ve belirtileri nelerdir?
Migrene ne iyi gelir?
...Negative
Cevabı doküman koleksiyonunda bulunmayan sorular:
Toyota Corolla'nın motor hacmi kaç cc?
Python'da bir liste nasıl sıralanır?
Fransa'nın başkenti neresidir?
SQL'de iki tablo nasıl JOIN edilir?
...Similarity Dağılımı
Benchmark sonucunda:
En düşük pozitif skor:
0.604484En yüksek negatif skor:
0.534648olmuştur.
İki sınıf arasında:
0.604484 - 0.534648
= 0.069836bir ayrım gözlenmiştir.
Threshold Seçimi
Negatif maksimum değer ile pozitif minimum değer arasındaki orta nokta hesaplanmıştır:
(0.534648 + 0.604484) / 2
= 0.569566Bu değer final uygulamada okunabilirlik amacıyla:
THRESHOLD = 0.57olarak kullanılmıştır.
Karar mekanizması:
if top1_similarity >= 0.57:
retrieve_parent_context()
generate_answer()
else:
return "Bu sorunun cevabı dokümanlarımda yer almamaktadır"şeklindedir.
Threshold Scan
Ayrıca:
0.200 → 0.800aralığında:
0.001adımla toplam 601 threshold değeri taranmıştır.
Her threshold için:
- True Positive
- True Negative
- False Positive
- False Negative
- Accuracy
- Precision
- Recall
- Specificity
- F1
- Balanced Accuracy
hesaplanmıştır.
Seçilen 0.57 threshold değerinde benchmark sonucu:
TP = 20
TN = 10
FP = 0
FN = 0olarak elde edilmiştir.
Buna karşılık:
Accuracy = 1.00
Precision = 1.00
Recall = 1.00
Specificity = 1.00
F1 = 1.00
Balanced Accuracy = 1.00sonuçları elde edilmiştir.
Bu değerler yalnızca oluşturulan benchmark üzerinde gözlenen sonuçlardır ve genel kullanım için %100 başarı iddiası olarak değerlendirilmemelidir.
🤖 Answer Generation
Retrieval sonucunda threshold'u geçen sorgular için generation modeli olarak:
Qwen/Qwen3-1.7Bkullanılmıştır.
Akış:
User Question
↓
Child Retrieval
↓
Threshold
↓
Unique Parent Selection
↓
Parent Context
↓
Qwen3-1.7B
↓
Final Turkish AnswerGenerator'a verilen system prompt modeli yalnızca retrieve edilen context içerisindeki bilgilere göre cevap vermeye yönlendirmektedir.
Modelden:
- dış bilgi kullanmaması,
- tahmin yapmaması,
- dokümanda bulunmayan bilgi eklememesi,
- Türkçe ve doğrudan cevap vermesi
istenmektedir.
🚫 Cevabı Olmayan Sorular
Top-1 similarity:
similarity < 0.57olduğunda generator model çalıştırılmaz.
Sistem doğrudan ve tam olarak:
Bu sorunun cevabı dokümanlarımda yer almamaktadırcevabını üretir.
Bu yaklaşım:
- hallucination riskini azaltır,
- gereksiz LLM inference maliyetini önler,
- sistem davranışını deterministik hale getirir.
🧪 Final RAG Testi
30 soruluk benchmark final RAG pipeline üzerinden tekrar çalıştırılmıştır.
Sonuç:
30 / 30 threshold decision correctolarak gözlenmiştir.
Örnek pozitif sorgu:
Soru:
Angelman sendromunun belirtileri nelerdir?
Similarity:
~0.816
Threshold:
0.57
Decision:
ACCEPTİlgili Angelman Sendromu dokümanı retrieval ile bulunmuş ve parent context kullanılarak cevap oluşturulmuştur.
Örnek negatif sorgu:
Soru:
Toyota Corolla'nın motor hacmi kaç cc?
Similarity:
~0.33
Threshold:
0.57
Decision:
REJECTSistem:
Bu sorunun cevabı dokümanlarımda yer almamaktadırcevabını üretmiştir.
🧩 Script Açıklamaları
🚀 Kurulum
Repository, final RAG pipeline'ını çalıştırmak için gerekli hazırlanmış artifact'ları içerir. Bu nedenle veri toplama, chunking ve embedding aşamalarının tekrar çalıştırılması zorunlu değildir.
1. Repository'yi klonlayın
git clone <https://github.com/ssedayzc/turkish-medical-rag.git>
cd turkish-medical-rag2. Bağımlılıkları yükleyin
Python 3.11 önerilmektedir.
python -m pip install -r requirements.txt3. Final benchmark'ı çalıştırın
python 09_run_rag_questions.pyScript repository içerisindeki hazır:
- benchmark questions,
- child embeddings,
- ChromaDB vector index,
- parent documents,
- selected threshold
artifact'larını kullanarak 30 benchmark sorusunu final RAG pipeline üzerinden yeniden çalıştırır.
İlk çalıştırmada Hugging Face modelleri otomatik olarak indirilecektir.
👀 Çalıştırmadan Sonuçları İnceleme
Final sonuçları görmek için herhangi bir model indirmeniz veya kod çalıştırmanız gerekmez.
Hazır sonuçlar:
analysis/rag_question_answers.txt
analysis/rag_question_answers.json
analysis/benchmark_results.csv
analysis/threshold_scan.csv
analysis/selected_threshold.jsondosyalarında bulunmaktadır.
Özellikle:
analysis/rag_question_answers.txtdosyası benchmark sorularını, retrieval kararlarını, similarity skorlarını, üretilen cevapları ve kullanılan kaynakları insan tarafından okunabilir formatta içerir.
🔄 Pipeline'ı Baştan Yeniden Üretme
Hazır artifact'ları kullanmak yerine tüm pipeline'ı sıfırdan yeniden üretmek isteyen kullanıcılar aşağıdaki adımları çalıştırabilir:
python 01_collect_articles.py
python 02_chunk_articles.py
python 02_1_inspect_chunks.py
python 02_2_inspect_content_quality.py
python 03_embed_chunks.py
python 04_build_chroma.py
python 05_test_retrieval.py
python 06_run_benchmark.py
python 07_select_threshold.py
python 09_run_rag_questions.pyInteractive RAG uygulaması ayrıca:
python 08_final_rag.pyile çalıştırılabilir.
01_collect_articles.py kaynak Hugging Face datasetine eriştiğinden, pipeline'ı sıfırdan çalıştırmak isteyen kullanıcının dataset erişim koşullarını kabul etmiş olması gerekebilir.
Gerekirse:
hf auth loginkullanılabilir.
📤 Üretilen Çıktılar
Final benchmark aşağıdaki çıktıları üretir:
analysis/rag_question_answers.csv
analysis/rag_question_answers.json
analysis/rag_question_answers.txtHer kayıt içerisinde:
question
question_type
top1_similarity
decision
answer
source_titles
source_urls
embedding_seconds
search_seconds
generation_seconds
total_secondsgibi bilgiler bulunmaktadır.
🧾 Özet
Bu projede:
500 Turkish medical articles
↓
Hierarchical Parent-Child Chunking
↓
3259 Child Chunks
↓
Qwen3-Embedding-0.6B
↓
1024-D Dense Embeddings
↓
ChromaDB / Cosine Search
↓
0.57 Similarity Threshold
↓
Parent Context Retrieval
↓
Qwen3-1.7B
↓
Grounded Turkish Answerpipeline'ı oluşturulmuştur.
Ana tasarım hedefi yalnızca doğru dokümanı bulmak değil, aynı zamanda cevabı doküman koleksiyonunda bulunmayan soruların güvenilir şekilde filtrelenmesidir.
