Belajar Generative AI - RAG Lanjutan: Graph, Hybrid & Multi-Modal RAG
Episode 8 of 25

Belajar Generative AI - RAG Lanjutan: Graph, Hybrid & Multi-Modal RAG

Meningkatkan RAG dari tahap dasar ke level produksi: strategi chunking lanjutan, reranking, parent-child document, dan GraphRAG untuk data ber-relasi. Episode ini juga membuka multimodal RAG — image & table extraction, vision RAG, dan integrasi OCR — untuk dokumen yang bukan sekadar teks.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Setelah di episode 7 kalian membangun RAG dasar yang berfungsi, episode ini menjawab pertanyaan yang muncul begitu aplikasi berhadapan dengan dunia nyata: bagaimana kalau datanya dokumen tebal dengan tabel, gambar, dan hubungan antar-konsep? RAG naif — chunk lalu embed — akan mulai tersendat di sini.

Mengapa episode ini penting? Karena di produksi, dokumen perusahaan jarang berupa teks polos yang rapi. Ada PDF dengan tabel yang harus dibaca kolom-per-kolom, slide dengan diagram yang hanya masuk akal sebagai gambar, dan basis pengetahuan di mana jawaban tersebar di banyak halaman yang saling terkait. RAG lanjutan adalah seperangkat alat untuk menangani semua itu.

Strategi Chunking Lanjutan

Document-Aware Chunking

Daripada memotong teks buta per karakter, hormati struktur dokumen: pecah per heading (#), pertahankan tabel utuh, dan ikuti batas paragraf. Hasilnya chunk yang koheren secara makna, bukan potongan kalimat di tengah.

Chunking berbasis heading
def chunk_by_headings(text):
    sections, current, title = [], [], "root"
    for line in text.splitlines():
        if line.startswith("## "):
            sections.append((title, "\n".join(current)))
            title, current = line[3:], []
        else:
            current.append(line)
    sections.append((title, "\n".join(current)))
    return sections

Parent-Child Document

Idea cerdas untuk menjawab pertanyaan yang butuh konteks lebih luas: simpan child chunk kecil (akurat untuk retrieval) yang punya referensi ke parent chunk besar (lengkap untuk konteks LLM). Retrieve child → tarik parent → kirim parent ke LLM.

Parent-child: retrieve kecil, generate besar
def ask_parent_child(question):
    qv = embed(question)
    child = col.query(query_embeddings=[qv], n_results=3)
    # untuk tiap child, ambil parent (chunk besar) yang sama sumber & bagiannya
    parents = [parent_of(c["id"]) for c in child["ids"][0]]
    return llm_answer(question, context="\n\n".join(parents))

Parent-child adalah perbaikan paling "murah" dalam hal efektivitas — sering menaikkan skor faithfulness secara signifikan.

Reranking: Menyaring Hasil Awal

Vector similarity bagus sebagai penyaring awal, tapi bisa salah urut — misal chunk yang cocok secara "makna" tapi tidak menjawab pertanyaan sebenarnya. Reranker adalah model kedua yang menilai ulang pasangan (query, dokumen) secara lebih akurat dan mahal, lalu mengurutkan ulang.

Pola reranking (Cohere / cross-encoder)
import cohere
 
co = cohere.Client(api_key=os.environ["CO_API_KEY"])
 
# 1. Ambil 20 kandidat murah dengan vector search
candidates = col.query(query_embeddings=[qv], n_results=20)
 
# 2. Rerank dengan model yang lebih teliti
reranked = co.rerank(
    query=question,
    documents=candidates["documents"][0],
    top_n=4,
    model="rerank-multilingual-v3.0",
)
 
# 3. Kirim hanya 4 terbaik ke LLM
final = [candidates["documents"][0][i] for i in
         [r.index for r in reranked.results]]

Pola retrieve-then-rerank adalah standar produksi 2026: vektor menyaring cepat, reranker menyaring akurat — biaya rerank hanya untuk puluhan kandidat, bukan seluruh korpus.

GraphRAG: Menangkap Relasi Antar-Konsep

Untuk pertanyaan yang menghubungkan banyak konsep ("siapa kolaborator yang paling sering muncul dengan tim X?"), RAG chunk polos gagal karena informasi tersebar. GraphRAG membangun knowledge graph: entitas (orang, organisasi, konsep) sebagai node dan relasi sebagai edge, lalu retrieval berjalan di atas grafik itu.

100%

Langkahnya: ekstrak entitas & relasi dari dokumen (bisa via LLM), simpan sebagai graph (misal Neo4j), lalu jawab pertanyaan dengan traversing graf + LLM. Biayanya lebih mahal untuk dibangun, tetapi unggul untuk pertanyaan global (whole-corpus) dan analisis relasi.

Note

GraphRAG bukan pengganti RAG vector biasa — ia pelengkap. Untuk pertanyaan lokal ("apa isi bagian X?"), vector RAG sudah cukup; GraphRAG unggul untuk pertanyaan yang melintasi banyak dokumen. Banyak produksi memakai keduanya: vector untuk lookup, graph untuk relasi.

Multimodal RAG: Bukan Hanya Teks

Image & Table Extraction

Dokumen nyata penuh tabel dan gambar. Dua pendekatan:

  1. Extraction → teks: OCR/parsing mengubah tabel menjadi teks (misal markdown dari tabel PDF) lalu di-embed seperti teks biasa.
  2. Vision RAG: kirim gambar langsung ke model vision (VLM) sebagai bagian dari konteks — baik sebagai retrieval (embed gambar dengan model multimodal) maupun di generation.
Vision RAG: kirim gambar ke VLM
import base64
 
def image_b64(path):
    with open(path, "rb") as f:
        return base64.b64encode(f.read()).decode()
 
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": [
        {"type": "text", "text": "Apa isi tabel pada slide ini? Format jawaban markdown."},
        {"type": "image_url",
         "image_url": {"url": f"data:image/png;base64,{image_b64('slide.png')}"}},
    ]}],
)
print(resp.choices[0].message.content)

Integrasi OCR

Untuk PDF hasil scan (gambar halaman), wajib OCR dulu — misal pytesseract atau PaddleOCR — sebelum chunking. Ingat: OCR dulu, chunking kedua, embed ketiga. Melewatkan OCR = seluruh isi dokumen hilang.

Install OCR
pip install pytesseract pdf2image
OCR halaman PDF
import pytesseract
from pdf2image import convert_from_path
 
pages = convert_from_path("scan.pdf", dpi=200)
text = "\n".join(pytesseract.image_to_string(p) for p in pages)
print(text[:200])

Table-Aware Parsing

Tabel yang di-OCR sebagai teks datar sering rusak. Tool seperti pdfplumber atau unstructured bisa mengekstrak tabel per-sel dan menyimpannya sebagai markdown — sehingga retrieval "berapa penjualan Q3?" bisa menemukan tabelnya.

Install parser dokumen
pip install unstructured pdfplumber
Ekstrak tabel ke markdown
import pdfplumber
 
with pdfplumber.open("laporan.pdf") as pdf:
    table = pdf.pages[0].extract_table()
    for row in table:
        print(" | ".join(cell or "" for cell in row))

Common Pitfalls

  • Melewati reranking: memakai 4 hasil teratas vector search langsung → sering salah urut untuk pertanyaan spesifik.
  • OCR sebelum chunking terlewat: PDF hasil scan yang "tampak" punya teks ternyata kosong.
  • Tabel di-embed sebagai teks datar: retrieval kehilangan struktur kolom — selalu konversi ke markdown/struktur yang jelas.
  • GraphRAG untuk semua query: mahal; pakai sesuai kebutuhan pertanyaan global/relasi.

Penutup

Inti yang harus dibawa pulang:

  • Document-aware chunking dan parent-child meningkatkan koherensi konteks.
  • Retrieve-then-rerank adalah pola produksi: vektor menyaring, reranker mengurutkan ulang.
  • GraphRAG menangkap relasi antar-konsep untuk pertanyaan lintas dokumen.
  • Multimodal RAG: OCR & table extraction dulu, vision RAG untuk gambar, gabungkan semua ke satu pipeline.

Di episode 9 selanjutnya kita akan membangun Function Calling & Tool Use — structured tool schema, tool retry/error handling, dan agen yang bisa query database, kalkulasi, atau memanggil API eksternal. Sampai jumpa di episode 9!

Belajar Generative AI - RAG Lanjutan: Graph, Hybrid & Multi-Modal RAG | Belajar Generative AI