Belajar LangChain - Retrieval & RAG Dasar
Episode 11 of 23

Belajar LangChain - Retrieval & RAG Dasar

Merangkai pipeline RAG pertama: VectorStoreRetriever dan similarity_search dengan top-k serta filter metadata, kombinasi retrieve-prompt-generate memakai LCEL, dan cara mengevaluasi kualitas jawaban.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Pendahuluan

Perjalanan panjang kita akhirnya sampai di titik yang dituju sejak episode 9: RAG. Kalian sudah punya chunks (episode 9) dan index vektor (episode 10). Sekarang kita gabungkan keduanya menjadi sistem yang bisa menjawab pertanyaan berdasarkan dokumen milik kalian sendiri, bukan hanya mengandalkan pengetahuan bawaan model.

Episode ini membangun pipeline RAG dasar end-to-end. Kita mulai dari retriever: VectorStoreRetriever dan similarity_search dengan pengaturan top-k serta filter metadata. Lalu pipeline RAG: alur retrieve → prompt → generate yang dirangkai dengan LCEL. Terakhir, kita bahas evaluasi — bagaimana menilai apakah jawaban yang dihasilkan benar-benar berkualitas.

VectorStoreRetriever

Jembatan antara vector store dan pipeline adalah retriever. vectorstore.as_retriever() membungkus vector store sehingga kalian bisa mengambil dokumen relevan dengan antarmuka yang konsisten — dan retriever ini sendiri adalah Runnable, jadi bisa langsung disambungkan ke chain LCEL.

PythonMembuat retriever dari vector store
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
dokumen_relevan = retriever.invoke("Apa itu RAG?")
 
for doc in dokumen_relevan:
    print(doc.page_content[:80])

search_kwargs={"k": 3} meminta tiga dokumen paling relevan setiap pencarian. Karena retriever adalah Runnable, pemanggilan invoke mengembalikan list Document — siap dikonsumsi oleh komponen berikutnya.

similarity_search dan Top-k

Di balik retriever ada pencarian kemiripan. similarity_search adalah cara langsung meng-query vector store tanpa lewat antarmuka retriever — berguna saat kalian butuh kontrol lebih, misalnya mengambil dokumen mentah beserta skor kemiripannya.

Pythonsimilarity_search dengan skor
hasil = vectorstore.similarity_search_with_score(
    "Bagaimana cara menyimpan vektor di Postgres?",
    k=3,
)
for doc, skor in hasil:
    print(round(skor, 4), doc.page_content[:60])

Top-k menentukan berapa banyak dokumen yang dikembalikan. Nilai kecil (2-4) menghasilkan konteks yang fokus tapi bisa melewatkan informasi; nilai besar memberi konteks lebih lengkap namun bisa mendorong model keluar dari jalur. Nilai 3-5 umumnya titik awal yang seimbang.

Info

Skor yang dikembalikan similarity_search_with_score adalah jarak, bukan kemiripan — semakin kecil semakin relevan. Tafsiran persisnya bergantung pada metric yang dipakai vector store kalian.

Filter Metadata

Metadata dari episode 9 membayar kebaikannya di sini: dengan filter, kalian membatasi pencarian hanya pada subset dokumen — misalnya sumber tertentu, tanggal, atau kategori — sehingga hasil lebih relevan dan lebih murah.

PythonFilter metadata saat retrieval
dokumen = vectorstore.similarity_search(
    "Strategi investasi jangka panjang",
    k=3,
    filter={"sumber": "laporan-2026.pdf"},
)

Sintaks filter bisa berbeda antar vector store — Chroma memakai dict seperti di atas, sementara Qdrant memakai kondisi yang lebih eksplisit. Kuncinya: pastikan metadata ditulis konsisten saat add_documents di episode 10, karena filter sebaik apa pun tidak berguna bila metadata tidak terstruktur.

Pipeline RAG dengan LCEL

Sekarang rangkai semuanya. Pipeline RAG klasik terdiri dari empat langkah: retrieve konteks, format konteks menjadi teks, suntikkan ke prompt, dan generate jawaban. Dengan LCEL seluruh alur cukup beberapa baris.

PythonPipeline RAG lengkap
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
 
prompt = ChatPromptTemplate.from_messages([
    ("system", "Jawab berdasarkan konteks di bawah. Jika konteks tidak cukup, katakan tidak tahu. Konteks: {context}"),
    ("human", "{pertanyaan}"),
])
model = ChatOpenAI(model="gpt-4o-mini")
 
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)
 
rag_chain = (
    {
        "context": retriever | format_docs,
        "pertanyaan": RunnablePassthrough(),
    }
    | prompt
    | model
    | StrOutputParser()
)
 
jawaban = rag_chain.invoke("Apa itu RAG dan bagaimana cara kerjanya?")
print(jawaban)

Alur ini patut dibaca pelan-pelan. retriever | format_docs mengambil dokumen lalu menggabungkan isinya menjadi satu blok konteks. RunnablePassthrough meneruskan pertanyaan asli. Keduanya dirakit menjadi dict yang diisi ke prompt, lalu diproses model dan parser. Dengan cara ini, fungsi format_docs dan hasil retriever bisa diuji secara terpisah sebelum digabung.

Evaluasi Kualitas Jawaban

RAG bukan sekali jadi — kualitas harus diukur. Evaluasi dasar memeriksa dua hal: apakah konteks yang di-retrieve relevan, dan apakah jawaban yang dihasilkan benar serta setia pada konteks.

PythonMemeriksa relevansi konteks yang di-retrieve
pertanyaan = "Apa peran checkpointer di LangGraph?"
konteks = retriever.invoke(pertanyaan)
 
for doc in konteks:
    print(doc.metadata.get("sumber"), doc.page_content[:70])

Mulailah dari sini: saat jawaban terasa salah, periksa dulu konteksnya. Kalau konteks tidak relevan, masalah ada di chunking (episode 9) atau embedder (episode 10), bukan di prompt. Kalau konteks relevan tapi jawaban melenceng, perbaiki prompt sistem. Latih juga sekumpulan pertanyaan uji dan bandingkan jawaban RAG dengan jawaban yang diharapkan — pembandingan manual yang rutin jauh lebih berharga daripada tanpa evaluasi sama sekali. Framework evaluasi yang lebih sistematis — datasets, evaluator otomatis, dan regression testing — akan kalian dalami lewat LangSmith di episode 19.

Success

Aturan emas debugging RAG: telusuri ke belakang. Jawaban salah → periksa konteks. Konteks salah → periksa chunk dan embedding. Prompt adalah komponen terakhir yang disalahkan, bukan yang pertama.

Penutup

Pipeline RAG dasar kalian kini berfungsi end-to-end: retriever mengambil dokumen relevan dengan top-k dan filter metadata, LCEL merangkai retrieve → prompt → generate dalam satu chain, dan kalian punya metode evaluasi untuk menjaga kualitas. Dari sini, kemungkinan pengembangan tinggal maju ke teknik yang lebih canggih.

Inti yang harus dibawa pulang:

  • as_retriever() membungkus vector store menjadi Runnable yang bisa dipasang langsung ke chain LCEL.
  • search_kwargs={"k": N} mengatur top-k; similarity_search_with_score memberi skor jarak untuk menilai relevansi.
  • Filter metadata membatasi pencarian ke subset dokumen dan meningkatkan relevansi.
  • Pipeline RAG = retrieve → format konteks → prompt → generate, dirangkai dengan RunnablePassthrough.
  • Debug dari belakang: jawaban salah periksa konteks, konteks salah periksa chunking dan embedding.
  • Evaluasi rutin dengan pertanyaan uji menjaga kualitas RAG seiring perubahan data dan prompt.

Di episode 12 kita lanjut ke teknik yang lebih tajam: Advanced RAG — multi-query retrieval, reranking, hybrid search, dan contextual retrieval untuk menjawab pertanyaan yang jauh lebih sulit. Sampai jumpa!

Belajar LangChain - Retrieval & RAG Dasar | Belajar LangChain