79 lines
4.3 KiB
Python
79 lines
4.3 KiB
Python
from main import koleksi_kecil, koleksi_besar
|
||
|
||
# Lab 3 — 15 pasangan (pertanyaan, kata/frasa kunci yang HARUS ada di chunk jawaban yang benar)
|
||
UJI = [
|
||
("Apa syarat cuti akademik?", "cuti akademik"),
|
||
("Berapa batas kehadiran untuk ujian?", "75 persen"),
|
||
("Berapa maksimal cuti akademik selama masa studi?", "2 semester"),
|
||
("Kapan batas pengajuan cuti akademik dilakukan?", "2 minggu"),
|
||
("Berapa SKS maksimal jika IP semester sebelumnya 3.20?", "24 SKS"),
|
||
("Berapa SKS minimal untuk kelulusan program sarjana?", "144 SKS"),
|
||
("Apa syarat IPK minimal untuk lulus program sarjana?", "2.00"),
|
||
("Berapa lama masa studi maksimal program sarjana?", "14 semester"),
|
||
("Berapa SKS minimal yang harus ditempuh untuk mengambil skripsi?", "110 SKS"),
|
||
("Berapa syarat nilai minimal mata kuliah Metodologi Penelitian?", "nilai C"),
|
||
("Berapa kali bimbingan minimal sebelum sidang skripsi?", "8 kali"),
|
||
("Apa sanksi bagi mahasiswa yang melakukan kecurangan ujian?", "nilai E"),
|
||
("Berapa lama waktu ujian susulan dapat diajukan setelah jadwal?", "3 hari"),
|
||
("Berapa nilai minimal untuk mendapatkan predikat Cum Laude?", "3.51"),
|
||
("Berapa persentase maksimal kemiripan turnitin untuk naskah skripsi?", "20 persen"),
|
||
]
|
||
|
||
|
||
def hit_at_k(uji, k=3, target_koleksi=koleksi_kecil):
|
||
if not uji:
|
||
return 0.0
|
||
benar = 0
|
||
for pertanyaan, kunci in uji:
|
||
docs = target_koleksi.query(query_texts=[pertanyaan], n_results=k)["documents"][0]
|
||
if any(kunci.lower() in d.lower() for d in docs):
|
||
benar += 1
|
||
return benar / len(uji)
|
||
|
||
|
||
def tampilkan_detail_gagal(uji, k, target_koleksi, nama_koleksi):
|
||
gagal = []
|
||
for pertanyaan, kunci in uji:
|
||
docs = target_koleksi.query(query_texts=[pertanyaan], n_results=k)["documents"][0]
|
||
if not any(kunci.lower() in d.lower() for d in docs):
|
||
gagal.append((pertanyaan, kunci))
|
||
if gagal:
|
||
print(f"\nPertanyaan yang gagal pada {nama_koleksi} (Hit@{k}):")
|
||
for p, kw in gagal:
|
||
print(f" - {p} (kunci: '{kw}')")
|
||
else:
|
||
print(f"\nSemua pertanyaan berhasil ditemukan pada {nama_koleksi} untuk Hit@{k}!")
|
||
|
||
|
||
KESIMPULAN = """
|
||
KESIMPULAN EVALUASI (LAB 3):
|
||
1. Ukuran chunk kecil (500 karakter) umumnya menghasilkan Hit@1 yang lebih presisi untuk pertanyaan spesifik (seperti angka SKS atau batas persentase), karena vektor embedding tidak terdilusi oleh topik lain di dalam satu chunk yang terlalu panjang.
|
||
2. Sebaliknya, ukuran chunk besar (1500 karakter) unggul pada Hit@3 dan Hit@5 ketika kata kunci jawaban berada agak jauh dari kalimat topik utamanya, namun rentan menurunkan akurasi Hit@1 karena satu chunk menggabungkan beberapa sub-pasal sekaligus.
|
||
3. Kegagalan retrieval biasanya terjadi pada pertanyaan yang jawabannya terpotong tepat di batas chunk (boundary split) atau pertanyaan yang menggunakan angka/istilah singkat yang mirip antar-pasal (misalnya angka semester atau SKS).
|
||
4. Solusi untuk meningkatkan performa di proyek RAG adalah menggunakan chunking berbasis struktur kalimat/paragraf dengan ukuran moderat (500–800 karakter) dan overlap 10–20% serta mengambil k=3 hingga k=5 chunk teratas.
|
||
""".strip()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
if koleksi_kecil.count() == 0 or koleksi_besar.count() == 0:
|
||
print("Koleksi evaluasi masih kosong. Jalankan `python main.py` terlebih dahulu setelah mengisi folder `dokumen/`.")
|
||
else:
|
||
print("=" * 70)
|
||
print("LAB 3 — EVALUASI HIT@K PADA DUA UKURAN CHUNK BERBEDA")
|
||
print("=" * 70)
|
||
print(f"Jumlah pertanyaan uji: {len(UJI)}\n")
|
||
print(f"{'Metrik':<10} | {'Chunk 500 (Overlap 75)':<25} | {'Chunk 1500 (Overlap 225)':<25}")
|
||
print("-" * 66)
|
||
for k in (1, 3, 5):
|
||
skor_500 = hit_at_k(UJI, k=k, target_koleksi=koleksi_kecil)
|
||
skor_1500 = hit_at_k(UJI, k=k, target_koleksi=koleksi_besar)
|
||
print(f"Hit@{k:<6} | {skor_500:<25.2f} | {skor_1500:<25.2f}")
|
||
|
||
tampilkan_detail_gagal(UJI, k=1, target_koleksi=koleksi_kecil, nama_koleksi="Chunk 500")
|
||
tampilkan_detail_gagal(UJI, k=1, target_koleksi=koleksi_besar, nama_koleksi="Chunk 1500")
|
||
|
||
print("\n" + "=" * 70)
|
||
print(KESIMPULAN)
|
||
print("=" * 70)
|
||
|