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.

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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.RunnablePassthrough.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!