nsr51324 commited on
Commit
76b2481
·
verified ·
1 Parent(s): 201270e

Create README.md

Browse files
Files changed (1) hide show
  1. README.md +1196 -0
README.md ADDED
@@ -0,0 +1,1196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ library_name: sentence-transformers
5
+ tags:
6
+ - rag
7
+ - retrieval-augmented-generation
8
+ - medical
9
+ - question-answering
10
+ - semantic-search
11
+ - faiss
12
+ - cross-encoder
13
+ - medical-qa
14
+ pipeline_tag: question-answering
15
+ license: apache-2.0
16
+ ---
17
+
18
+ # Medical RAG System
19
+
20
+ A retrieval-augmented generation (RAG) system for answering medical questions using a curated English medical Question-Answer knowledge base.
21
+
22
+ The system combines:
23
+
24
+ - Semantic retrieval using Sentence Transformers
25
+ - FAISS vector search
26
+ - Medical query expansion
27
+ - Cross-Encoder reranking
28
+ - Evidence deduplication
29
+ - Confidence gating
30
+ - LLM-based answer generation
31
+ - Retrieval evaluation
32
+ - Confidence-gate evaluation
33
+ - Latency measurement
34
+
35
+ > **Important:** This system is intended for research and educational purposes. It is not a medical diagnostic system and should not be used as a substitute for professional medical advice.
36
+
37
+ ---
38
+
39
+ # 1. Overview
40
+
41
+ This project implements a complete Retrieval-Augmented Generation pipeline for medical Question-Answer data.
42
+
43
+ Instead of asking an LLM to answer directly from its internal knowledge, the system first retrieves relevant medical evidence from a local knowledge base.
44
+
45
+ The pipeline is:
46
+
47
+ ```text
48
+ User Question
49
+
50
+
51
+ Query Expansion
52
+
53
+
54
+ Sentence Transformer Embedding
55
+
56
+
57
+ FAISS Vector Search
58
+
59
+
60
+ Top-N Candidate Documents
61
+
62
+
63
+ Cross-Encoder Reranking
64
+
65
+
66
+ Top-K Evidence
67
+
68
+
69
+ Near-Duplicate Removal
70
+
71
+
72
+ Confidence Gate
73
+
74
+ ├── Reject → Insufficient Evidence
75
+
76
+
77
+ LLM Generation
78
+
79
+
80
+ Evidence-Based Answer
81
+ ```
82
+
83
+ ---
84
+
85
+ # 2. Knowledge Base
86
+
87
+ The knowledge base contains approximately:
88
+
89
+ ```text
90
+ 16,384 medical Question-Answer records
91
+ ```
92
+
93
+ The dataset contains medical questions and corresponding answers, together with categorical information.
94
+
95
+ Main columns used by the system:
96
+
97
+ ```text
98
+ Question
99
+ Answer
100
+ Category
101
+ doc_id
102
+ ```
103
+
104
+ A unique `doc_id` is assigned to every document:
105
+
106
+ ```python
107
+ df = df.reset_index(drop=True)
108
+ df["doc_id"] = df.index
109
+ ```
110
+
111
+ The `doc_id` is later used to identify evidence sources.
112
+
113
+ ---
114
+
115
+ # 3. Embedding Model
116
+
117
+ The system uses:
118
+
119
+ ```text
120
+ sentence-transformers/all-MiniLM-L6-v2
121
+ ```
122
+
123
+ The model converts every medical question into a dense vector representation.
124
+
125
+ Embeddings are normalized:
126
+
127
+ ```python
128
+ question_embeddings = embedder.encode(
129
+ questions,
130
+ batch_size=64,
131
+ show_progress_bar=True,
132
+ convert_to_numpy=True,
133
+ normalize_embeddings=True,
134
+ )
135
+ ```
136
+
137
+ Normalization allows the FAISS Inner Product index to behave as cosine similarity search.
138
+
139
+ The resulting embedding matrix is stored as:
140
+
141
+ ```text
142
+ question_embeddings.npy
143
+ ```
144
+
145
+ ---
146
+
147
+ # 4. FAISS Retrieval
148
+
149
+ FAISS is used for efficient vector similarity search.
150
+
151
+ The index is created using:
152
+
153
+ ```python
154
+ faiss.IndexFlatIP(embedding_dim)
155
+ ```
156
+
157
+ Because the embeddings are normalized, Inner Product corresponds to cosine similarity.
158
+
159
+ The FAISS index contains:
160
+
161
+ ```text
162
+ 16,384 vectors
163
+ ```
164
+
165
+ The index is saved as:
166
+
167
+ ```text
168
+ questions.index
169
+ ```
170
+
171
+ Retrieval works by:
172
+
173
+ 1. Embedding the user query
174
+ 2. Searching the FAISS index
175
+ 3. Returning the top-N most similar questions
176
+
177
+ Default retrieval configuration:
178
+
179
+ ```python
180
+ RETRIEVE_TOP_N = 20
181
+ ```
182
+
183
+ ---
184
+
185
+ # 5. Query Expansion
186
+
187
+ The system includes a lightweight medical query expansion layer.
188
+
189
+ This helps bridge the gap between everyday language and medical terminology.
190
+
191
+ Examples:
192
+
193
+ ```text
194
+ underactive thyroid
195
+
196
+ hypothyroidism
197
+
198
+ overactive thyroid
199
+
200
+ hyperthyroidism
201
+
202
+ high blood sugar
203
+
204
+ hyperglycemia
205
+
206
+ low blood sugar
207
+
208
+ hypoglycemia
209
+
210
+ sugar disease
211
+
212
+ diabetes
213
+ ```
214
+
215
+ For example:
216
+
217
+ ```text
218
+ I suffer from an underactive thyroid gland
219
+ ```
220
+
221
+ becomes:
222
+
223
+ ```text
224
+ I suffer from an underactive thyroid gland
225
+ (hypothyroidism)
226
+ ```
227
+
228
+ The original query is not replaced.
229
+
230
+ The medical term is simply appended before generating the embedding.
231
+
232
+ ---
233
+
234
+ # 6. Cross-Encoder Reranking
235
+
236
+ After FAISS retrieves the initial candidates, a Cross-Encoder is used to rerank them.
237
+
238
+ Model:
239
+
240
+ ```text
241
+ cross-encoder/ms-marco-MiniLM-L-6-v2
242
+ ```
243
+
244
+ The system retrieves:
245
+
246
+ ```text
247
+ Top 20
248
+ ```
249
+
250
+ candidates and reranks them to keep:
251
+
252
+ ```text
253
+ Top 6
254
+ ```
255
+
256
+ Configuration:
257
+
258
+ ```python
259
+ RETRIEVE_TOP_N = 20
260
+ RERANK_TOP_K = 6
261
+ ```
262
+
263
+ The reranker scores:
264
+
265
+ ```text
266
+ (query, Answer)
267
+ ```
268
+
269
+ rather than:
270
+
271
+ ```text
272
+ (query, Question)
273
+ ```
274
+
275
+ This is important because the dataset contains multiple records with the same Question but different medical answers.
276
+
277
+ Reranking the Answer therefore helps determine which evidence is actually useful for answering the user's question.
278
+
279
+ ---
280
+
281
+ # 7. Evidence Deduplication
282
+
283
+ Medical datasets can contain multiple answers that are almost identical.
284
+
285
+ The system removes near-duplicate answers using:
286
+
287
+ ```python
288
+ difflib.SequenceMatcher
289
+ ```
290
+
291
+ with:
292
+
293
+ ```python
294
+ threshold = 0.92
295
+ ```
296
+
297
+ This prevents the LLM from receiving multiple copies of essentially the same evidence.
298
+
299
+ Each evidence item contains:
300
+
301
+ ```text
302
+ doc_id
303
+ question
304
+ answer
305
+ category
306
+ similarity
307
+ rerank_score
308
+ ```
309
+
310
+ ---
311
+
312
+ # 8. Confidence Gate
313
+
314
+ The system does not automatically answer every question.
315
+
316
+ Before sending evidence to the LLM, a confidence gate checks whether the retrieved evidence is strong enough.
317
+
318
+ Current configuration:
319
+
320
+ ```python
321
+ MIN_RERANK_SCORE = -8
322
+ MIN_SIMILARITY_FLOOR = 0.40
323
+ MIN_SUPPORT_COUNT = 2
324
+ SUPPORT_SCORE = -5.0
325
+ ```
326
+
327
+ The system accepts the evidence only if:
328
+
329
+ 1. At least one result exists.
330
+ 2. The highest rerank score is above the minimum threshold.
331
+ 3. The similarity score is above the minimum similarity floor.
332
+ 4. At least two retrieved documents provide sufficient support.
333
+
334
+ Otherwise, the system refuses to generate an evidence-based answer.
335
+
336
+ Example:
337
+
338
+ ```text
339
+ Question:
340
+ Why do I feel short of breath and tired when I climb stairs?
341
+
342
+ Result:
343
+ No sufficiently relevant evidence.
344
+
345
+ System:
346
+ I couldn't find sufficiently relevant medical evidence
347
+ in the knowledge base to answer this question.
348
+ ```
349
+
350
+ This behavior is important for reducing unsupported answers.
351
+
352
+ ---
353
+
354
+ # 9. LLM Generation
355
+
356
+ The generation stage uses a Groq-hosted LLM.
357
+
358
+ Current model used during development:
359
+
360
+ ```text
361
+ openai/gpt-oss-20b
362
+ ```
363
+
364
+ The LLM is explicitly instructed to operate in RAG mode.
365
+
366
+ Main generation rules:
367
+
368
+ ```text
369
+ 1. Use only retrieved evidence.
370
+ 2. Do not add outside medical knowledge.
371
+ 3. Do not guess.
372
+ 4. Cite evidence using [doc_id].
373
+ 5. Mention when evidence is insufficient.
374
+ 6. Do not diagnose users.
375
+ 7. Do not prescribe personalized treatment or dosages.
376
+ 8. Mention disagreements between sources.
377
+ 9. Keep answers concise and organized.
378
+ 10. Include a medical-information disclaimer.
379
+ ```
380
+
381
+ The API key is NOT stored in this repository.
382
+
383
+ It should be provided through an environment variable:
384
+
385
+ ```python
386
+ import os
387
+
388
+ GROQ_API_KEY = os.environ["GROQ_API_KEY"]
389
+ ```
390
+
391
+ ---
392
+
393
+ # 10. Example
394
+
395
+ ## Input
396
+
397
+ ```text
398
+ What signs might suggest that my thyroid is not producing enough hormones?
399
+ ```
400
+
401
+ ## Retrieved Evidence
402
+
403
+ ```text
404
+ [15967] Thyroid symptoms
405
+ [13504] Thyroid symptoms
406
+ [10676] Thyroid symptoms
407
+ [13989] What are the symptoms of thyroid disease?
408
+ [13559] Symptoms that indicate a disorder in the thyroid gland
409
+ [12173] How do I know that I have a thyroid problem?
410
+ ```
411
+
412
+ ## Generated Answer
413
+
414
+ The system generated an evidence-based response describing symptoms associated with low thyroid hormone production, including:
415
+
416
+ - Fatigue
417
+ - Feeling cold
418
+ - Weight gain
419
+ - Constipation
420
+ - Menstrual changes
421
+ - Hair loss
422
+
423
+ The final response also included the required medical disclaimer.
424
+
425
+ ---
426
+
427
+ # 11. Example of Out-of-Domain Query
428
+
429
+ ## Input
430
+
431
+ ```text
432
+ What is the best treatment for a broken leg?
433
+ ```
434
+
435
+ The retriever returned some medically related documents, mostly concerning diabetic foot injuries.
436
+
437
+ However, those documents did not contain appropriate evidence about treating fractures.
438
+
439
+ The final system response therefore stated that the available evidence did not contain information about treating a broken leg.
440
+
441
+ This demonstrates an important property of the system:
442
+
443
+ > Retrieval similarity alone does not guarantee that the retrieved evidence is appropriate for the question.
444
+
445
+ ---
446
+
447
+ # 12. Evaluation
448
+
449
+ The system was evaluated using multiple complementary evaluation methods.
450
+
451
+ These include:
452
+
453
+ - Self-retrieval accuracy
454
+ - Recall@K
455
+ - Precision@K
456
+ - F1@K
457
+ - MRR
458
+ - NDCG@K
459
+ - Category sanity check
460
+ - Confidence-gate accuracy
461
+ - Cross-validation threshold tuning
462
+ - Latency evaluation
463
+
464
+ ---
465
+
466
+ # 13. Self-Retrieval Evaluation
467
+
468
+ A sample of 50 questions was tested.
469
+
470
+ Result:
471
+
472
+ ```text
473
+ Self-retrieval Top-1 Accuracy:
474
+ 50 / 50
475
+
476
+ = 100%
477
+ ```
478
+
479
+ However, this metric should NOT be interpreted as proof that the system has 100% real-world retrieval accuracy.
480
+
481
+ It mainly verifies that the embedding/index pipeline can retrieve the original record when the exact same question is used.
482
+
483
+ ---
484
+
485
+ # 14. Retrieval Evaluation
486
+
487
+ The retrieval evaluation used questions that have duplicate Question entries in the dataset.
488
+
489
+ This provides multiple possible relevant answers for the same question.
490
+
491
+ ```text
492
+ Questions with duplicate entries usable for evaluation:
493
+ 67
494
+ ```
495
+
496
+ ## Retrieval Only
497
+
498
+ ```text
499
+ Recall@1 = 0.690
500
+ Precision@1 = 1.000
501
+ F1@1 = 0.745
502
+
503
+ Recall@3 = 0.851
504
+ Precision@3 = 0.560
505
+ F1@3 = 0.563
506
+
507
+ Recall@5 = 0.899
508
+ Precision@5 = 0.423
509
+ F1@5 = 0.462
510
+
511
+ Recall@10 = 0.959
512
+ Precision@10 = 0.286
513
+ F1@10 = 0.349
514
+
515
+ MRR = 1.000
516
+ ```
517
+
518
+ Number of evaluated queries:
519
+
520
+ ```text
521
+ 150
522
+ ```
523
+
524
+ ---
525
+
526
+ # 15. Retrieval + Cross-Encoder Evaluation
527
+
528
+ The same evaluation was also performed after Cross-Encoder reranking.
529
+
530
+ Results:
531
+
532
+ ```text
533
+ Recall@1 = 0.083
534
+ Precision@1 = 0.113
535
+ F1@1 = 0.093
536
+
537
+ Recall@3 = 0.157
538
+ Precision@3 = 0.087
539
+ F1@3 = 0.100
540
+
541
+ Recall@5 = 0.222
542
+ Precision@5 = 0.121
543
+ F1@5 = 0.120
544
+
545
+ Recall@10 = 0.388
546
+ Precision@10 = 0.135
547
+ F1@10 = 0.153
548
+
549
+ MRR = 0.237
550
+ ```
551
+
552
+ Number of evaluated queries:
553
+
554
+ ```text
555
+ 150
556
+ ```
557
+
558
+ ---
559
+
560
+ # 16. Important Evaluation Observation
561
+
562
+ The evaluation shows that the Cross-Encoder performed significantly worse under this particular retrieval benchmark.
563
+
564
+ This is an important finding rather than something to hide.
565
+
566
+ The current reranker was trained for general passage relevance using:
567
+
568
+ ```text
569
+ cross-encoder/ms-marco-MiniLM-L-6-v2
570
+ ```
571
+
572
+ while this evaluation is based on medical Question-Answer records.
573
+
574
+ Therefore, the Cross-Encoder may not rank the medical answers in the same way as the manually defined relevance criteria.
575
+
576
+ This suggests that the reranking component requires further investigation before being considered production-ready.
577
+
578
+ Possible future improvements include:
579
+
580
+ - Medical-domain reranker
581
+ - Fine-tuning a Cross-Encoder on medical relevance pairs
582
+ - Using a manually reviewed gold set
583
+ - Better relevance labeling
584
+ - Evaluating reranking separately from retrieval
585
+ - Testing alternative reranking models
586
+
587
+ ---
588
+
589
+ # 17. Category Sanity Check
590
+
591
+ A category-based sanity check was also performed.
592
+
593
+ The goal is to determine whether retrieved documents contain at least one document belonging to the same category as the query's source document.
594
+
595
+ ## Retrieval + Reranker
596
+
597
+ ```text
598
+ Category Recall = 0.98
599
+ n = 100
600
+ ```
601
+
602
+ ## Retrieval Only
603
+
604
+ ```text
605
+ Category Recall = 0.97
606
+ n = 100
607
+ ```
608
+
609
+ This indicates that the retrieval system generally retrieves documents from the expected medical category.
610
+
611
+ However:
612
+
613
+ > Category matching is only a supporting diagnostic metric and is NOT treated as the final ground truth for relevance.
614
+
615
+ ---
616
+
617
+ # 18. Confidence Gate Evaluation
618
+
619
+ A manually constructed evaluation set contained:
620
+
621
+ ```text
622
+ 25 in-domain questions
623
+ 25 out-of-domain questions
624
+ ```
625
+
626
+ Total:
627
+
628
+ ```text
629
+ 50 questions
630
+ ```
631
+
632
+ The system achieved:
633
+
634
+ ```text
635
+ Gate Decision Accuracy = 88%
636
+ ```
637
+
638
+ The system correctly accepted most in-domain questions and rejected most out-of-domain questions.
639
+
640
+ However, several false positives were observed.
641
+
642
+ Examples included questions about:
643
+
644
+ ```text
645
+ broken legs
646
+ kidney stones
647
+ sprained ankles
648
+ broken arms
649
+ food poisoning
650
+ ```
651
+
652
+ These questions sometimes retrieved medically related evidence even though the knowledge base did not contain appropriate evidence.
653
+
654
+ This demonstrates why confidence gating and stronger relevance evaluation are necessary.
655
+
656
+ ---
657
+
658
+ # 19. Confidence Score Distribution
659
+
660
+ For the confidence-gate evaluation:
661
+
662
+ ### Expected answer = True
663
+
664
+ ```text
665
+ Mean score = 5.539
666
+ Minimum = -8.938
667
+ Maximum = 9.321
668
+ ```
669
+
670
+ ### Expected answer = False
671
+
672
+ ```text
673
+ Mean score = -6.167
674
+ Minimum = -11.062
675
+ Maximum = 1.532
676
+ ```
677
+
678
+ There is overlap between the two distributions.
679
+
680
+ Therefore, a single rerank-score threshold cannot perfectly separate valid and invalid questions.
681
+
682
+ ---
683
+
684
+ # 20. Threshold Tuning
685
+
686
+ The confidence threshold was evaluated using 5-fold cross-validation.
687
+
688
+ Instead of selecting a threshold from one train/test split, the data is divided into five different folds.
689
+
690
+ For every fold:
691
+
692
+ 1. A threshold is optimized on the training portion.
693
+ 2. The threshold is evaluated on the held-out fold.
694
+ 3. The threshold and test accuracy are recorded.
695
+ 4. Mean and standard deviation are calculated.
696
+
697
+ This helps determine whether the selected threshold is stable or highly dependent on a small evaluation sample.
698
+
699
+ A large threshold standard deviation indicates that the evaluation set is too small or unstable and should be expanded before selecting a production threshold.
700
+
701
+ ---
702
+
703
+ # 21. Gold Set
704
+
705
+ A semi-automatic gold-set construction process was implemented.
706
+
707
+ The process:
708
+
709
+ ```text
710
+ 100 sampled questions
711
+
712
+
713
+ Exact duplicate questions
714
+
715
+
716
+ Semantic candidates with similarity >= 0.90
717
+
718
+
719
+ Manual review
720
+
721
+
722
+ Relevant = 1
723
+ Not relevant = 0
724
+
725
+
726
+ Final Gold Set
727
+ ```
728
+
729
+ The initial run generated:
730
+
731
+ ```text
732
+ 100 questions
733
+ 16 candidate pairs
734
+ 3 questions with semantic candidates
735
+ ```
736
+
737
+ The generated file:
738
+
739
+ ```text
740
+ gold_set_for_manual_review.xlsx
741
+ ```
742
+
743
+ contains candidate pairs that should be manually reviewed.
744
+
745
+ For each candidate, the reviewer should enter:
746
+
747
+ ```text
748
+ 1 = relevant
749
+ 0 = not relevant
750
+ ```
751
+
752
+ Only manually approved candidates should be added to the final relevant evidence set.
753
+
754
+ ---
755
+
756
+ # 22. Gold Set Evaluation Metrics
757
+
758
+ Once the manually reviewed gold set is completed, the system evaluates:
759
+
760
+ ```text
761
+ Recall@5
762
+ MRR
763
+ NDCG@5
764
+ ```
765
+
766
+ The evaluation compares:
767
+
768
+ ```text
769
+ Retriever only
770
+ ```
771
+
772
+ against:
773
+
774
+ ```text
775
+ Retriever + Cross-Encoder Reranker
776
+ ```
777
+
778
+ The manually reviewed gold set is preferred over category-based evaluation because it provides explicit relevance judgments.
779
+
780
+ ---
781
+
782
+ # 23. Latency Evaluation
783
+
784
+ The complete RAG pipeline was also measured for response latency.
785
+
786
+ Example result:
787
+
788
+ ```text
789
+ Retrieval = 0.016 sec
790
+ Reranking = 0.094 sec
791
+ Evidence build = 0.025 sec
792
+ LLM generation = 0.858 sec
793
+
794
+ Total = 0.993 sec
795
+ ```
796
+
797
+ Approximate breakdown:
798
+
799
+ ```text
800
+ Retrieval █
801
+ Reranking █████
802
+ Evidence ██
803
+ LLM █████████████████████████████████████
804
+ ```
805
+
806
+ The LLM generation stage is the largest contributor to total latency.
807
+
808
+ The measured end-to-end latency in this test was approximately:
809
+
810
+ ```text
811
+ 0.99 seconds
812
+ ```
813
+
814
+ This should not be interpreted as a guaranteed production latency because API/network conditions, hardware, load, and model availability can change.
815
+
816
+ ---
817
+
818
+ # 24. Saved Artifacts
819
+
820
+ The system uses the following main artifacts:
821
+
822
+ ```text
823
+ questions.index
824
+ question_embeddings.npy
825
+ README.md
826
+ gold_set_for_manual_review.xlsx
827
+ ```
828
+
829
+ ## questions.index
830
+
831
+ FAISS vector index containing the question embeddings.
832
+
833
+ ## question_embeddings.npy
834
+
835
+ NumPy array containing the normalized question embeddings.
836
+
837
+ ## gold_set_for_manual_review.xlsx
838
+
839
+ Human-review file used to create the manually verified relevance set.
840
+
841
+ ---
842
+
843
+ # 25. Local Deployment
844
+
845
+ The RAG system can be deployed locally as a Python service.
846
+
847
+ Recommended architecture:
848
+
849
+ ```text
850
+ Frontend
851
+
852
+
853
+ Backend API
854
+
855
+
856
+ Medical RAG Pipeline
857
+
858
+ ├── FAISS
859
+ ├── Sentence Transformer
860
+ ├── Cross Encoder
861
+ └── LLM API
862
+ ```
863
+
864
+ The application should load the embedding model and FAISS index once when the service starts.
865
+
866
+ They should NOT be reloaded for every user request.
867
+
868
+ Example:
869
+
870
+ ```python
871
+ from sentence_transformers import SentenceTransformer, CrossEncoder
872
+ import faiss
873
+ import numpy as np
874
+
875
+ embedder = SentenceTransformer(
876
+ "sentence-transformers/all-MiniLM-L6-v2"
877
+ )
878
+
879
+ reranker = CrossEncoder(
880
+ "cross-encoder/ms-marco-MiniLM-L-6-v2"
881
+ )
882
+
883
+ faiss_index = faiss.read_index(
884
+ "questions.index"
885
+ )
886
+
887
+ question_embeddings = np.load(
888
+ "question_embeddings.npy"
889
+ )
890
+ ```
891
+
892
+ ---
893
+
894
+ # 26. Example API Architecture
895
+
896
+ A backend can expose an endpoint such as:
897
+
898
+ ```http
899
+ POST /api/rag/query
900
+ ```
901
+
902
+ Request:
903
+
904
+ ```json
905
+ {
906
+ "question": "What are the symptoms of diabetes?"
907
+ }
908
+ ```
909
+
910
+ Response:
911
+
912
+ ```json
913
+ {
914
+ "answer": "...",
915
+ "evidence": [
916
+ {
917
+ "doc_id": 4793,
918
+ "similarity": 0.91,
919
+ "rerank_score": 8.21
920
+ }
921
+ ]
922
+ }
923
+ ```
924
+
925
+ This makes the RAG pipeline independent from the frontend.
926
+
927
+ ---
928
+
929
+ # 27. Recommended Project Structure
930
+
931
+ ```text
932
+ medical-rag/
933
+
934
+ ├── README.md
935
+
936
+ ├── artifacts/
937
+ │ ├── questions.index
938
+ │ └── question_embeddings.npy
939
+
940
+ ├── src/
941
+ │ ├── retrieval.py
942
+ │ ├── reranker.py
943
+ │ ├── query_expansion.py
944
+ │ ├── evidence.py
945
+ │ ├── confidence_gate.py
946
+ │ ├── generation.py
947
+ │ └── rag_pipeline.py
948
+
949
+ ├── api/
950
+ │ └── app.py
951
+
952
+ ├── evaluation/
953
+ │ ├── retrieval_evaluation.py
954
+ │ ├── gate_evaluation.py
955
+ │ └── gold_set_evaluation.py
956
+
957
+ ├── data/
958
+ │ └── gold_set_for_manual_review.xlsx
959
+
960
+ └── requirements.txt
961
+ ```
962
+
963
+ ---
964
+
965
+ # 28. Installation
966
+
967
+ Install the main dependencies:
968
+
969
+ ```bash
970
+ pip install sentence-transformers faiss-cpu numpy pandas openpyxl
971
+ ```
972
+
973
+ For Groq-based generation:
974
+
975
+ ```bash
976
+ pip install groq
977
+ ```
978
+
979
+ ---
980
+
981
+ # 29. Environment Variables
982
+
983
+ Never hard-code API keys inside source code.
984
+
985
+ Set:
986
+
987
+ ```bash
988
+ GROQ_API_KEY=your_api_key_here
989
+ ```
990
+
991
+ Python:
992
+
993
+ ```python
994
+ import os
995
+
996
+ api_key = os.environ["GROQ_API_KEY"]
997
+ ```
998
+
999
+ ---
1000
+
1001
+ # 30. Security
1002
+
1003
+ The API key used during development must not be committed to GitHub or Hugging Face.
1004
+
1005
+ Recommended practice:
1006
+
1007
+ ```text
1008
+ .env
1009
+ ```
1010
+
1011
+ and:
1012
+
1013
+ ```text
1014
+ .gitignore
1015
+ ```
1016
+
1017
+ Example `.gitignore`:
1018
+
1019
+ ```text
1020
+ .env
1021
+ __pycache__/
1022
+ *.pyc
1023
+ .ipynb_checkpoints/
1024
+ ```
1025
+
1026
+ If an API key has already been exposed publicly, revoke it and generate a new one.
1027
+
1028
+ ---
1029
+
1030
+ # 31. Limitations
1031
+
1032
+ This system has several important limitations.
1033
+
1034
+ ### 1. Medical domain limitations
1035
+
1036
+ The knowledge base does not necessarily cover every medical condition or clinical scenario.
1037
+
1038
+ ### 2. Retrieval limitations
1039
+
1040
+ A semantically similar document is not necessarily an appropriate answer.
1041
+
1042
+ ### 3. Reranker limitations
1043
+
1044
+ The current Cross-Encoder was not specifically trained on this medical dataset.
1045
+
1046
+ ### 4. Gold-set limitations
1047
+
1048
+ The manually reviewed gold set is still small.
1049
+
1050
+ ### 5. Evaluation limitations
1051
+
1052
+ Some evaluation metrics rely on duplicate Question entries rather than a fully manually annotated relevance dataset.
1053
+
1054
+ ### 6. LLM limitations
1055
+
1056
+ The generated answer depends on the quality of the retrieved evidence.
1057
+
1058
+ ### 7. Clinical safety
1059
+
1060
+ The system should not be used for diagnosis, emergency decisions, prescribing medication, or personalized treatment.
1061
+
1062
+ ---
1063
+
1064
+ # 32. Future Improvements
1065
+
1066
+ Recommended next steps:
1067
+
1068
+ ```text
1069
+ 1. Complete the manual gold-set annotation.
1070
+
1071
+ 2. Increase the number of manually reviewed questions.
1072
+
1073
+ 3. Train or evaluate a medical-domain reranker.
1074
+
1075
+ 4. Re-evaluate the Cross-Encoder using the manual gold set.
1076
+
1077
+ 5. Tune the confidence gate using a larger validation set.
1078
+
1079
+ 6. Add citation/source metadata.
1080
+
1081
+ 7. Add automated regression tests.
1082
+
1083
+ 8. Add monitoring for retrieval failures.
1084
+
1085
+ 9. Add API-level authentication and rate limiting.
1086
+
1087
+ 10. Deploy the RAG pipeline behind a REST API.
1088
+
1089
+ 11. Add a frontend chat interface.
1090
+
1091
+ 12. Evaluate hallucination/faithfulness separately from retrieval quality.
1092
+ ```
1093
+
1094
+ ---
1095
+
1096
+ # 33. Evaluation Summary
1097
+
1098
+ | Metric | Result |
1099
+ |---|---:|
1100
+ | Knowledge Base Size | 16,384 records |
1101
+ | Self-Retrieval Top-1 | 100% |
1102
+ | Retrieval Recall@1 | 69.0% |
1103
+ | Retrieval Recall@3 | 85.1% |
1104
+ | Retrieval Recall@5 | 89.9% |
1105
+ | Retrieval Recall@10 | 95.9% |
1106
+ | Retrieval Precision@1 | 100% |
1107
+ | Retrieval F1@1 | 74.5% |
1108
+ | Retrieval MRR | 1.000 |
1109
+ | Category Recall + Reranker | 98% |
1110
+ | Category Recall Retrieval Only | 97% |
1111
+ | Confidence Gate Accuracy | 88% |
1112
+ | Example End-to-End Latency | 0.993 sec |
1113
+
1114
+ > The evaluation numbers above are specific to the current experimental setup and should not be interpreted as general medical accuracy.
1115
+
1116
+ ---
1117
+
1118
+ # 34. Responsible Use
1119
+
1120
+ This project provides general medical information retrieval and generation.
1121
+
1122
+ It is not:
1123
+
1124
+ - A diagnostic tool
1125
+ - A clinical decision-support system
1126
+ - A replacement for a physician
1127
+ - A prescription system
1128
+ - An emergency medical service
1129
+
1130
+ Users should consult qualified healthcare professionals for medical decisions.
1131
+
1132
+ ---
1133
+
1134
+ # 35. Citation and References
1135
+
1136
+ ### Sentence Transformers
1137
+
1138
+ https://www.sbert.net/
1139
+
1140
+ ### FAISS
1141
+
1142
+ https://github.com/facebookresearch/faiss
1143
+
1144
+ ### Cross-Encoder
1145
+
1146
+ https://www.sbert.net/examples/applications/cross-encoder/README.html
1147
+
1148
+ ### Hugging Face Model Cards
1149
+
1150
+ https://huggingface.co/docs/hub/en/model-cards
1151
+
1152
+ ### Hugging Face Model Release Checklist
1153
+
1154
+ https://huggingface.co/docs/hub/en/model-release-checklist
1155
+
1156
+ ---
1157
+
1158
+ # 36. Project Status
1159
+
1160
+ ```text
1161
+ Status: Research / Prototype
1162
+
1163
+ Retrieval: Implemented
1164
+ FAISS: Implemented
1165
+ Query Expansion: Implemented
1166
+ Cross-Encoder Reranking: Implemented
1167
+ Evidence Deduplication: Implemented
1168
+ Confidence Gate: Implemented
1169
+ LLM Generation: Implemented
1170
+ Evaluation: Implemented
1171
+ Latency Measurement: Implemented
1172
+ Manual Gold Set: In Progress
1173
+ Production Deployment: Future Work
1174
+ ```
1175
+
1176
+ ---
1177
+
1178
+ # 37. Final Note
1179
+
1180
+ The main objective of this project is not simply to generate medical answers.
1181
+
1182
+ The goal is to build a RAG system that:
1183
+
1184
+ ```text
1185
+ Retrieves evidence
1186
+
1187
+ Ranks evidence
1188
+
1189
+ Checks confidence
1190
+
1191
+ Generates from evidence
1192
+
1193
+ Provides traceable document IDs
1194
+ ```
1195
+
1196
+ This design allows the system to be evaluated as a retrieval pipeline independently from the LLM generation layer.