Membangun sistem "chat dengan dokumen" tampak sederhana di permukaan, namun pengembang yang mencoba mengimplementasikannya di lingkungan produksi akan segera menyadari kompleksitas tersembunyi di baliknya. Seorang pengembang baru-baru ini menyelesaikan proyek myRAG — sebuah tumpukan RAG (Retrieval-Augmented Generation) sepenuhnya self-hosted yang mencakup backend FastAPI, frontend React, serta tiga mesin penyimpanan: Qdrant untuk vektor, PostgreSQL untuk metadata, dan Neo4j untuk graf pengetahuan. Semua komponen diorkestrasi menggunakan Docker Compose, menciptakan arsitektur yang modular dan dapat diskalakan tanpa bergantung pada layanan cloud proprietary.
Fondasi kualitas retrieval terletak pada tahap parsing dokumen. Proyek ini menggunakan Docling sebagai layanan terpisah yang mengonversi PDF, DOCX, dan HTML menjadi Markdown bersih sambil mempertahankan struktur heading dan tabel. Keputusan untuk mempertahankan format Markdown bukan sekadar preferensi estetika — struktur tabel yang dihancurkan menjadi "sup karakter" tidak akan pernah dapat dicari dengan baik, seberapa pun canggihnya model embedding yang digunakan. Prinsip "garbage in, garbage out" berlaku ketat di sini: kualitas parsing menentukan batas atas performa seluruh sistem.
Chunking, atau pemotongan dokumen, dinilai sebagai keputusan paling diremehkan namun paling kritis dalam arsitektur RAG. Chunk terlalu besar menghasilkan embedding yang kabur karena mencakup terlalu banyak topik sekaligus, sedangkan chunk terlalu kecil kehilangan konteks yang diperlukan agar potongan teks dapat dipahami secara mandiri. Proyek ini mengadopsi strategi recursive splitting dengan ukuran chunk 512 token dan overlap 64 token. Overlap ini esensial: tanpa ia, jawaban yang berada di batas dua chunk akan jatuh ke dalam celah dan tidak pernah di-retrieve secara utuh.
Inovasi kunci lain terletak pada strategi pengindeksan ganda. Sebagian besar tutorial hanya melakukan embedding sekali, namun myRAG mengindeks setiap chunk dua cara sekaligus: dense vector menggunakan model Qwen3-Embedding 4096-dimensi via OpenRouter untuk kesamaan semantik, dan sparse BM25 vector yang dihitung lokal dengan fastembed untuk kesamaan leksikal. Pendekatan ini menangani kelemahan masing-masing metode: model embedding kesulitan dengan nomor bagian, nama proper, dan akronim, sedangkan BM25 unggul pada pencocokan eksak. Qdrant menyimpan keduanya sebagai named vectors pada titik data yang sama, dengan IDF BM25 dihitung sisi server.
Pada tahap pencarian, sistem menerapkan Reciprocal Rank Fusion (RRF) untuk menggabungkan hasil dari kedua metode pencarian. RRF bekerja dengan memperingkat ulang dokumen berdasarkan formula Σ 1/(k + rank) di seluruh daftar, tanpa perlu normalisasi skor yang tidak sebanding. Chunk yang berpangkat tinggi di salah satu metode akan muncul, dan yang tinggi di keduanya akan mendominasi. Pendekatan ini terbukti sangat efektif tanpa memerlukan tuning parameter yang rumit.
Untuk presisi akhir, sistem menerapkan arsitektur corong dua tahap klasik: hybrid search mengambil 10 kandidat dengan biaya rendah, lalu cross-encoder reranker (Cohere rerank via OpenRouter) menyaringnya menjadi 5 teratas. Reranker membaca query dan chunk secara bersamaan, menghasilkan skor relevansi yang jauh lebih tajam dibanding pencarian vektor murni yang membandingkan query dengan chunk yang di-embed tanpa konteks pertanyaan.
Keunggulan arsitektur ini semakin terasa pada pertanyaan relasional yang gagal ditangani RAG vektor murni. Pertanyaan seperti "Siapa yang melaporkan ke orang yang mendirikan X?" melibatkan fakta yang tersebar di chunk berbeda. Selama ingest, LLM mengekstrak triple (subjek, relasi, objek) ke Neo4j. Saat query, entitas diekstrak dari pertanyaan, dicocokkan ke node graf via fulltext index, dan tetangga 1-hop-nya diinjeksikan ke prompt sebagai fakta terstruktur. Setiap relasi diberi tag doc_uuid, memungkinkan penghapusan dokumen yang bersih beserta fakta-fakta terkait.
Terakhir, manajemen memori dan anggaran token memastikan percakapan multi-turn berjalan efisien. Sistem menerapkan ringkasan bergulir: setelah N putaran, percakapan lama dikompresi menjadi ringkapan berjalan oleh LLM kecil. Anggaran token diterapkan dengan prioritas eksplisit: system prompt, ringkasan, fakta graf, dan pertanyaan selalu dipertahankan; riwayat terbaru dan chunk terbaik masuk jika ruang memungkinkan; chunk berpangkat terendah dibuang pertama. Arsitektur ini menunjukkan bahwa RAG produksi bukan sekadar embedding dan similarity search, melainkan tumpukan sistem terintegrasi yang masing-masing memecahkan batasan sistem lain.