L
Artificial Intelligence & LLM • Literally Web ID

Implementasi Retrieval-Augmented Generation (RAG) dengan LLM dan Vector Database

⏱️ 15 menit baca • 📅 20 Oct 2026 • 👁️ 3 views
Implementasi Retrieval-Augmented Generation (RAG) dengan LLM dan Vector Database

1. Konteks Industri & Analisis Akar Masalah

Di era kecerdasan buatan generatif, Large Language Models (LLM) seperti GPT-4, Claude 3.5, dan Llama 3 telah mengubah lanskap aplikasi enterprise secara drastis. Namun, LLM memiliki kelemahan mendasar: mereka dilatih pada data publik hingga batas waktu tertentu (knowledge cutoff) dan tidak memiliki akses ke data internal perusahaan yang bersifat rahasia, dinamis, dan spesifik domain. Mengandalkan fine-tuning untuk setiap pembaruan data perusahaan tidak hanya memakan biaya komputasi yang sangat masif, tetapi juga rentan terhadap catastrophic forgetting dan halusinasi.

Retrieval-Augmented Generation (RAG) hadir sebagai solusi arsitektural standar industri untuk menjembatani kesenjangan ini. RAG menggabungkan kemampuan pemahaman bahasa alami dari LLM dengan sistem pencarian informasi eksternal berbasis Vector Database (seperti Qdrant atau Pinecone). Tantangan terbesar bagi seorang Principal Web & Infrastructure Systems Architect bukanlah sekadar memanggil API LLM, melainkan merancang pipeline end-to-end yang latensinya rendah, skalabel di bawah beban tinggi (high concurrency), aman dari injeksi prompt, serta efisien dalam penggunaan token.

Sebelum vs Sesudah Penerapan RAG

Parameter Sebelum RAG (Pure LLM / Fine-Tuning) Sesudah RAG (Arsitektur Enterprise)
Akurasi Data Sering berhalusinasi, tidak tahu data internal perusahaan terbaru. Sangat akurat, bersumber langsung dari dokumen internal terverifikasi.
Biaya Pembaruan Sangat mahal ( retraining / fine-tuning berkala ). Sangat murah (cukup re-index dokumen baru ke Vector DB).
Keamanan & Privasi Data sensitif dikirim mentah atau tercakup dalam bobot model publik. Kontrol akses ketat pada dokumen sebelum diumpankan ke context window.
Auditabilitas Mustahil melacak sumber referensi jawaban model. Dilengkapi source citation (nomor halaman, ID dokumen, URI).

2. Konsep Inti & Deep Dive Arsitektur

Arsitektur RAG under the hood melibatkan dua fase utama: Inbound Ingestion Pipeline (persiapan data offline/background) dan Runtime Query Pipeline (eksekusi online saat user bertanya).

Alur Eksekusi Data (ASCII Flow Chart)

+-------------------------------------------------------------------------+
|                         INBOUND INGESTION PIPELINE                      |
|                                                                         |
|  [ Internal Docs: PDF, MD, HTML ]                                       |
|                 |                                                       |
|                 v                                                       |
|  [ Text Extractor & Cleaner ]                                           |
|                 |                                                       |
|                 v                                                       |
|  [ Smart Chunking Strategy (e.g., 512 tokens, 10% overlap) ]            |
|                 |                                                       |
|                 v                                                       |
|  [ Embedding Model (e.g., text-embedding-3-small / BGE-M3) ]            |
|                 |                                                       |
|                 v                                                       |
|  [ Vector Database (Qdrant / Pinecone) ] <--- Storage Metadata          |
+-------------------------------------------------------------------------+

+-------------------------------------------------------------------------+
|                          RUNTIME QUERY PIPELINE                         |
|                                                                         |
|  [ User Prompt / Question via Web API (Go / Node.js) ]                  |
|                 |                                                       |
|                 v                                                       |
|  [ Query Embedding Generator ]                                          |
|                 |                                                       |
|                 v                                                       |
|  [ Vector DB Similarity Search (Cosine / Dot Product) ]                 |
|                 |                                                       |
|                 v                                                       |
|  [ Context Assembler & Prompt Engineering ]                             |
|                 |                                                       |
|                 v                                                       |
|  [ LLM Inference Engine (OpenAI / vLLM / Ollama) ]                      |
|                 |                                                       |
|                 v                                                       |
|  [ Response to User + Source Citations ]                                |
+-------------------------------------------------------------------------+

[!IMPORTANT] Kualitas keluaran RAG 90% ditentukan oleh kualitas Chunking Strategy dan relevansi hasil pencarian di Vector Database, bukan semata-mata kecerdasan LLM-nya.


3. Perbandingan Komparatif / Analisis Pendekatan

Dalam membangun infrastruktur penyimpanan vektor, arsitek dihadapkan pada pilihan antara menggunakan Managed Cloud Vector DB (seperti Pinecone) atau Self-Hosted Vector DB (seperti Qdrant atau Milvus).

Aspek Perbandingan Pinecone (Managed) Qdrant (Self-Hosted / Cloud)
Setup & Maintenance Zero maintenance, otomatis scale-up. Membutuhkan provisioning server, backup, & monitoring.
Latency (P99) Rendah (bergantung pada region cloud). Sangat rendah jika di-deploy dekat dengan backend app (lokal LAN).
Biaya Operasional Berdasarkan jumlah vector count & operasi tulis/baca (mahal di skala besar). Biaya tetap (fixed cost) berdasarkan spesifikasi RAM/CPU server.
Fitur Filter Lanjutan Mendukung metadata filtering standar. Sangat powerful dengan payload filtering dan payload indexing.
Compliance & GDPR Terikat pada kebijakan vendor cloud pihak ketiga. 100% data berada di infrastruktur internal perusahaan.

4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menulis kode implementasi, pastikan infrastruktur sistem memenuhi spesifikasi berikut:

  • OS: Ubuntu 22.04 LTS / Debian 12 (Production Grade)
  • Runtime: Python 3.11+, Node.js 20+ atau Go 1.22+
  • Vector Database: Qdrant v1.9+ (berjalan via Docker Container)
  • Web Server / Reverse Proxy: Nginx dengan konfigurasi SSL/TLS Let's Encrypt
  • Memory (RAM): Minimal 8GB (direkomendasikan 16GB untuk menampung embedding cache)

Setup Qdrant Menggunakan Docker Compose

Buat file docker-compose.yml di server produksi Anda:

version: '3.8'

services:
  qdrant:
    image: qdrant/qdrant:v1.9.0
    container_name: enterprise_qdrant
    restart: always
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - /opt/qdrant/storage:/qdrant/storage
    environment:
      - QDRANT__SERVICE__HTTP_PORT=6333
      - QDRANT__SERVICE__GRPC_PORT=6334
    networks:
      - rag_internal

networks:
  rag_internal:
    driver: bridge

Jalankan container dengan perintah:

sudo mkdir -p /opt/qdrant/storage
docker-compose up -d

5. Panduan Implementasi Langkah demi Langkah

Berikut adalah implementasi Ingestion Pipeline dan Query Engine menggunakan Python dengan pustaka langchain, qdrant-client, dan fastapi untuk menyediakannya sebagai layanan web backend.

Skrip 1: Ingestion & Chunking Pipeline (ingest.py)

import os
from typing import List
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_openai import OpenAIEmbeddings
from qdrant_client import QdrantClient
from qdrant_client.http import models
from qdrant_client.http.models import Distance, VectorParams

# Konfigurasi Environment
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "sk-your-openai-key")
QDRANT_HOST = "localhost"
QDRANT_PORT = 6333
COLLECTION_NAME = "enterprise_knowledge_base"

def init_vector_db(client: QdrantClient):
    collections = client.get_collections().collections
    exists = any(col.name == COLLECTION_NAME for col in collections)
    
    if not exists:
        client.create_collection(
            collection_name=COLLECTION_NAME,
            vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
        )
        print(f"Koleksi '{COLLECTION_NAME}' berhasil dibuat.")

def run_ingestion(data_dir: str):
    print("Memulai proses ekstraksi dokumen...")
    loader = DirectoryLoader(data_dir, glob="**/*.md", loader_cls=TextLoader)
    documents = loader.load()

    # Chunking strategi: 512 token per chunk dengan overlap 50 token
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=512,
        chunk_overlap=50,
        length_function=len,
    )
    chunks = text_splitter.split_documents(documents)
    print(f"Total chunks dihasilkan: {len(chunks)}")

    embeddings = OpenAIEmbeddings(model="text-embedding-3-small", openai_api_key=OPENAI_API_KEY)
    client = QdrantClient(host=QDRANT_HOST, port=QDRANT_PORT)
    
    init_vector_db(client)

    texts = [chunk.page_content for chunk in chunks]
    metadatas = [chunk.metadata for chunk in chunks]
    vectors = embeddings.embed_documents(texts)

    points = [
        models.PointStruct(
            id=idx,
            vector=vector,
            payload={"text": text, **meta}
        )
        for idx, (vector, text, meta) in enumerate(zip(vectors, texts, metadatas))
    ]

    client.upsert(
        collection_name=COLLECTION_NAME,
        points=points
    )
    print("Ingestion selesai dan data berhasil disimpan ke Qdrant!")

if __name__ == "__main__":
    run_ingestion("./internal_docs")

Skrip 2: FastAPI Runtime RAG Server (app.py)

import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from qdrant_client import QdrantClient
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage

app = FastAPI(title="Enterprise RAG Gateway", version="1.0.0")

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "sk-your-openai-key")
QDRANT_HOST = "localhost"
QDRANT_PORT = 6333
COLLECTION_NAME = "enterprise_knowledge_base"

class QueryRequest(BaseModel):
    question: str
    top_k: int = 3

@app.post("/api/v1/query")
async def query_rag(req: QueryRequest):
    try:
        # 1. Inisialisasi Klien
        embeddings = OpenAIEmbeddings(model="text-embedding-3-small", openai_api_key=OPENAI_API_KEY)
        qdrant_client = QdrantClient(host=QDRANT_HOST, port=QDRANT_PORT)
        
        # 2. Embed Query Pengguna
        query_vector = embeddings.embed_query(req.question)
        
        # 3. Vector Search di Qdrant
        search_results = qdrant_client.search(
            collection_name=COLLECTION_NAME,
            query_vector=query_vector,
            limit=req.top_k
        )
        
        # 4. Susun Konteks dari Hasil Pencarian
        context_texts = [hit.payload["text"] for hit in search_results]
        context_block = "\n\n---\n\n".join(context_texts)
        
        # 5. Konstruksi Prompt untuk LLM
        system_prompt = (
            "Anda adalah Asisten AI perusahaan yang sangat akurat. "
            "Jawablah pertanyaan pengguna HANYA berdasarkan konteks dokumen internal yang diberikan di bawah ini. "
            "Jika jawaban tidak ditemukan dalam konteks, katakan 'Maaf, informasi tidak tersedia dalam dokumen internal.'"
        )
        
        user_prompt = f"Konteks Dokumen:\n{context_block}\n\nPertanyaan Pengguna: {req.question}"
        
        # 6. Panggil LLM (GPT-4o-mini)
        chat = ChatOpenAI(model="gpt-4o-mini", temperature=0.0, openai_api_key=OPENAI_API_KEY)
        response = chat.invoke([
            SystemMessage(content=system_prompt),
            HumanMessage(content=user_prompt)
        ])
        
        return {
            "status": "success",
            "question": req.question,
            "answer": response.content,
            "sources": [hit.payload.get("source", "Unknown") for hit in search_results]
        }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

6. Bedah Kode & Penjelasan Detail Baris Kunci

  1. RecursiveCharacterTextSplitter: Digunakan untuk memecah dokumen panjang berdasarkan hierarki karakter (paragraf, baris baru, spasi). Parameter chunk_size=512 menjaga agar konteks tidak terlalu besar sehingga menghemat token LLM, sementara chunk_overlap=50 memastikan tidak ada informasi penting yang terpotong di batas antar-chunk.
  2. Distance.COSINE: Parameter metrik jarak di Qdrant. Cosine similarity sangat ideal untuk membandingkan arah vektor orientasi teks tanpa terpengaruh oleh panjang absolut dokumen.
  3. temperature=0.0: Pada ChatOpenAI, nilai temperatur nol memaksa model memberikan jawaban yang deterministik, meminimalisir risiko halusinasi kreatif, serta menjaga konsistensi jawaban enterprise.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Di lingkungan produksi enterprise dengan traffic tinggi (ribuan concurrent queries per detik), arsitektur monolitik Python di atas tidak akan mencukupi. Pendekatan produksi yang direkomendasikan adalah:

  • Load Balancing Nginx: Menempatkan beberapa instance app.py di belakang reverse proxy Nginx dengan metode least_conn.
  • Async Worker & Queue: Untuk Ingestion Pipeline, proses ekstraksi dokumen besar tidak boleh dijalankan secara sinkron di HTTP request. Gunakan queue seperti Redis Queue (RQ) atau Celery yang dikelola via Supervisor.
  • Caching Layer: Memanfaatkan Redis untuk menyimpan hasil embedding dari pertanyaan-pertanyaan yang sering diajukan (frequently asked queries) guna menekan latensi hingga di bawah 50ms dan memangkas biaya API OpenAI secara signifikan.

8. Common Pitfalls, Anti-Patterns & Solusi

[!WARNING] Anti-Pattern Terbesar: Menggunakan chunk size terlalu besar (misal: 4000 token) dengan asumsi "agar konteks lengkap". Ini justru membuat embedding kehilangan spesifisitas semantik dan menurunkan akurasi similarity search.

  • Pitfall 1: Mengabaikan pembersihan karakter khusus / markdown kotor pada dokumen mentah yang mengakibatkan noise pada vektor.
  • Pitfall 2: Tidak mengamankan endpoint API dengan rate limiting, menyebabkan serangan denial of wallet akibat lonjakan konsumsi token LLM eksternal.
  • Solusi: Terapkan rate limiter berbasis Redis di Nginx atau di level aplikasi FastAPI.

9. Benchmark, Metrik Kinerja & Tuning Performa

Pengujian performa API RAG dapat dilakukan menggunakan tool benchmark k6. Buat skrip load-test.js:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 50 },
    { duration: '1m', target: 200 },
    { duration: '30s', target: 0 },
  ],
};

export default function () {
  const url = 'http://localhost:8000/api/v1/query';
  const payload = JSON.stringify({
    question: 'Bagaimana prosedur klaim cuti tahunan perusahaan?',
    top_k: 3,
  });

  const params = {
    headers: { 'Content-Type': 'application/json' },
  };

  const res = http.post(url, payload, params);
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 1500ms': (r) => r.timings.duration < 1500,
  });
  sleep(1);
}

Jalankan pengujian:

k6 run load-test.js

Metrik utama yang dipantau adalah Time to First Token (TTFT) dan P99 Latency.


10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan sistem RAG ke production environment, pastikan checklist berikut terpenuhi:

  • Konfigurasi Qdrant persistence volume telah di-backup secara otomatis berkala.
  • Seluruh kunci API (OPENAI_API_KEY) disimpan di environment variable aman (Secret Manager), bukan hardcode.
  • Rate limiting aktif di Nginx atau FastAPI untuk mencegah penyalahgunaan.
  • Sistem logging terpusat (ELK Stack / Prometheus & Grafana) memantau penggunaan token harian.
  • Fallback mechanism disiapkan jika LLM provider utama mengalami downtime.

Dengan mengikuti panduan komprehensif ini, Anda kini memiliki fondasi arsitektur enterprise yang tangguh, aman, dan siap produksi untuk mengimplementasikan Retrieval-Augmented Generation secara optimal.

🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server