# Artifact Plan: Optimasi Ekstrim "Bilingual Mega-Sentence" & Pipeline Concurrency (V2 - Hybrid Local-Cloud)

## 1. Judul
**Blueprint Optimasi Kinerja Tinggi V2: Pemisahan CPU-I/O, Bounded Semaphore, dan Local Retrieval Embedding**

## 2. Tanggal
Minggu, 10 Mei 2026

## 3. Deskripsi
Dokumen ini merupakan cetak biru (*blueprint*) revisi teknis untuk mengoptimalkan kinerja *ingestion pipeline* ("Small-to-Big Retrieval") pada `backend-sre-(Knowledge Extractor)`. Cetak biru ini dirancang khusus untuk mengakomodasi keterbatasan spesifikasi perangkat keras (RAM/CPU rendah) serta mengeliminasi masalah kuota dan penolakan layanan (Error 429 & 401) dari penyedia API Cloud. Arsitektur bergeser dari pemrosesan Cloud murni menjadi hibrida: komputasi ringan dilakukan di *local* (CPU), sementara penalaran logis diserahkan ke *Cloud* secara terkontrol.

## 4. Latar Belakang
Pada eksekusi sebelumnya, *pipeline* mengalami lumpuh total (*deadlock* dan *crash*) akibat tiga hal:
1. **Ledakan API Call:** Ratusan *child chunks* dikirimkan ke API Cloud untuk di-*embed*, memicu batas *Rate Limit* (429 Too Many Requests).
2. **Jebakan Python GIL & OOM:** Pemrosesan banyak dokumen raksasa secara paralel murni memicu rebutan inti CPU (*context switching*) dan ancaman kehabisan RAM (*Out of Memory*).
3. **Ketidakstabilan Pihak Ketiga:** Penggunaan pelbagai *endpoint* (seperti OpenRouter) menyebabkan kompleksitas otentikasi.

## 5. Metodologi
Pendekatan optimasi ini diwujudkan melalui dua lapisan pertahanan (Dual-Layer Defense):
1.  **Lapis 1 - Perlindungan Hardware (CPU vs I/O Split):** Memisahkan secara keras antara pekerjaan "otot" dan "menunggu". *Parsing* PDF (`pymupdf4llm`) wajib berjalan satu per satu (Sekuensial) untuk menjaga RAM. Sebaliknya, proses *Retrieval* dan panggilan API LLM dimasukkan ke dalam `ThreadPoolExecutor` (Asinkronus).
2.  **Lapis 2 - Perlindungan API (Global Semaphore & Tenacity):** Di dalam fase asinkronus, panggilan ke API LLM dijaga oleh `threading.BoundedSemaphore`. Jika ada 3 dokumen yang berjalan bersamaan, Semaphore memastikan hanya sejumlah *N* (misal 1 atau 2) yang diizinkan menembak API Alibaba DashScope pada detik yang sama. Kegagalan sisa ditangani dengan mundur eksponensial (Exponential Backoff) menggunakan pustaka `tenacity`.
3.  **Local Embedding Shift:** Memutus rantai jaringan untuk tugas perbandingan *chunk* harian dengan menurunkan komputasi tersebut murni ke dalam pustaka lokal `sentence-transformers`.

## 6. Asumsi & Detail Requirements

Semua spesifikasi kunci diatur ulang dalam tabel berikut secara ketat:

| Komponen Sistem | Alat / Model yang Digunakan | Spesifikasi & Deskripsi |
| :--- | :--- | :--- |
| **Model Ekstraksi (LLM)** | `qwen3-30b-a3b-thinking-2507` | Dihosting **Eksklusif melalui Alibaba DashScope** (`https://dashscope-intl.aliyuncs.com/compatible-mode/v1`). Dilarang keras menggunakan *endpoint* lain. |
| **Model Embedding Retrieval (Lokal)** | `sentence-transformers/all-MiniLM-L6-v2` | **Spesifikasi Hardware:**<br>• VRAM/GPU: **Tidak Wajib (Zero GPU)**<br>• RAM Minimal: **~300 MB - 500 MB**<br>• Ukuran Disk: **~90 MB**<br>• Tipe Komputasi: PyTorch CPU Tensor.<br>• Output: 384 Dimensi.<br>**Fungsi:** HANYA digunakan untuk mencocokkan *query* pengguna dengan ratusan *Child Chunks* secara luring (*offline*). |
| **Model Embedding Vektor DB (Cloud)** | `text-embedding-3-small` | Dihosting oleh OpenAI. Diubah menjadi 1024 Dimensi via parameter API. Digunakan **HANYA** untuk menyimpan nilai akhir (Node Pilar) ke dalam Neo4j. |
| **Pustaka Pemulihan (Retry)** | `tenacity` | Dekorator Python untuk memastikan kode tidak *crash*. **Konfigurasi Waktu:** Menggunakan `wait_exponential_jitter` dengan waktu tunggu awal (initial) 2 detik, maksimal tunggu 60 detik, dan maksimal percobaan (stop) 10 kali. *Jitter* memberikan selang waktu acak agar antrean tidak bertabrakan ulang. |
| **Penjaga Konkurensi API** | `threading.BoundedSemaphore` | Mencegah *thread* memanggil API secara simultan di luar batas wajar (mencegah *DDoS* dari server sendiri ke API Alibaba). |
| **Manajemen Database (Raw Chunks)** | *Background Worker Queue* (Supabase) | *Thread* independen yang mengambil data dari keranjang (*queue*) dan mengunggahnya diam-diam di *background*, diakhiri dengan *Graceful Shutdown*. |

## 7. Keputusan
1.  **Dilarang Paralel pada Parsing PDF:** Eksekusi `pymupdf4llm` wajib berada dalam blok sinkronus (*Main Thread*) untuk mengakomodir spesifikasi server yang rendah.
2.  **Pemecatan API Cloud untuk Retrieval:** Ketergantungan *embedding* API Cloud pada ratusan *chunk* dibatalkan. Diganti penuh ke *Library* Lokal (SBERT).
3.  **Penyesuaian Indeks Vektor Neo4j:** Mengingat arsitektur kini hibrida, skrip `setup_indexes.py` akan mengubah ruang pencarian (*search space*) menjadi 384D bagi sistem pencarian internal, jika suatu saat ingin menyimpan *raw chunks* secara semantik. Namun Node Pilar utama di Neo4j tetap menggunakan format 1024D (OpenAI). *(Sesuai desain integrasi)*.

## 8. Alur Diagram
```mermaid
flowchart TD
    subgraph MainThread ["Lapis 1: Main Thread (Sekuensial CPU-Bound)"]
        A[Daftar PDF Files] --> B[Ekstrak Markdown - pymupdf4llm]
        B --> C[Pembentukan Spatial Chunk]
        C -->|Lempar Queue| D[(Supabase Background Worker)]
    end

    subgraph IOBound ["Lapis 2: ThreadPoolExecutor (Paralel I/O-Bound)"]
        B -->|Mulai Asinkron| E[Local Retrieval - all-MiniLM-L6-v2]
        E --> F[Deduplikasi Parent Chunks]
        F --> G{"Global API Semaphore"}
        
        subgraph CloudAPI ["Panggilan Jaringan (Diamankan Tenacity)"]
            G -->|Acquire| H[LLM Pillar Extract - Qwen DashScope]
            H -->|Release| I[Node Embedding - OpenAI 3-small]
            I --> J[Edge Reasoning - Qwen DashScope]
        end
        
        J --> K[(Neo4j AuraDB)]
    end
```

## 9. Struktur Folder (Tree)
Pembaruan ini akan terfokus pada lokasi skrip berikut:
```text
/home/daegir/Documents/PERCOBAAN/backend-sre-(Knowledge Extractor)/
├── requirements.txt             # (TARGET: Tambah 'tenacity' & 'sentence-transformers')
├── scripts/
│   └── setup_indexes.py         # (TARGET: Update Dimensi menjadi 384/1024 sesuai peruntukan)
├── app/
│   └── services/
│       ├── ingestion.py                 # (TARGET: ThreadPool, Semaphore, Tenacity, & Clean DashScope config)
│       └── parser/
│           └── semantic_retriever.py    # (TARGET: Migrasi API ke SBERT Local Model)
└── Markdown/
    └── small-to-big-retrieval/
        ├── Plan/
        │   ├── optimization-concurrency-plan.md     # Versi V1 (Kuno)
        │   └── optimization-concurrency-plan-v2.md  # File dokumen INI (Aktif)
        └── Log-Execution/                           # Untuk pelaporan eksekusi matriks performa
```

## 10. Asumsi
1. Server target memiliki sumber daya komputasi di bawah rata-rata (e.g., < 4 Core, < 8GB RAM). Oleh karena itu, lonjakan memori harus ditahan lewat eksekusi sekuensial pada fase pemrosesan *string* raksasa.
2. Kecepatan lokal (`all-MiniLM-L6-v2`) cukup cepat (di bawah 30 detik untuk ratusan *chunk*) meski tanpa GPU, berkat komputasi Tensor CPU bawaan PyTorch.
3. Kredensial `DASHSCOPE_API_KEY` dan `OPENAI_API_KEY` tersedia valid dengan saldo yang mencukupi untuk menghindari penolakan akses statis (*Arrearage*).

## 11. Konsep Tabel Metriks (End-to-End Industrial Grade)

Untuk memantau performa secara absolut dari awal pembacaan file hingga relasi *Graph* terbangun di Neo4j, keluaran (*output*) terminal akan mengadopsi struktur matriks berikut:
| Metrik Pemantauan | Ekspektasi Sebelum V2 | Ekspektasi Setelah V2 | Status |
| :--- | :--- | :--- | :--- |
| **Stabilitas Parsing (OOM)** | Sering *Crash* jika > 3 PDF paralel | 0% *Crash* (Jalan 1 per 1) | Aman |
| **Waktu Retrieval (Ratusan Chunks)** | > 60 detik (Sering HTTP 429) | 10 - 25 detik (0% Network) | Ekstrem Cepat |
| **Kestabilan LLM Extract** | *Crash* bersamaan karena lonjakan RPS | Rapi & Mengantre (Sistem Bounded Semaphore) | Terkontrol |
```text
=================================================================================================================================
📊 INDUSTRIAL-GRADE PERFORMANCE MONITORING MATRIX (END-TO-END)
=================================================================================================================================
| Nama Dokumen                                  | Status  | Parse | Retrvl | Extract | NodeDB | EdgeGen | Total Waktu | In/Out Tokens |
|-----------------------------------------------|---------|-------|--------|---------|--------|---------|-------------|---------------|
| [Nama Jurnal Dipotong Jika Panjang...]        | Success | 00.00 | 00.00  | 00.00   | 00.00  | 00.00   | 00.00 s     | 000 / 000     |
=================================================================================================================================
* Keterangan: Waktu disajikan dalam hitungan detik (s).
  - Parse   : Waktu baca PDF & ekstraksi Markdown (pymupdf4llm).
  - Retrvl  : Waktu pencarian kemiripan Child Chunks menggunakan Local SBERT (all-MiniLM-L6-v2).
  - Extract : Waktu LLM mengekstrak 5 Pilar (DashScope).
  - NodeDB  : Waktu penyimpanan struktur Node ke Neo4j & Supabase.
  - EdgeGen : Waktu pencarian Vektor Index Neo4j & LLM Reasoning untuk injeksi Edge Graf.
  - Total   : Waktu End-to-End absolut per dokumen.
```

## 12. Konsep Logika
Logika utama sistem sekarang bukan lagi mengenai "Seberapa Cepat Bisa Mengirim *Request*", melainkan **"Bagaimana Mendistribusikan Komputasi Agar Tidak Bertabrakan"**.
1. **Delegasi Sempurna:** *CPU* mengurus PDF dan *Embedding* Lokal. *Internet* mengurus LLM Reasoning dan Vektor DB Node.
2. **Katup Pengaman (*Valve*):** *BoundedSemaphore* memastikan bahwa meskipun ada 10 *Thread* siap jalan, aliran menuju API DashScope tetap terbatas layaknya corong sempit yang terukur.
3. **Pemaafan Ekstrem (*Forgiveness*):** Jika *Rate Limit* secara teknis masih tertembus, `tenacity` dengan metode `wait_exponential_jitter(initial=2, max=60)` memastikan antrean mundur dengan waktu tunggu acak antara 2 hingga maksimal 60 detik sebelum mencoba lagi, sehingga mencegah tabrakan *request* yang berulang.

## 13. Langkah Implementasi
1. Membersihkan sisa-sisa impor dan konfigurasi pihak ketiga (OpenRouter, Gemini) dari `.env` dan kode dasar `ingestion.py`.
2. Melakukan modifikasi pada `semantic_retriever.py` agar murni hanya mengimpor dan menjalankan `sentence-transformers` secara luring (*offline*).
3. Mendefinisikan ulang *Global Semaphore* di luar batasan perulangan agar dapat diakses bersamaan oleh semua *Worker Thread*.
4. Mengimplementasikan `ThreadPoolExecutor` di `ingestion.py` *hanya* setelah proses ekstrak Markdown dari PDF tersebut usai secara sekuensial.
5. Menjalankan uji coba dengan matriks *monitoring industrial-grade* untuk memastikan latensi Retrieval menyusut drastis.

## 14. Tabel Eksekusi Task

| Check Box | Fase | Task | Detail Task | Deskripsi | Acceptance Criteria |
| :---: | :---: | :---: | :--- | :--- | :--- |
| [x] | 1 - *Cleanup* | Purifikasi Modul | Hapus sisa kode `OpenRouter` & `Gemini` | Membersihkan `.env` dan logika inisialisasi API di `ingestion.py` yang mengarah pada provider yang dilarang. | Kode 100% menunjuk ke `dashscope-intl.aliyuncs.com` untuk LLM dan OpenAI untuk DB Embed. |
| [x] | 1 - Dependensi | Pasang Modul Pendukung | Update `requirements.txt` | Memastikan `tenacity` dan `sentence-transformers` terdaftar secara kokoh di struktur virtual environment. | `pip install` berhasil mengunduh model MiniLM. |
| [x] | 2 - Transformasi *Retrieval* | *Rewrite* `semantic_retriever.py` | Substitusi API ke SBERT | Mengganti mekanisme `request.post()` atau `client.embeddings` dengan komputasi tensor lokal dari model `all-MiniLM-L6-v2`. | Fungsi `find_top_k_parents` tidak lagi mengandalkan koneksi internet. |
| [x] | 3 - Stabilisasi Konkurensi | Refaktor `ingestion.py` (Lapis 1) | Implementasi Sekuensial - Asinkronus | Memindahkan eksekusi dari fungsi-fungsi berat jaringan (Retrieval, LLM, Inject) ke dalam `executor.submit()`, tetapi mempertahankan `pymupdf4llm` di luar blok tersebut. | *Parsing* berjalan berurutan, *Retrieval* & LLM berjalan asinkronus (tumpang tindih). |
| [x] | 4 - Penguncian Jaringan | Implementasi Semaphore | Pasang `BoundedSemaphore` & `Tenacity` | Menyisipkan pengunci pada setiap fungsi yang menembak API DashScope / OpenAI untuk meredam risiko HTTP 429. | Tidak ada ledakan pemanggilan (*request storm*) saat >3 *worker* berjalan. |
| [x] | 5 - Verifikasi | Uji Coba Kinerja Ekstrem | Uji pemrosesan PDF massal | Mengeksekusi ulang `ingestion.py` dengan dokumen berat untuk menguji efisiensi RAM dan keandalan Semaphore. | Eksekusi menyelesaikan seluruh relasi graf tanpa macet (*hanging*) atau *crash*. |
| [x] | 6 - Dokumentasi | Finalisasi Log Eksekusi | Buat laporan matriks performa | Menyusun catatan akhir (waktu eksekusi, *bottleneck* tersisa, konsumsi token) di folder log. | Log `optimization_concurrency_log.md` (atau serupa) terbentuk dengan metrik *industrial-grade*. |