spinny:~/writing $ vim rag-langchain-deep-dive.md
1~2Model Bahasa Besar (LLM) seperti GPT-4 dan Claude sangat kuat, tetapi mereka memiliki keterbatasan mendasar: pengetahuan mereka terhenti pada saat pelatihan. Mereka tidak dapat mengakses dokumen internal Anda, database Anda, atau informasi real-time. **Retrieval-Augmented Generation (RAG)** memecahkan masalah ini dengan menggabungkan kekuatan generatif LLM dengan kemampuan untuk mengambil informasi dari sumber eksternal.3~4## Masalah: Keterbatasan LLM5~6Sebelum membahas RAG, penting untuk memahami mengapa kita membutuhkannya.7~81. **Pengetahuan statis**: LLM hanya mengetahui apa yang dilihatnya selama pelatihan. Jika Anda bertanya tentang peristiwa yang terjadi setelah batas waktu pelatihannya, ia tidak dapat menjawab.92. **Halusinasi**: Ketika LLM tidak mengetahui jawabannya, ia cenderung mengarangnya, menghasilkan informasi yang masuk akal tetapi sepenuhnya salah.103. **Tidak ada akses ke data privat**: LLM generik tidak memiliki akses ke dokumentasi internal perusahaan Anda, tiket, atau basis kode.11~12RAG mengatasi ketiga masalah ini dengan menyediakan **konteks yang relevan** yang diambil dari sumber eksternal pada saat kueri.13~14## Apa itu RAG?15~16Retrieval-Augmented Generation adalah arsitektur yang memperkaya prompt yang dikirim ke LLM dengan informasi yang diambil dari basis pengetahuan eksternal. Alih-alih hanya mengandalkan pengetahuan parametrik model, RAG terlebih dahulu **mencari** informasi yang relevan kemudian **menyuntikkannya** ke dalam prompt, memungkinkan model menghasilkan respons yang akurat dan berdasar.17~18```mermaid19graph LR20 User["User"] -- "Question" --> Retriever21 Retriever -- "Search relevant\ndocuments" --> VectorStore["Vector Store"]22 VectorStore -- "Relevant\ndocuments" --> Retriever23 Retriever -- "Context + Question" --> LLM24 LLM -- "Grounded\nresponse" --> User25```26~27## Cara Kerja RAG secara Detail28~29Arsitektur RAG terdiri dari dua fase utama: **Pengindeksan** (offline) dan **Pengambilan + Pembuatan** (online).30~31### Fase 1: Pengindeksan (Ingesti Dokumen)32~33Fase pengindeksan mempersiapkan dokumen Anda untuk pencarian semantik. Terdiri dari empat langkah.34~35```mermaid36graph TD37 A["Documents\n(PDF, HTML, MD, DB)"] --> B["Document Loader"]38 B --> C["Text Splitter"]39 C --> D["Text Chunks"]40 D --> E["Embedding Model"]41 E --> F["Numerical Vectors"]42 F --> G["Vector Store\n(ChromaDB, Pinecone, FAISS)"]43```44~45#### 1. Pemuatan Dokumen46~47Dokumen dapat berasal dari sumber mana pun: file PDF, halaman web, database, file Markdown, API. **Document Loader** membaca dokumen-dokumen ini dan mengubahnya menjadi teks terstruktur.48~49#### 2. Pemisahan Teks (Chunking)50~51LLM memiliki jendela konteks yang terbatas, dan dokumen bisa sangat panjang. **Text Splitter** membagi dokumen menjadi fragmen-fragmen kecil yang disebut *chunks*. Kualitas chunking sangat penting: chunks yang terlalu kecil kehilangan konteks, sementara chunks yang terlalu besar mengencerkan relevansi.52~53Strategi yang paling umum adalah:54- **Recursive Character Splitting**: Memisahkan teks secara rekursif menggunakan pemisah seperti `\n\n`, `\n`, `. `, dengan menghormati struktur dokumen.55- **Semantic Splitting**: Menggunakan embeddings untuk menemukan titik pemisahan alami dalam teks.56- **Chunk Overlap**: Menyertakan tumpang tindih antara chunks berurutan untuk menjaga konteks di batas.57~58#### 3. Embedding59~60Setiap chunk diubah menjadi **vektor numerik** (embedding) melalui model embedding (seperti `text-embedding-3-small` dari OpenAI). Vektor-vektor ini menangkap makna semantik teks: kalimat dengan makna serupa akan memiliki vektor yang berdekatan dalam ruang multidimensi.61~62#### 4. Vector Store63~64Vektor-vektor disimpan dalam **Vector Store** (atau database vektor), seperti ChromaDB, Pinecone, Weaviate, atau FAISS. Database ini dioptimalkan untuk **pencarian kesamaan**: diberikan sebuah kueri, ia menemukan vektor-vektor yang paling mirip (dan karenanya chunks teks yang paling relevan).65~66### Fase 2: Pengambilan + Pembuatan67~68Ketika pengguna mengajukan pertanyaan:69~701. Pertanyaan diubah menjadi embedding menggunakan model embedding yang sama.712. Vector Store menemukan chunks yang paling mirip melalui **pencarian kesamaan** (biasanya cosine similarity atau jarak Euclidean).723. Chunks yang diambil disisipkan ke dalam prompt sebagai konteks.734. LLM menghasilkan respons berdasarkan konteks yang diberikan.74~75## Membangun Pipeline RAG dengan LangChain76~77**LangChain** adalah framework Python (dan JavaScript) paling populer untuk membangun aplikasi berbasis LLM. Framework ini menyediakan abstraksi tingkat tinggi untuk setiap komponen pipeline RAG.78~79### Instalasi80~81```bash82pip install langchain langchain-openai langchain-community chromadb83```84~85### Langkah 1: Muat Dokumen86~87LangChain menyediakan puluhan Document Loader untuk berbagai sumber data.88~89```python90from langchain_community.document_loaders import (91 PyPDFLoader,92 WebBaseLoader,93 DirectoryLoader,94 TextLoader,95)96~97# Load a PDF98pdf_loader = PyPDFLoader("docs/manual.pdf")99pdf_docs = pdf_loader.load()100~101# Load a web page102web_loader = WebBaseLoader("https://docs.example.com/guide")103web_docs = web_loader.load()104~105# Load all .md files from a directory106dir_loader = DirectoryLoader("./knowledge_base", glob="**/*.md", loader_cls=TextLoader)107md_docs = dir_loader.load()108~109all_docs = pdf_docs + web_docs + md_docs110```111~112### Langkah 2: Pisahkan Dokumen menjadi Chunks113~114```python115from langchain.text_splitter import RecursiveCharacterTextSplitter116~117text_splitter = RecursiveCharacterTextSplitter(118 chunk_size=1000,119 chunk_overlap=200,120 separators=["\n\n", "\n", ". ", " ", ""],121)122~123chunks = text_splitter.split_documents(all_docs)124print(f"Original documents: {len(all_docs)}, Chunks: {len(chunks)}")125```126~127Parameter `chunk_overlap` sangat penting: ia menciptakan tumpang tindih antara chunks berurutan sehingga konteks tidak hilang di batas.128~129### Langkah 3: Buat Embeddings dan Vector Store130~131```python132from langchain_openai import OpenAIEmbeddings133from langchain_community.vectorstores import Chroma134~135embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")136~137vectorstore = Chroma.from_documents(138 documents=chunks,139 embedding=embedding_model,140 persist_directory="./chroma_db",141)142```143~144### Langkah 4: Buat Retriever145~146Retriever adalah komponen yang, diberikan sebuah kueri, mengambil chunks yang paling relevan dari vector store.147~148```python149retriever = vectorstore.as_retriever(150 search_type="similarity",151 search_kwargs={"k": 4},152)153~154relevant_docs = retriever.invoke("How does authentication work?")155for doc in relevant_docs:156 print(doc.page_content[:200])157 print("---")158```159~160### Langkah 5: Bangun RAG Chain161~162Sekarang mari kita satukan semuanya dengan LLM dan template prompt.163~164```python165from langchain_openai import ChatOpenAI166from langchain_core.prompts import ChatPromptTemplate167from langchain_core.runnables import RunnablePassthrough168from langchain_core.output_parsers import StrOutputParser169~170llm = ChatOpenAI(model="gpt-4o", temperature=0)171~172prompt = ChatPromptTemplate.from_template("""173Answer the question based only on the provided context.174If the context does not contain enough information, say you don't know.175~176Context:177{context}178~179Question: {question}180~181Answer:182""")183~184def format_docs(docs):185 return "\n\n".join(doc.page_content for doc in docs)186~187rag_chain = (188 {"context": retriever | format_docs, "question": RunnablePassthrough()}189 | prompt190 | llm191 | StrOutputParser()192)193~194response = rag_chain.invoke("How does authentication work in the system?")195print(response)196```197~198## Teknik RAG Lanjutan199~200Pipeline dasar bekerja dengan baik, tetapi ada beberapa teknik untuk meningkatkan kualitas respons secara signifikan.201~202### Pengambilan Multi-Kueri203~204Terkadang kueri pengguna ambigu atau tidak selaras dengan bahasa yang digunakan dalam dokumen. **Multi-Query Retriever** secara otomatis menghasilkan varian dari pertanyaan asli untuk menangkap berbagai perspektif.205~206```python207from langchain.retrievers import MultiQueryRetriever208~209multi_retriever = MultiQueryRetriever.from_llm(210 retriever=vectorstore.as_retriever(),211 llm=llm,212)213~214docs = multi_retriever.invoke("What are the security best practices?")215```216~217### Kompresi Kontekstual218~219Tidak semua konten dalam sebuah chunk relevan dengan kueri. **Contextual Compression Retriever** menggunakan LLM untuk mengekstrak hanya bagian yang relevan dari setiap chunk yang diambil.220~221```python222from langchain.retrievers import ContextualCompressionRetriever223from langchain.retrievers.document_compressors import LLMChainExtractor224~225compressor = LLMChainExtractor.from_llm(llm)226compression_retriever = ContextualCompressionRetriever(227 base_compressor=compressor,228 base_retriever=retriever,229)230```231~232### Pencarian Hibrida233~234Pencarian murni semantik tidak selalu optimal. **Pencarian Hibrida** menggabungkan pencarian semantik (embeddings) dengan pencarian leksikal (BM25, pencocokan kata kunci) untuk mencapai hasil yang lebih baik.235~236```python237from langchain.retrievers import EnsembleRetriever238from langchain_community.retrievers import BM25Retriever239~240bm25_retriever = BM25Retriever.from_documents(chunks)241bm25_retriever.k = 4242~243semantic_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})244~245hybrid_retriever = EnsembleRetriever(246 retrievers=[bm25_retriever, semantic_retriever],247 weights=[0.4, 0.6],248)249```250~251### RAG Percakapan (dengan Memori)252~253Untuk membangun chatbot RAG yang mengingat konteks percakapan, Anda perlu menambahkan memori yang merumuskan ulang pertanyaan pengguna dengan mempertimbangkan riwayat percakapan.254~255```python256from langchain.chains import create_history_aware_retriever257from langchain_core.prompts import MessagesPlaceholder258~259contextualize_prompt = ChatPromptTemplate.from_messages([260 ("system", "Given the chat history and the user's latest question, "261 "reformulate the question so it is understandable without the history."),262 MessagesPlaceholder("chat_history"),263 ("human", "{input}"),264])265~266history_aware_retriever = create_history_aware_retriever(267 llm, retriever, contextualize_prompt268)269```270~271## Praktik Terbaik272~2731. **Pilih ukuran chunk yang tepat**: Bereksperimen dengan berbagai ukuran (500-1500 token). Chunks lebih kecil untuk jawaban presisi, lebih besar untuk konteks yang lebih luas.2742. **Gunakan metadata dokumen**: Tambahkan sumber, tanggal, dan kategori sebagai metadata ke chunks. Ini memungkinkan pemfilteran hasil selama pengambilan.2753. **Evaluasi kualitas**: Gunakan framework seperti [RAGAS](https://docs.ragas.io/) untuk mengukur metrik seperti *faithfulness*, *relevancy*, dan *context precision*.2764. **Kelola pembaruan dokumen**: Implementasikan pipeline re-ingesti untuk menjaga vector store tetap tersinkronisasi dengan sumber data Anda.2775. **Tambahkan re-ranker**: Setelah pengambilan awal, gunakan model re-ranking (seperti Cohere Rerank) untuk mengurutkan ulang hasil berdasarkan relevansi aktual.278~279## Kesimpulan280~281RAG telah menjadi arsitektur standar untuk membangun aplikasi AI yang membutuhkan akses ke pengetahuan spesifik dan terkini. LangChain sangat menyederhanakan implementasi, menyediakan abstraksi untuk setiap komponen pipeline.282~283**Langkah selanjutnya:**284- **Bereksperimen secara lokal**: Mulai dengan ChromaDB dan beberapa dokumen untuk membiasakan diri dengan pipeline.285- **Jelajahi LangSmith**: Gunakan [LangSmith](https://smith.langchain.com/) untuk memantau dan men-debug chain Anda di produksi.286- **Coba model embedding yang berbeda**: Bandingkan model seperti `text-embedding-3-small`, `text-embedding-3-large`, dan model open-source dari Sentence Transformers.287- **Periksa dokumentasi**: [Dokumentasi LangChain](https://python.langchain.com/docs/) adalah sumber yang sangat baik dan terus diperbarui.288~
NORMAL · rag-langchain-deep-dive.md [readonly]288 lines · :q to close