← Journal
June 17, 2026·11 min read·Nasywan

MembangunSistemRAG(Retrieval-AugmentedGeneration)SederhanaDenganSupabaseVector&OpenAI

Bagaimana cara memberi memori khusus pada AI untuk menjawab dokumen internal perusahaan? Pelajari cara mengimplementasikan RAG menggunakan database Supabase Vector dan API OpenAI.

AIOpenAISupabaseVector DatabaseRAG
Membangun Sistem RAG (Retrieval-Augmented Generation) Sederhana Dengan Supabase Vector & OpenAI

Halo gess! Hari ini kita mau ngebahas topik AI yang lagi sangat panas di dunia industri teknologi: RAG (Retrieval-Augmented Generation).

Pasti kamu pernah mencoba menggunakan ChatGPT atau Claude untuk menjawab pertanyaan seputar data internal organisasi kamu. Hasilnya? AI tersebut pasti kebingungan atau bahkan berhalusinasi mengarang jawaban palsu. Ini wajar karena model bahasa besar (LLM) tersebut hanya dilatih menggunakan data publik internet sampai tahun tertentu saja.

Bagaimana solusinya? Apakah kita harus melatih ulang (fine-tuning) LLM tersebut dengan dokumen internal kita? Oh, tentu tidak. Fine-tuning itu proses yang sangat mahal, membutuhkan waktu berminggu-minggu, kartu grafis GPU mahal, and keahlian machine learning yang rumit.

Solusi terbaik dan standar industri saat ini adalah menggunakan metode RAG. RAG bertindak seperti memberikan 'buku referensi open-book' ke AI. Ketika user mengajukan pertanyaan, sistem kita akan mencari paragraf dokumen yang paling relevan dari database kita, menyisipkan paragraf tersebut sebagai konteks ke dalam instruksi prompt, lalu menyuruh LLM menjawab berdasarkan konteks dokumen tersebut.

Untuk mencari paragraf dokumen yang paling relevan, kita membutuhkan teknologi bernama Vector Database. Di tutorial ini, kita akan menggunakan Supabase Vector (yang menggunakan ekstensi pgvector di PostgreSQL) dan OpenAI API untuk memproses pertanyaan secara cerdas.

Yuk, kita bedah langkah demi langkah cara membuat sistem pintar ini! Siapkan database Supabase kamu, dan mari kita mulai petualangan AI kita!

Mengenal Konsep Embeddings: Representasi Makna Teks

Sebelum kita coding, mari kita pahami dulu apa itu Embeddings. Bagaimana komputer bisa tahu kalau kalimat 'Kucing melompat ke meja' memiliki makna yang mirip dengan 'Seekor meong meloncat ke atas bangku'? Secara teks, huruf-hurufnya sangat berbeda.

Embeddings mengubah teks menjadi array angka-angka desimal panjang (vektor). Array angka ini mewakili letak koordinat makna kalimat tersebut dalam ruang multi-dimensi. Kalimat dengan makna yang mirip akan memiliki jarak koordinat yang sangat dekat (disebut cosine similarity).

Kita menggunakan model text-embedding-3-small milik OpenAI untuk mengubah dokumen internal kita menjadi vektor koordinat tersebut. Hasil koordinat inilah yang akan kita simpan ke dalam database Supabase Vector.

Setup Database Supabase: Aktifkan pgvector

Langkah pertama, masuk ke SQL Editor di dashboard Supabase kamu.

supabase-setup.sqlsql
1-- Mengaktifkan ekstensi pgvector
2create extension if not exists vector;
3
4-- Membuat tabel dokumen
5create table document_chunks (
6 id uuid primary key default gen_random_uuid(),
7 content text not null, -- Potongan paragraf dokumen
8 embedding vector(1536) -- Array koordinat 1536 dimensi dari OpenAI
9);
10
11-- Membuat index similarity search agar pencarian cepat
12create index on document_chunks using hnsw (embedding vector_cosine_ops);

Selain tabel, kita juga butuh membuat database function (stored procedure) di SQL Editor.

match-documents.sqlsql
1create or replace function match_documents (
2 query_embedding vector(1536),
3 match_threshold float,
4 match_count int
5)
6returns table (
7 id uuid,
8 content text,
9 similarity float
10)
11language sql stable
12as $$
13 select
14 document_chunks.id,
15 document_chunks.content,
16 1 - (document_chunks.embedding <=> query_embedding) as similarity
17 from document_chunks
18 where 1 - (document_chunks.embedding <=> query_embedding) > match_threshold
19 order by document_chunks.embedding <=> query_embedding
20 limit match_count;
21$$;

Menghubungkan NodeJS, OpenAI, and Supabase Vector

Sekarang mari kita buat script untuk mencari dokumen dan mengirimkannya sebagai konteks ke ChatGPT.

src/lib/rag-engine.tstypescript
1import { createClient } from '@supabase/supabase-js';
2import OpenAI from 'openai';
3
4const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!);
5const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
6
7export async function askAIWithRAG(question: string) {
8 // 1. Mengubah pertanyaan user menjadi koordinat vektor
9 const embeddingResponse = await openai.embeddings.create({
10 model: 'text-embedding-3-small',
11 input: question,
12 });
13 const [{ embedding }] = embeddingResponse.data;
14
15 // 2. Mencari potongan dokumen paling relevan di Supabase Vector
16 const { data: matchedDocuments, error } = await supabase.rpc('match_documents', {
17 query_embedding: embedding,
18 match_threshold: 0.6, // Minimal kecocokan makna 60%
19 match_count: 3, // ...
20 });
21
22 if (error || !matchedDocuments) {
23 throw new Error('Gagal mencari dokumen referensi.');
24 }
25
26 // 3. Menggabungkan potongan dokumen menjadi satu teks konteks
27 const contextText = matchedDocuments.map(doc => doc.content).join('\n\n');
28
29 // 4. Mengirimkan instruksi ke GPT-4o dengan menyisipkan konteks
30 const chatResponse = await openai.chat.completions.create({
31 model: 'gpt-4o',
32 messages: [
33 {
34 role: 'system',
35 content: `Kamu adalah asisten pintar. Jawablah pertanyaan user HANYA berdasarkan konteks dokumen referensi berikut ini. Jika dokumen tidak mengandung jawaban, katakan sejujurnya.\n\nKonteks:\n${contextText}`
36 },
37 { role: 'user', content: question }
38 ]
39 });
40
41 return chatResponse.choices[0].message.content;
42}

Deep Dive: Chunking Strategies, Vector Metrics & Prompt Engineering

Dalam membuat RAG yang handal, ada dua rahasia penting: strategi chunking (pemotongan teks) and hybrid search. Chunking menentukan seberapa besar teks dipotong sebelum diubah menjadi vektor. Jika terlalu kecil, konteks makna kalimat akan hilang. Jika terlalu besar, akurasi vector distance akan menurun karena bercampur dengan bahasan lain.

Pola pemotongan terbaik adalah menggunakan recursive text splitter dengan overlap window. Misalnya kita potong setiap 1000 karakter, namun kita sisipkan 200 karakter dari potongan sebelumnya di awal potongan baru. Ini mencegah putusnya kalimat di tengah paragraf.

Sementara Hybrid Search menggabungkan pencarian kemiripan makna (Semantic Vector Search) dengan pencarian kata kunci eksak (Full-Text Search) PostgreSQL. Ini sangat penting ketika user mencari kata kunci yang berupa kode produk, nama orang kustom, atau singkatan tertentu yang tidak memiliki padanan makna di embeddings OpenAI. Kombinasi keduanya menghasilkan sistem RAG paling mantap!

Untuk mengimplementasikan hybrid search di PostgreSQL, kita menggunakan operator OR untuk menggabungkan pencarian vector similarity rpc dengan query pencarian text search @@ plainto_tsquery. Tentukan bobot relevansi (weight score) untuk masing-masing hasil pencarian. Ini adalah teknik andalan korporasi besar!

Mengenai Vector Metrics, ada tiga metrik utama: Cosine Distance (melihat sudut arah vektor), L2 Distance atau Euclidean Distance (melihat jarak garis lurus antar titik koordinat), and Inner Product. Untuk embeddings OpenAI, Cosine Distance adalah standard industri karena panjang vektornya ternormalisasi.

Selain itu, prompt engineering sangat menentukan kualitas jawaban AI. Kita harus membatasi kreativitas LLM (temperature set ke 0) agar AI tidak berhalusinasi. Tulis instruksi system prompt secara eksplisit: 'Jawablah HANYA menggunakan fakta yang tertulis dalam dokumen.

FAQ & Troubleshooting RAG Engine

Mari kita bahas beberapa pertanyaan and masalah yang sering terjadi di RAG:

  • Kenapa AI menjawab tidak tahu padahal infonya ada di dokumen? Cek parameter match_threshold. Jika diset terlalu tinggi (misal 0.85), PostgreSQL akan mem-filter out dokumen yang maknanya mirip tapi gaya bahasanya sedikit berbeda. Turunkan threshold ke 0.6 atau 0.5.
  • Bagaimana cara meng-update embedding jika dokumen diubah? Kamu harus menghapus potongan embedding lama di tabel, lalu jalankan ulang tokenization and request embedding ke OpenAI, baru simpan koordinat barunya.
  • Berapa chunk size yang paling ideal? Untuk teks umum berbahasa Indonesia, range 800-1200 karakter dengan overlap 150-200 karakter terbukti memberikan akurasi penemuan makna tertinggi.
  • Apakah pgvector di Supabase gratis? Ya, pgvector adalah extension open-source PostgreSQL. Supabase mengaktifkannya secara gratis untuk semua jenis database, termasuk project free tier!

Evaluasi Hasil RAG & Mengatasi Masalah Context Window Limits

Tantangan terbesar setelah sistem RAG kita berjalan adalah mengukur kualitas jawaban AI (evaluation). Apakah context yang dicari dari database benar-benar relevan? Apakah jawaban AI mengandung halusinasi? Kita bisa menggunakan kerangka evaluasi seperti Ragas or TruLens untuk memberikan nilai akurasi pada retrieve context and generate response.

Selain itu, jika dokumen referensi kita sangat tebal, kita akan terbentur batas limit context window LLM. Mengirimkan terlalu banyak context juga membuat performa AI melambat and tagihan token API membengkak. Strateginya, gunakan teknik Re-ranking (seperti Cohere ReRank) untuk menyeleksi ulang potongan dokumen paling relevan, sebelum dikirim ke ChatGPT.

Kita juga bisa menerapkan metadata filtering di Supabase Vector. Misalnya, batasi pencarian dokumen hanya pada departemen tertentu or rentang tanggal rilis tertentu. Ini memotong noise data yang tidak perlu, sehingga AI bisa fokus menjawab dengan cepat and tepat.

Sebagai tambahan, simpanlah riwayat percakapan user (chat history) di database PostgreSQL. 5 terlebih dahulu. Ini menghasilkan query vector yang jauh lebih akurat, karena membawa konteks percakapan sebelumnya. Hasil RAG pun menjadi semakin pintar! Kita juga bisa menyimpan metadata pencarian untuk keperluan analytics di masa mendatang, membantu kita memahami topik apa saja yang paling sering ditanyakan oleh pengguna.

Kesimpulan

RAG adalah solusi cerdas untuk mengatasi keterbatasan memori LLM. Dengan memanfaatkan Supabase Vector dan pgvector, kita tidak perlu memelihara server database vector terpisah. Kita bisa tetap menggunakan infrastruktur PostgreSQL yang sudah sangat matang.

Kombinasi embedding OpenAI dan kueri similarity search Supabase memastikan asisten AI kita selalu memberikan jawaban akurat berdasarkan dokumen internal asli organisasi kita. Selamat mencoba membangun chatbot pintar kamu sendiri! Teruslah belajar dan berinovasi!

Glosarium Penting Artificial Intelligence & RAG

Retrieval-Augmented Generation (RAG) adalah metode menyuntikkan dokumen referensi ke dalam prompt instruction LLM agar AI bisa menjawab berdasarkan data internal organisasi.

Vector Database adalah database khusus (seperti pgvector di Supabase) yang menyimpan data koordinat vektor teks untuk kueri similarity search.

Embeddings adalah representasi matematis berbentuk array angka desimal panjang yang melambangkan kemiripan makna semantik sebuah teks.

Cosine Similarity adalah metrik penghitungan sudut untuk menentukan seberapa dekat makna semantik antara pertanyaan user dengan dokumen database.

Chunking adalah taktik pemotongan dokumen panjang menjadi potongan paragraf kecil agar muat ke dalam limit window context LLM.

Overlap Window adalah jumlah karakter dari chunk sebelumnya yang kita sisipkan ke chunk berikutnya agar makna kalimat tidak terputus di tengah.

Hybrid Search adalah teknik menggabungkan semantic vector search dengan keyword full-text search untuk meningkatkan akurasi pencarian nama produk or kode.

Temperature adalah parameter pengaturan kreativitas LLM. Kita men-set temperature ke 0 agar AI memberikan jawaban faktual and tidak berhalusinasi.

Stored Procedure (RPC) adalah fungsi SQL yang kita simpan langsung di database Supabase untuk mempercepat perhitungan cosine distance vector.

Strategi Chunking dan Tagging Metadata yang Efektif

Keberhasilan sistem RAG sangat ditentukan oleh kualitas data yang dikirimkan ke model LLM melalui prompt context. Strategi pemotongan dokumen (chunking) menggunakan recursive character text splitter membantu menjaga keutuhan konteks semantik dari setiap bagian teks. Selain itu, menyematkan metadata tagging seperti kategori, nama dokumen asal, dan tanggal pembuatan pada setiap vektor di database Supabase Vector memungkinkan kita melakukan filter pencarian yang lebih spesifik sebelum menghitung kesamaan kosinus vektor.

Untuk mencegah terputusnya informasi penting di perbatasan potongan teks, kita harus mengatur nilai chunk overlap yang proporsional, idealnya sekitar sepuluh hingga dua puluh persen dari total ukuran chunk. Dengan begitu, kalimat yang terpotong di akhir satu chunk akan tetap utuh di awal chunk berikutnya. Hal ini sangat meningkatkan akurasi retrieval model saat mencari jawaban atas pertanyaan user yang kompleks yang membutuhkan korelasi data dari beberapa halaman dokumen sekaligus.

(Share)

(Next essay)

Selamat Tinggal Tagihan Cloud Mahal: Panduan Self-Hosting Aplikasi Web Dengan Coolify