Implementasi RAG Dasar: Tutorial Langkah demi Langkah

Tutorial ramah pemula ini menjelaskan cara kerja implementasi RAG dasar, membahas praktik terbaik, dan memandu Anda membangun sistem RAG berbasis baris perintah yang berfungsi dengan Python, ChromaDB, serta model embedding dan model bahasa dari Perplexity.

Basic RAG implementation process diagram: the interface sends input to the orchestrator, which retrieves data from a vector database, builds the input context for the LLM, and returns the output to the interface.

RAG adalah komponen penting dalam infrastruktur modern berbasis LLM. Dengan memungkinkan model AI mengakses data eksternal, RAG membantu mengatasi masalah seperti halusinasi dan data pelatihan yang tidak lengkap. RAG juga memungkinkan perusahaan menggunakan basis pengetahuan internal yang berisi informasi sensitif atau rahasia perusahaan.

Implementasi RAG bisa sangat kompleks. Namun, sistem RAG dasar ternyata cukup mudah dibangun. Bagi pemula, membuat arsitektur sederhana dapat memperjelas cara kerja RAG di dunia nyata sekaligus menjadi batu loncatan untuk eksperimen lebih lanjut.

Dalam artikel ini, kita akan memetakan implementasi RAG dasar, membahas praktik terbaik, lalu membangun sistem yang berfungsi menggunakan Python, ChromaDB, dan dua model Perplexity untuk embedding dan pembuatan jawaban.

Proses implementasi RAG dasar: Gambaran umum

Sistem RAG dasar memiliki tiga komponen utama: orkestrator, sumber informasi, dan LLM. Dalam alur kerja yang umum, pengguna memasukkan prompt, lalu orkestrator memodifikasinya untuk menelusuri sumber informasi apa pun yang terhubung. Informasi yang diambil kemudian ditambahkan ke konteks input asli dan dikirim ke LLM agar balasan dapat dibuat.

Anda perlu memperhitungkan langkah-langkah berikut saat membangun implementasi RAG Anda:

  1. Pengindeksan dan embedding: Pada tahap ini, dokumen Anda dikonversi menjadi sumber informasi yang dapat ditelusuri oleh orkestrator. Salah satu cara paling umum untuk melakukannya adalah membangun indeks vektor yang dapat ditelusuri. Kita akan menggunakan model khusus dari Perplexity untuk mengonversi potongan dokumen Anda menjadi embedding. Setelah itu, kita akan menyimpan embedding tersebut dengan ChromaDB, database vektor sumber terbuka yang populer.
  2. Orkestrasi: Ini adalah aplikasi yang berada di antara sumber informasi eksternal (dalam kasus ini, database vektor) dan LLM. Kita akan membuat skrip Python sederhana yang berfungsi sebagai orkestrator.
  3. Pengambilan dan pembuatan: Saat pengguna mengajukan pertanyaan melalui antarmuka chat, orkestrator akan menerimanya, menjalankan pencarian vektor, lalu meneruskan input yang telah diperluas ke LLM. Alih-alih membangun frontend khusus, kita akan menggunakan baris perintah untuk mengirim prompt dan berkomunikasi dengan orkestrator Python kita.

Praktik terbaik: Apa yang membuat implementasi RAG efektif?

Ada berbagai jenis arsitektur RAG, dan setiap kasus penggunaan menuntut pendekatan yang berbeda. Meski demikian, sejumlah praktik terbaik berlaku dalam semua kasus dan memastikan sistem yang akurat, hemat biaya, skalabel, dan mudah dipelihara.

Praktik terbaik berikut berlaku untuk semua jenis implementasi RAG:

  • Pastikan pipeline ingesti yang bersih: Data sumber Anda harus sebersih mungkin sebelum diindeks. Anda juga sebaiknya menggunakan model embedding yang sesuai dengan konten Anda.
  • Gunakan pencarian hibrida: Metode pengambilan terbaik, baik pencarian database vektor, pencarian web berbasis API, penelusuran graf pengetahuan, pencarian kata kunci, maupun metode lainnya, berbeda-beda tergantung kasus penggunaannya. Memilih kombinasi yang tepat sangat penting untuk menekan biaya.
  • Evaluasi sistem Anda: Setelah implementasi, Anda perlu mengevaluasi sistem berdasarkan tiga ukuran inti: akurasi, relevansi, dan latensi. Akurasi mengacu pada kebenaran faktual, relevansi pada kesesuaian informasi yang diambil dengan kueri pengguna, dan latensi pada kecepatan pengambilan informasi.
  • Tangani informasi dengan aman: Jika sistem RAG Anda memanfaatkan informasi internal yang bersifat pribadi, pastikan informasi tersebut disimpan dengan aman dan akses ke antarmuka sistem dikelola dengan baik. Kunci API tidak boleh dibagikan kepada siapa pun.

Implementasi RAG dasar: Tutorial 7 langkah

Dalam tutorial ini, kita akan membangun aplikasi baris perintah yang menjawab pertanyaan tentang satu dokumen. Kita akan menggunakan Python, ChromaDB, dan Perplexity API.

Tujuannya bukan untuk membangun sistem RAG yang siap produksi. Sebaliknya, ini adalah tutorial ramah pemula yang dirancang untuk menggambarkan cara kerja arsitektur RAG sederhana dalam praktik.

Langkah 1: Instal perangkat lunak

Pastikan perangkat lunak berikut sudah terinstal di komputer Anda dan Anda memiliki akun Perplexity API:

  • Python: Ini adalah bahasa pemrograman yang akan kita gunakan untuk membangun orkestrator yang mengoordinasikan aliran data antara model embedding, ChromaDB, dan Perplexity.
  • Visual Studio: Kita akan menggunakan Visual Studio sebagai editor kode. Setelah terinstal, buka panel Extensions dan unduh ekstensi Python.
  • Akun Perplexity API: Perplexity akan menyediakan model embedding (yang mengubah data Anda menjadi embedding vektor) sekaligus LLM yang akan memproses prompt yang telah diperluas. Anda tidak memerlukan akun berbayar untuk melakukannya, meskipun akan ada sedikit biaya kredit.

Langkah 2: Buat folder proyek

Mulailah dengan membuat folder bernama rag-project, lalu buka folder tersebut di VS Code dengan memilih File > Open Folder. Kemudian, buka terminal terintegrasi melalui Terminal > New Terminal.

Masukkan perintah berikut untuk membuat lingkungan virtual Python:

bash
py -3.12 -m venv .venv

Sekarang Anda perlu menginstal empat library Python: perplexityai, chromadb, python-dotenv, dan numpy. Perplexity SDK memungkinkan Anda terhubung ke model Perplexity melalui API. ChromaDB membangun database vektor dan akan berjalan secara lokal. Python-dotenv memuat kunci API Anda secara aman dari file lokal, dan NumPy dibutuhkan selama proses ingesti.

Instal library tersebut dengan perintah berikut:

bash
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpy

Langkah 3: Siapkan file Anda

Tambahkan file berikut ke rag-project (root proyek) dengan memilih New File… di sidebar Explorer:

  • index.py: Ini adalah aplikasi yang akan mengindeks dokumen Anda. Anda dapat menjalankannya kembali untuk menambahkan teks lainnya.
  • rag.py: Ini adalah aplikasi Python yang akan berfungsi sebagai orkestrator.
  • document.txt: File ini akan berisi dokumentasi yang akan Anda konversi menjadi database vektor.
  • .env: Di sinilah Anda akan menyimpan kunci Perplexity API Anda.

Di .env, masukkan baris berikut:

plaintext
PERPLEXITY_API_KEY=your_api_key_here

Ganti your_api_key_here dengan kunci Anda yang sebenarnya. Untuk mendapatkannya, buka dasbor beranda Perplexity API Console dan pilih Create an API key. Jaga kerahasiaan kunci API ini.

Kita akan menggunakan dua model: pplx-embed-v1-0.6b dari Perplexity untuk membuat embedding dokumentasi sebelum diunggah ke ChromaDB, dan GPT-5.6-Luna (diakses melalui API Perplexity), yang akan memproses informasi yang diambil.

Di document.txt, tambahkan teks yang akan diambil oleh pipeline RAG Anda. Jika Anda tidak memiliki dokumen yang siap digunakan, gunakan Songs of Innocence and of Experience karya William Blake dari Project Gutenberg untuk tutorial ini. Teks ini singkat, mudah dipahami, dan berada di domain publik.

Langkah 4: Tulis program pengindeksan

Salin dan tempel kode di bawah ini ke index.py. Setiap subjudul memberikan penjelasan singkat tentang fungsi segmen kode berikutnya. Program inilah yang akan mengonversi materi sumber Anda menjadi embedding vektor dan menyimpannya dalam database ChromaDB menggunakan model embedding Perplexity, pplx-embed-v1-0.6b, dan library NumPy.

Berikut yang dilakukan program ini:

  1. Membuka document.txt.
  2. Membagi teks menjadi potongan-potongan yang saling tumpang-tindih.
  3. Mengirim potongan-potongan tersebut ke model embedding pplx-embed-v1-0.6b dari Perplexity.
  4. Mendekode dan menormalisasi vektor yang dikembalikan menggunakan NumPy, library Python yang berisi fungsi-fungsi komputasi.
  5. Menyimpan vektor dan potongan asli dalam database ChromaDB (database ini akan muncul di direktori proyek Anda).

Program ini telah diatur agar tidak mengindeks ulang dokumen Anda setiap kali dijalankan. Jika Anda menambahkan informasi ke document.txt, program hanya akan membuat embedding untuk teks yang baru.

python
from pathlib import Path from collections import defaultdict, deque from hashlib import sha256 import base64 import numpy as np import chromadb from dotenv import load_dotenv from perplexity import Perplexity # 1. Connect to Perplexity and ChromaDB load_dotenv() ai = Perplexity() db = chromadb.PersistentClient(path="./rag_database_perplexity") collection = db.get_or_create_collection( name="documents", metadata={"hnsw:space": "cosine"} ) # Convert Perplexity's encoded embeddings into numerical vectors def decode_embedding(encoded): vector = np.frombuffer(base64.b64decode(encoded), dtype=np.int8).astype(np.float32) norm = np.linalg.norm(vector) if norm == 0: raise ValueError("Received a zero-length embedding vector.") return (vector / norm).tolist() # 2. Read the document and split it into chunks text = Path("document.txt").read_text(encoding="utf-8") words = text.split() chunk_size = 180 overlap = 30 step = chunk_size - overlap chunks = [" ".join(words[i:i + chunk_size]) for i in range(0, len(words), step)] if not chunks: raise ValueError("document.txt is empty.") # 3. Retrieve the chunks already stored in ChromaDB existing = collection.get(include=["documents"]) stored_chunks = defaultdict(deque) existing_ids = set(existing["ids"]) for chunk_id, document in zip(existing["ids"], existing["documents"]): stored_chunks[document].append(chunk_id) # 4. Identify unchanged and new chunks new_chunks = [] new_ids = [] kept_ids = set() unchanged = 0 for chunk in chunks: if stored_chunks[chunk]: chunk_id = stored_chunks[chunk].popleft() kept_ids.add(chunk_id) unchanged += 1 else: chunk_hash = sha256(chunk.encode("utf-8")).hexdigest() chunk_id = f"chunk-{chunk_hash}" suffix = 1 while chunk_id in existing_ids or chunk_id in kept_ids or chunk_id in new_ids: chunk_id = f"chunk-{chunk_hash}-{suffix}" suffix += 1 new_chunks.append(chunk) new_ids.append(chunk_id) kept_ids.add(chunk_id) # 5. Generate embeddings in batches of up to 100 chunks batch_size = 100 for i in range(0, len(new_chunks), batch_size): batch_chunks = new_chunks[i:i + batch_size] batch_ids = new_ids[i:i + batch_size] embeddings = ai.embeddings.create( model="pplx-embed-v1-0.6b", input=batch_chunks, encoding_format="base64_int8" ) vectors = [decode_embedding(item.embedding) for item in embeddings.data] # 6. Store each batch in ChromaDB collection.upsert( ids=batch_ids, documents=batch_chunks, embeddings=vectors ) print(f"Indexed batch {(i // batch_size) + 1}") # 7. Remove outdated chunks old_ids = [chunk_id for chunk_id in existing["ids"] if chunk_id not in kept_ids] if old_ids: collection.delete(ids=old_ids) # 8. Display indexing results print("Indexing complete!") print("Unchanged chunks:", unchanged) print("New or modified chunks:", len(new_chunks)) print("Removed chunks:", len(old_ids)) print("Total stored chunks:", collection.count())

Langkah 5. Tulis orkestrator untuk sistem RAG

Salin dan tempel kode di bawah ini ke rag.py. Kode ini merupakan implementasi RAG yang lengkap namun minimal, yang menggunakan Perplexity SDK dan fungsionalitas database vektor lokal dari ChromaDB.

Berikut yang akan terjadi saat Anda menjalankan program:

  1. Terhubung ke Perplexity dan database ChromaDB baru Anda.
  2. Memastikan database berisi dokumen yang telah diindeks.
  3. Menerima pertanyaan dari pengguna.
  4. Mengirim pertanyaan ke model embedding Perplexity.
  5. Mendekode dan menormalisasi embedding yang dihasilkan menggunakan NumPy.
  6. Menelusuri ChromaDB untuk menemukan tiga potongan dokumen yang paling mirip.
  7. Menyusun prompt yang berisi potongan-potongan yang diambil dan pertanyaan pengguna.
  8. Mengirim prompt ke GPT-5.6 Luna melalui Agent API dari Perplexity.
  9. Menampilkan jawaban dan menunggu pertanyaan berikutnya.
python
import base64 import numpy as np import chromadb from dotenv import load_dotenv from perplexity import Perplexity # 1. Connect to Perplexity and the existing ChromaDB database load_dotenv() ai = Perplexity() db = chromadb.PersistentClient(path="./rag_database_perplexity") collection = db.get_collection("documents") # Convert Perplexity's encoded embeddings into numerical vectors def decode_embedding(encoded): vector = np.frombuffer(base64.b64decode(encoded), dtype=np.int8).astype(np.float32) norm = np.linalg.norm(vector) if norm == 0: raise ValueError("Received a zero-length embedding vector.") return (vector / norm).tolist() # 2. Check that the database contains indexed documents count = collection.count() if count == 0: raise ValueError("The database is empty. Run index.py first.") print("Connected to existing ChromaDB database.") print("Stored chunks:", count) # 3. Accept questions from the user while True: question = input("\nAsk a question (or type exit): ") if question.lower().strip() == "exit": break if not question.strip(): continue # 4. Convert the question into a Perplexity embedding question_response = ai.embeddings.create( model="pplx-embed-v1-0.6b", input=[question], encoding_format="base64_int8" ) question_vector = decode_embedding(question_response.data[0].embedding) # 5. Retrieve the most similar document chunks from ChromaDB results = collection.query( query_embeddings=[question_vector], n_results=min(3, count) ) context = "\n\n".join(results["documents"][0]) # 6. Construct a prompt and send it to the fixed LLM response = ai.responses.create( model="openai/gpt-5.6-luna", instructions=( "Answer using only the supplied document excerpts. " "Do not use external information. " "If the answer is not present, say you don't know." ), input=f"Document excerpts:\n{context}\n\nQuestion: {question}" ) # 7. Display the answer print("\nAnswer:\n", response.output_text)

Langkah 6: Jalankan aplikasi

Di terminal PowerShell VS Code, masukkan perintah berikut untuk membuat embedding dari konten di document.txt:

bash
.\.venv\Scripts\python.exe index.py

Jika dokumen Anda berhasil diindeks, Anda akan melihat output yang mirip dengan berikut ini:

plaintext
Indexing complete! Unchanged chunks: 0 New or modified chunks: 58 Removed chunks: 0 Total stored chunks: 58

Sekarang saatnya menjalankan aplikasi orkestrator utama. Masukkan perintah ini:

bash
.\.venv\Scripts\python.exe rag.py

Jika berhasil dijalankan, Anda akan melihat tampilan berikut:

plaintext
Connected to existing ChromaDB database. Stored chunks: 58 Ask a question (or type exit):

Sekarang Anda dapat mengajukan pertanyaan yang jawabannya diambil dari database vektor yang telah Anda buat, misalnya:

plaintext
Ask a question (or type exit): What animals does William Blake talk about? Answer: The excerpts mention sheep, lambs, birds, beasts, wolves, tigers, and a lion.

Langkah 7: Pahami apa yang telah Anda bangun

Sistem yang telah Anda bangun berisi dua pipeline inti yang ada di setiap arsitektur RAG: pipeline pengindeksan, atau “ingesti”, serta pipeline pengambilan dan pembuatan.

Implementasi RAG dasar Anda kini melakukan semua hal berikut:

  • Penyimpanan vektor: Embedding disimpan dalam database ChromaDB di lingkungan lokal Anda berdasarkan file pengetahuan Anda.
  • Pengindeksan inkremental: Potongan dokumen yang tidak berubah tidak dibuatkan embedding lagi, dan Anda dapat memperbarui dokumen kapan pun Anda mau.
  • Pengambilan semantik: ChromaDB mengambil potongan berdasarkan kemiripan vektor (dipicu oleh orkestrator).
  • Pembuatan jawaban berbasis sumber: LLM menerima bagian teks yang diambil sebagai konteks dan memasukkannya ke dalam jawaban.
  • Pengindeksan dan kueri yang terpisah: Anda dapat mengajukan pertanyaan tanpa harus memproses ulang seluruh teks dalam file pengetahuan Anda.
  • Koneksi model berbasis API: Semua jawaban dibuat menggunakan GPT-5.6 Luna melalui Perplexity, bukan model yang berjalan di mesin Anda.

Langkah selanjutnya: Cara mengembangkan implementasi ini lebih jauh

Tujuan tutorial ini adalah membangun implementasi dasar yang sederhana. Tutorial ini mencakup beberapa komponen inti arsitektur RAG yang ada dalam sistem modern. Jika ingin melangkah lebih jauh, ada berbagai cara untuk mengembangkannya.

Berikut beberapa ide untuk memperluas cakupan implementasi Anda:

  • Bereksperimen dengan LangChain: LangChain adalah salah satu framework orkestrasi sumber terbuka paling populer. Framework ini berisi komponen siap pakai untuk membangun aplikasi yang mampu menjalankan pipeline RAG yang kompleks.
  • Perluas fungsi pencarian: Gabungkan pencarian vektor padat dengan pencarian leksikal (kata kunci) seperti BM25. Menambahkan pencarian web melalui Perplexity Search API juga memungkinkan Anda mendasarkan jawaban pada data terkini.
  • Tambahkan model reranking: Integrasikan model reranking yang memeringkat bagian teks yang diambil berdasarkan prompt awal dan memilih bagian yang paling relevan untuk disertakan dalam konteks input yang diberikan ke LLM.
  • Bangun sistem RAG adaptif: RAG adaptif menggunakan LLM atau pengklasifikasi (komponen di dalam orkestrator) untuk menentukan metode pengambilan yang akan digunakan dalam sistem RAG modular. Membangun sistem ini adalah cara yang baik untuk mengeksplorasi implementasi RAG yang lebih canggih.

Meskipun semua ini mungkin terdengar rumit, perlu diingat bahwa platform AI populer seperti Perplexity dapat memberikan bantuan pemrograman tingkat lanjut. Platform semacam ini sangat cocok untuk proyek pribadi dan eksperimen, dan biayanya dapat ditekan agar tetap relatif rendah.

Catatan: Tutorial ini menggunakan GPT-5.6 Luna. Ketersediaan model dapat berubah, sehingga Anda mungkin perlu memperbarui panggilan API.