S13
IF1402 Praktikum
Sesi 13 - RAG Dasar
Sesi 13 dari 16

RAG Dasar

Pada sesi ini mahasiswa masuk ke salah satu pola aplikasi AI generatif yang paling penting dalam dunia nyata, yaitu Retrieval-Augmented Generation atau RAG. Ide dasarnya sederhana. Sebelum model menjawab, sistem lebih dulu mencari potongan dokumen yang relevan. Setelah itu, jawaban dibangun dengan berpijak pada dokumen tersebut. Jadi model tidak hanya mengandalkan ingatan umum, tetapi juga diberi “buku contekan” yang sesuai dengan pertanyaan.

Bayangkan seorang mahasiswa sedang ujian lisan. Jika hanya mengandalkan hafalan, jawabannya bisa meleset. Tetapi jika sebelum menjawab ia boleh membuka catatan resmi yang relevan, jawabannya akan cenderung lebih tepat. RAG bekerja mirip seperti itu. Retrieval adalah tahap mencari catatan yang tepat. Generation adalah tahap menyusun jawaban berdasarkan catatan itu.

Fokus: retrieval + generation Topik: chunking, embedding, context Output: QA berbasis dokumen
Pertanyaan inti sesi ini Bagaimana membuat LLM menjawab berdasarkan dokumen yang kita miliki, bukan sekadar berdasarkan tebakan atau memori umum?
Inti jawabannya Sistem harus memecah dokumen menjadi bagian kecil, mengubahnya menjadi embedding, mencari bagian yang paling relevan, lalu mengirim bagian itu sebagai konteks ke model generatif.
Hasil belajar Mahasiswa mampu membangun alur RAG sederhana untuk menjawab pertanyaan berdasarkan dokumen lokal seperti FAQ kampus, panduan praktikum, atau modul perkuliahan.

Apa itu RAG

RAG adalah singkatan dari Retrieval-Augmented Generation. Retrieval berarti mencari informasi yang relevan dari kumpulan dokumen. Augmented berarti hasil pencarian itu dipakai untuk memperkaya konteks. Generation berarti model menyusun jawaban berdasarkan konteks tersebut. Jadi RAG bukan model baru yang berdiri sendiri, melainkan pola kerja yang menggabungkan pencarian dan generasi teks.

Perumpamaan mudah

Bayangkan dosen bertanya, lalu mahasiswa boleh membuka modul kuliah sebelum menjawab. Tanpa membuka modul, mahasiswa mungkin menjawab berdasarkan ingatan yang samar. Dengan membuka modul yang tepat, jawabannya menjadi lebih aman, lebih akurat, dan lebih bisa dipertanggungjawabkan. Itulah manfaat utama RAG.

Alur kerja RAG dasar

1

Siapkan dokumen

Kita kumpulkan sumber seperti modul, FAQ, SOP, artikel, atau catatan praktikum yang nantinya akan menjadi basis jawaban.

2

Lakukan chunking

Dokumen panjang dipecah menjadi potongan yang lebih kecil agar pencarian lebih fokus dan hasil embedding lebih bersih.

3

Buat embedding dan retrieval

Setiap potongan diubah menjadi vektor. Saat ada pertanyaan, query juga diubah menjadi vektor lalu dicari chunk yang paling mirip.

4

Bangun jawaban dengan context

Chunk yang terpilih dikirim ke LLM bersama pertanyaan agar model menjawab dengan dasar yang lebih jelas dan lebih terikat pada sumber.

Mengapa RAG penting

LLM sangat kuat, tetapi kadang menjawab terlalu percaya diri walaupun sumbernya tidak jelas. Fenomena ini dikenal sebagai hallucination. RAG membantu mengurangi masalah itu karena jawaban diarahkan untuk memakai potongan dokumen yang benar-benar relevan. Selain itu, RAG berguna ketika pengetahuan yang dibutuhkan bersifat lokal atau spesifik, misalnya aturan kampus, materi dosen, FAQ program studi, atau manual aplikasi internal.

Kalau LLM ibarat mahasiswa yang pintar, maka RAG membuat mahasiswa itu boleh membuka arsip kampus saat menjawab pertanyaan yang sangat spesifik.

Apa itu chunking dan mengapa tidak langsung pakai dokumen utuh

Chunking adalah proses memotong dokumen besar menjadi potongan yang lebih kecil. Alasannya sederhana. Jika satu embedding dibuat dari dokumen yang terlalu panjang, maknanya bisa menjadi campur aduk. Potongan yang terlalu besar juga membuat retrieval kurang presisi. Sebaliknya, potongan yang terlalu kecil kadang kehilangan konteks. Jadi chunking adalah seni mencari ukuran yang pas.

Chunk terlalu besar

Pencarian menjadi kabur karena satu potongan memuat terlalu banyak topik sekaligus.

Chunk terlalu kecil

Informasi inti bisa terpotong sehingga model menerima konteks yang tidak utuh.

Praktikum 1: membuat chunking sederhana

Contoh berikut memecah teks panjang menjadi potongan berdasarkan jumlah karakter dengan sedikit overlap agar konteks antarbagian tidak putus terlalu tajam.

def chunk_text(text, chunk_size=300, overlap=60):
    chunks = []
    start = 0

    while start < len(text):
        end = start + chunk_size
        chunk = text[start:end]
        chunks.append(chunk)
        start += chunk_size - overlap

    return chunks

teks = """
Preprocessing teks adalah tahap awal yang sangat penting. Pada tahap ini teks dibersihkan,
kemudian diubah ke format yang lebih konsisten. Setelah itu teks dapat direpresentasikan
menjadi fitur seperti TF-IDF atau embedding. Dalam sistem modern, embedding sangat penting
karena membantu pencarian berbasis makna. Retrieval yang baik akan sangat berguna ketika
kita membangun sistem RAG untuk tanya jawab berbasis dokumen.
"""

hasil_chunk = chunk_text(teks, chunk_size=120, overlap=20)
for i, c in enumerate(hasil_chunk, 1):
    print(f"Chunk {i}:\n{c}\n")

Praktikum 2: membuat embedding untuk setiap chunk

Setelah dokumen dipecah, setiap chunk dibuat embedding-nya. Di sinilah sesi 12 bertemu langsung dengan sesi 13.

from sentence_transformers import SentenceTransformer

model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

dokumen = """
NLP membantu komputer memahami teks manusia. Preprocessing membersihkan data. TF-IDF mengubah
teks menjadi angka. Embedding membantu sistem memahami makna. RAG memadukan retrieval dan
jawaban generatif agar hasil lebih relevan.
"""

chunks = chunk_text(dokumen, chunk_size=100, overlap=20)
chunk_embeddings = model.encode(chunks)

print("Jumlah chunk:", len(chunks))
print("Ukuran embedding:", chunk_embeddings.shape)

Praktikum 3: retrieval top-k dengan cosine similarity

Di bawah ini query pengguna akan dicocokkan ke semua chunk. Lalu sistem mengambil beberapa chunk dengan skor similarity tertinggi.

from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

def retrieve_top_k(query, chunks, chunk_embeddings, model, k=3):
    query_embedding = model.encode([query])
    scores = cosine_similarity(query_embedding, chunk_embeddings)[0]
    ranking = np.argsort(scores)[::-1][:k]

    results = []
    for idx in ranking:
        results.append({
            "chunk": chunks[idx],
            "score": float(scores[idx])
        })
    return results

query = "Mengapa embedding berguna untuk pencarian makna?"
retrieved = retrieve_top_k(query, chunks, chunk_embeddings, model, k=2)

for item in retrieved:
    print("Skor:", round(item["score"], 4))
    print(item["chunk"])
    print("-" * 40)

Praktikum 4: helper LLM Groq untuk jawaban berbasis konteks

Setelah potongan relevan diperoleh, kita kirim ke model sebagai context. Prompt system perlu menekankan bahwa model harus menjawab berdasarkan dokumen dan jujur jika konteks tidak cukup.

import requests

API_KEY = "gsk_XXXX"
MODEL = "llama-3.1-8b-instant"
URL = "https://api.groq.com/openai/v1/chat/completions"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

def ask_llm_with_context(question, context):
    system_prompt = (
        "Anda adalah tutor mata kuliah NLP dan AI generatif. "
        "Jawab hanya berdasarkan konteks yang diberikan. "
        "Jika konteks tidak cukup, katakan bahwa informasi belum cukup. "
        "Gunakan bahasa Indonesia yang jelas, hangat, dan mudah dipahami."
    )

    user_prompt = f"Konteks:\n{context}\n\nPertanyaan:\n{question}"

    payload = {
        "model": MODEL,
        "temperature": 0.2,
        "max_tokens": 500,
        "messages": [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ]
    }

    response = requests.post(URL, headers=headers, json=payload)
    response.raise_for_status()
    data = response.json()
    return data["choices"][0]["message"]["content"]

Praktikum 5: pipeline RAG minimal end-to-end

Contoh berikut menggabungkan chunking, embedding, retrieval, dan generation menjadi alur yang utuh. Ini adalah mini RAG yang cukup baik untuk latihan awal mahasiswa.

from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import requests

API_KEY = "gsk_XXXX"
MODEL = "llama-3.1-8b-instant"
URL = "https://api.groq.com/openai/v1/chat/completions"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}


def chunk_text(text, chunk_size=300, overlap=60):
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size
        chunks.append(text[start:end])
        start += chunk_size - overlap
    return chunks


def retrieve_top_k(query, chunks, chunk_embeddings, model, k=3):
    query_embedding = model.encode([query])
    scores = cosine_similarity(query_embedding, chunk_embeddings)[0]
    ranking = np.argsort(scores)[::-1][:k]
    return [chunks[i] for i in ranking]


def answer_rag(question, documents, model_embed):
    all_chunks = []
    for doc in documents:
        all_chunks.extend(chunk_text(doc, chunk_size=250, overlap=40))

    chunk_embeddings = model_embed.encode(all_chunks)
    top_chunks = retrieve_top_k(question, all_chunks, chunk_embeddings, model_embed, k=3)
    context = "\n\n".join(top_chunks)

    payload = {
        "model": MODEL,
        "temperature": 0.2,
        "max_tokens": 600,
        "messages": [
            {
                "role": "system",
                "content": "Anda adalah tutor. Jawab berdasarkan konteks. Jika konteks belum cukup, katakan dengan jujur."
            },
            {
                "role": "user",
                "content": f"Konteks:\n{context}\n\nPertanyaan:\n{question}"
            }
        ]
    }

    response = requests.post(URL, headers=headers, json=payload)
    response.raise_for_status()
    return response.json()["choices"][0]["message"]["content"], top_chunks

model_embed = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

documents = [
    "Preprocessing adalah tahap membersihkan teks sebelum analisis. Tahap ini bisa meliputi case folding, tokenisasi, stopword removal, dan stemming.",
    "TF-IDF digunakan untuk memberi bobot pada kata. Kata yang sering muncul di satu dokumen tetapi tidak terlalu sering muncul di semua dokumen akan mendapat bobot lebih tinggi.",
    "RAG adalah pendekatan yang menggabungkan retrieval dokumen dengan generation agar jawaban model lebih relevan terhadap sumber yang tersedia."
]

pertanyaan = "Mengapa RAG dapat membantu mengurangi hallucination?"
jawaban, sumber = answer_rag(pertanyaan, documents, model_embed)

print("Sumber terpilih:")
for s in sumber:
    print("-", s)

print("\nJawaban model:")
print(jawaban)

Praktikum 6: contoh memakai FAISS agar retrieval lebih rapi

Jika jumlah chunk bertambah besar, retrieval manual masih bisa dipakai untuk latihan, tetapi vector database seperti FAISS jauh lebih praktis. Contoh ini memberi gambaran awal.

from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')
chunks = [
    "Preprocessing membersihkan teks.",
    "TF-IDF memberi bobot pada kata.",
    "RAG menggabungkan retrieval dan generation.",
    "Transformer memakai mekanisme attention."
]

emb = model.encode(chunks).astype('float32')
index = faiss.IndexFlatL2(emb.shape[1])
index.add(emb)

query = "Apa fungsi RAG dalam sistem tanya jawab dokumen?"
query_emb = model.encode([query]).astype('float32')
jarak, posisi = index.search(query_emb, k=2)

for idx in posisi[0]:
    print(chunks[idx])

Praktikum 7: contoh integrasi RAG sederhana dalam PHP

Untuk PHP, embedding sering dibuat lewat layanan eksternal atau proses Python terpisah. Namun alur logikanya tetap sama. Berikut contoh sederhana jika skor retrieval sudah tersedia.

<?php
define('GROQ_API_KEY', 'gsk_XXXX');
define('GROQ_MODEL', 'llama-3.1-8b-instant');
define('GROQ_URL', 'https://api.groq.com/openai/v1/chat/completions');

$chunks = [
    ['text' => 'Preprocessing membersihkan teks sebelum analisis.', 'score' => 0.71],
    ['text' => 'RAG menggabungkan retrieval dan generation.', 'score' => 0.92],
    ['text' => 'KNN adalah algoritma klasifikasi berbasis tetangga terdekat.', 'score' => 0.33],
];

usort($chunks, function($a, $b) {
    return $b['score'] <=> $a['score'];
});

$topChunks = array_slice($chunks, 0, 2);
$context = implode("\n\n", array_column($topChunks, 'text'));
$question = 'Mengapa RAG penting dalam sistem tanya jawab dokumen?';

$payload = [
    'model' => GROQ_MODEL,
    'temperature' => 0.2,
    'messages' => [
        [
            'role' => 'system',
            'content' => 'Jawab hanya berdasarkan konteks. Jika konteks tidak cukup, katakan dengan jujur.'
        ],
        [
            'role' => 'user',
            'content' => "Konteks:\n{$context}\n\nPertanyaan:\n{$question}"
        ]
    ]
];

$ch = curl_init(GROQ_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . GROQ_API_KEY
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

Kesalahan umum saat membuat RAG

Kesalahan pertama adalah retrieval yang asal-asalan. Kalau chunk yang diambil salah, jawaban model juga berisiko salah. Kesalahan kedua adalah prompt yang tidak tegas, sehingga model masih bercampur antara konteks dan pengetahuan umumnya. Kesalahan ketiga adalah chunking yang buruk. Kesalahan keempat adalah tidak menampilkan sumber atau setidaknya potongan context yang dipakai. Kesalahan kelima adalah mengira RAG menghilangkan semua hallucination. RAG mengurangi risiko, tetapi tetap perlu evaluasi.

RAG bukan obat ajaib. Jika dokumen sumber salah, lama, atau tidak relevan, jawaban yang dihasilkan juga tetap bisa menyesatkan.

Diskusi Mahasiswa dengan Sistem LLM

Tanyakan materi yang masih terkait Pembelajaran Mesin untuk Teks dan AI Generatif.

Siap Diskusi
Halo, saya siap membantu memahami materi praktikum, konsep, kode, studi kasus, UTS, UAS, dan mini project pada mata kuliah ini. Silakan tulis pertanyaan Anda.

Pembahasan dibatasi pada topik mata kuliah ini. Pertanyaan di luar tema akan ditolak secara otomatis.