Files
2026-11-02 10:46:09 +07:00

127 lines
9.8 KiB
Markdown

# Pertemuan 10: RAG Part 1 - Embedding & Vector Database
Repositori ini berisi implementasi praktikum **Retrieval-Augmented Generation (RAG) Bagian 1** untuk mata kuliah Kecerdasan Buatan (*Artificial Intelligence*). Proyek ini berfokus pada tahapan krusial sebelum generasi teks oleh LLM, yaitu: pemotongan teks (*chunking*), pembuatan *vector embedding*, penyimpanan ke dalam *vector database* (**ChromaDB**), pencarian semantik (*semantic search*), hingga evaluasi performa pengambilan dokumen menggunakan metrik **$\text{Hit}@k$**.
## 4. Penjelasan Kode (`rag_lab_runner.py`)
Skrip `rag_lab_runner.py` dibagi menjadi beberapa modul fungsional:
1. **Fungsi Utilitas (`baca_pdf` & `potong`):**
- `baca_pdf(path)`: Membaca seluruh halaman file PDF dan menggabungkannya menjadi satu *string* utuh.
- `potong(teks, ukuran, tumpang)`: Memotong teks menjadi bagian-bagian (*chunks*) berukuran tetap (`ukuran`) dengan pergeseran karakter sebesar $\text{step} = \text{ukuran} - \text{tumpang}$ untuk menjaga konteks antarpotongan (*overlap*).
2. **Lab 1 (`run_lab1`):**
- Mengekstrak teks dari salah satu dokumen (`Code of Conduct.pdf`) dan membandingkan jumlah *chunk* yang dihasilkan pada tiga konfigurasi: `(500, 50)`, `(1000, 100)`, dan `(1500, 150)`.
- Melakukan inspeksi pemotongan kalimat (*cutoff check*) dengan memeriksa apakah suatu *chunk* diawali huruf kecil (`starts_mid`) atau tidak diakhiri tanda baca akhir kalimat `.!?` (`ends_mid`).
3. **Lab 2 (`setup_collection` & `run_lab2`):**
- Membuat koleksi vektor di ChromaDB (`pedoman_500` dan `pedoman_1000`) menggunakan metrik *cosine distance*.
- Menguji pencarian menggunakan **5 kueri standar** (mengambil *top-3* tetapi menampilkan hasil teratas beserta skor jaraknya) dan **2 kueri parafrase** untuk menguji pemahaman semantik model ketika kata kunci eksak tidak digunakan.
4. **Lab 3 (`hit_at_k` & `run_lab3`):**
- Mengevaluasi performa sistem menggunakan **15 pasangan kueri dan kata kunci target (`TEST_SET`)**.
- Menghitung nilai $\text{Hit}@k$ untuk $k \in \{1, 3, 5\}$ dengan rumus:
$$\text{Hit}@k = \frac{\text{Jumlah kueri yang kata kuncinya ditemukan pada top-}k\text{ chunks}}{\text{Total kueri pengujian } (N = 15)}$$
- Menampilkan analisis kegagalan (*Miss Analysis*) pada kueri yang gagal ditemukan di urutan pertama ($k=1$).
---
## 5. Hasil Eksperimen & Pembahasan Output
Berikut adalah hasil eksekusi program di Windows PowerShell beserta analisis untuk masing-masing laboratorium.
---
### Lab 1: Chunking Experiment
Pada tahap ini, program membaca file `Code of Conduct.pdf` yang memiliki total panjang **2.015 karakter**.
![Output Lab 1 - Bagian Awal](Screenshot%20(258).png)
*Gambar 1: Pembacaan karakter awal PDF, perbandingan jumlah chunk pada 3 konfigurasi, dan sampel ukuran 500.*
![Output Lab 1 - Sampel Chunk 500, 1000, dan 1500](Screenshot%20(259).png)
*Gambar 2: Pemeriksaan kalimat terpotong (cutoff check) pada sampel ukuran 500, 1000, dan 1500.*
![Output Lab 1 - Detail Akhir Sampel 1500](Screenshot%20(260).png)
*Gambar 3: Detail akhir pemeriksaan sampel pada konfigurasi chunk 1500.*
#### Analisis Hasil Lab 1:
1. **Perbandingan Jumlah Chunk:**
- **Ukuran 500 (overlap 50):** Menghasilkan **5 chunks**.
- **Ukuran 1000 (overlap 100):** Menghasilkan **3 chunks**.
- **Ukuran 1500 (overlap 150):** Menghasilkan **2 chunks**.
- Semakin kecil ukuran *chunk*, semakin banyak jumlah potongan dokumen yang disimpan di database, namun informasi di tiap *chunk* menjadi lebih spesifik.
2. **Fenomena Kalimat Terpotong (*Truncated Sentences*):**
- Karena metode yang digunakan adalah *fixed-size character chunking* (memotong tepat pada hitungan karakter ke-$N$ tanpa memedulikan batas kata atau kalimat), hampir seluruh sampel memiliki status `Ends mid-sentence=True` dan sebagian besar `Starts mid-sentence=True`.
- Contoh nyata terlihat pada **Chunk Size 500 Sample 1** yang terpotong tepat di tengah kata: `...Employees are ex`, serta **Sample 3** yang diawali potongan kata `st...` dan diakhiri `...softwar`.
- **Solusi Mitigasi:** Penggunaan *overlap* (`tumpang`) sebesar 10% sangat membantu agar kata atau kalimat yang terbelah di ujung suatu *chunk* tetap utuh di bagian awal *chunk* berikutnya.
---
### Lab 2: Build Index & Search
Pada Lab 2, pencarian dilakukan terhadap koleksi `pedoman_500` (ukuran *chunk* 500 karakter). Jarak dihitung menggunakan *Cosine Distance* (semakin kecil nilai `distance` mendekati $0$, semakin mirip/relevan dokumen tersebut dengan kueri).
![Output Lab 2 - Standard & Paraphrased Queries](Screenshot%20(261).jpg)
*Gambar 4: Hasil pengujian 5 kueri standar dan 2 kueri parafrase pada koleksi ChromaDB.*
#### Analisis Hasil Lab 2:
1. **Pengujian 5 Kueri Standar:**
Seluruh kueri standar berhasil memetakan pencarian ke dokumen PDF yang tepat dengan jarak *cosine* yang rendah ($0.3113$ hingga $0.4653$):
- Kueri panjang *password* $\rightarrow$ `Data Protection Policy.pdf | chunk 2` (`distance: 0.3603`), langsung memuat jawaban *"at least 12 cha[racters]"*.
- Kueri pelecehan & diskriminasi $\rightarrow$ `Code of Conduct.pdf | chunk 1` (`distance: 0.3113` - kemiripan tertinggi).
- Kueri tempat penyimpanan data elektronik $\rightarrow$ `Data Protection Policy.pdf | chunk 1` (`distance: 0.3670`).
2. **Pengujian 2 Kueri Parafrase (Semantic vs Keyword):**
- **Kueri 1:** *"Can I log in using a free cafe internet connection?"* (Target maksud: Kebijakan kerja jarak jauh / penggunaan VPN di Wi-Fi publik).
- **Hasil:** Mengambil `Remote Work Policy.pdf | chunk 3` (`distance: 0.6669`). Meskipun di kueri menggunakan istilah *"free cafe internet"*, model embedding memahami konteksnya berkaitan dengan *remote work*.
- **Kueri 2:** *"What is the penalty if I take a second job or outside gig?"* (Target maksud: Konflik kepentingan / sanksi pekerjaan sampingan).
- **Hasil:** Mengambil `Code of Conduct.pdf | chunk 4` (`distance: 0.6437`) yang membahas sanksi mulai dari pelatihan wajib hingga pemutusan hubungan kerja (*termination of employment*).
- Skor jarak pada kueri parafrase ($\approx 0.64 - 0.66$) lebih besar dibandingkan kueri standar ($\approx 0.31 - 0.46$) karena tidak adanya kesamaan leksikal (kata per kata), namun pencarian vektor tetap mampu mengarahkan ke dokumen yang berkaitan.
---
### Lab 3: Measure Hit@k Evaluation
Pada Lab 3, dilakukan pengujian kuantitatif menggunakan 15 kueri (`TEST_SET`) untuk membandingkan performa antara `Collection (size=500)` dan `Collection (size=1000)`.
![Output Lab 3 - Hit@k Evaluation & Miss Analysis](Screenshot%20(262).png)
*Gambar 5: Tabel hasil evaluasi metrik Hit@1, Hit@3, Hit@5 beserta analisis kegagalan (Miss Analysis) pada k=1.*
#### Tabel Ringkasan Evaluasi $\text{Hit}@k$
| Collection | $\text{Hit}@1$ | $\text{Hit}@3$ | $\text{Hit}@5$ |
| :--- | :---: | :---: | :---: |
| **Collection (`size=500`)** | $0.80$ ($12/15$) | **$1.00$ ($15/15$)** | **$1.00$ ($15/15$)** |
| **Collection (`size=1000`)** | $0.80$ ($12/15$) | $0.93$ ($14/15$) | $0.93$ ($14/15$) |
#### Analisis Hasil Lab 3:
1. **Perbandingan Ukuran Chunk (`500` vs `1000`):**
- Pada **$k=1$**, kedua koleksi sama-sama mencapai akurasi **$0.80$ ($80\%$)**, artinya 12 dari 15 pertanyaan langsung menemukan jawaban di urutan paling atas (*top-1*).
- Pada **$k=3$ dan $k=5$**, koleksi **`size=500` unggul mutlak dengan skor sempurna $1.00$ ($100\%$)**, sedangkan `size=1000` tertahan di **$0.93$ ($93\%$)**.
- **Mengapa `size=500` lebih baik?** *Chunk* yang lebih kecil memiliki representasi vektor (embedding) yang lebih terfokus pada satu topik spesifik. Pada `size=1000`, satu *chunk* memuat banyak sub-bab sekaligus sehingga makna vektornya menjadi "tercampur" (*diluted embedding*), yang menyebabkan informasi spesifik lebih sulit menempati peringkat teratas.
2. **Analisis Kegagalan (*Miss Analysis*) pada `size=500` saat $k=1$:**
Terdapat 3 kueri yang meleset di peringkat ke-1 (namun berhasil ditemukan ketika cakupan diperluas ke $k=3$):
- **Miss 1:** `'What is required before connecting to public Wi-Fi?'` (Target: `'VPN'`)
- *Penyebab:* Top-1 justru mengambil `Data Protection Policy.pdf` tentang akses data umum, karena kata *"connecting"* dan *"required"* memiliki kedekatan semantik umum dengan aturan akses data. Potongan tentang VPN berada di urutan ke-2 atau ke-3.
- **Miss 2:** `'What should be done with sensitive paper documents?'` (Target: `'shredded'`)
- *Penyebab:* Kata *"sensitive ... documents"* sangat dominan beririsan dengan bagian awal aturan penyimpanan data di `Data Protection Policy.pdf` (urutan ke-1), sementara instruksi penghancuran kertas (*shredded*) berada di *chunk* selanjutnya.
- **Miss 3:** `'What disciplinary actions can follow policy violations?'` (Target: `'termination'`)
- *Penyebab:* Kueri ini mengambil `Code of Conduct.pdf | chunk 1` tentang perilaku profesional di urutan pertama, sedangkan kata kunci `'termination'` berada di bagian akhir dokumen (`chunk 4`).
---
## 6. Kesimpulan
1. **Trade-off Ukuran Chunk:** Metode *fixed-size chunking* dengan ukuran yang lebih kecil (`chunk_size=500`, `overlap=50`) memberikan presisi pengambilan (*retrieval*) yang lebih tinggi ($\text{Hit}@3 = 1.00$) dibandingkan ukuran besar (`chunk_size=1000`, $\text{Hit}@3 = 0.93$) pada dokumen kebijakan yang padat informasi.
2. **Kelemahan Fixed-Size Splitting:** Pemotongan berbasis jumlah karakter murni sering membelah kata dan kalimat di tengah jalan (`Ends mid-sentence=True`). Untuk pengembangan selanjutnya, metode ini dapat ditingkatkan menggunakan *Recursive Character Text Splitter* (memotong berdasarkan paragraf `\n\n`, kalimat `. `, lalu spasi).
3. **Pentingnya Nilai $k$ pada RAG:** Mengandalkan hanya 1 dokumen teratas ($k=1$) berisiko kehilangan konteks penting (akurasi hanya $80\%$). Dengan mengatur parameter pengambilan ke $k=3$ (`n_results=3`), sistem berhasil mencapai cakupan informasi $100\%$ untuk diteruskan ke *Large Language Model* (LLM).