pgvector untuk RAG: kenapa aku tidak pakai vector database terpisah
AI WhatsApp bot pakai pgvector di PostgreSQL, bukan Pinecone. Satu database, zero vendor baru, dan performanya cukup di scale-ku.
Context
Project AI WhatsApp bot: multi-tenant chatbot dengan RAG (Retrieval-Augmented Generation). Bot harus jawab pertanyaan customer berdasarkan data produk/layanan tiap tenant — bukan dari pengetahuan umum model AI.
RAG singkatnya: dokumen produk dipecah jadi chunk, tiap chunk diubah jadi embedding (array angka), disimpan. Saat user tanya, pertanyaannya juga di-embed, lalu dicari chunk yang paling mirip. Chunk itu dikirim ke AI sebagai konteks jawaban.
Pertanyaannya: embedding itu disimpan di mana?
Options yang dipertimbangkan
Option A: Pinecone / vector database dedicated
- Pro: managed, dioptimasi khusus untuk vector search di jutaan vector
- Pro: ANN index mature, metadata filtering built-in
- Con: service baru = infra baru, billing baru, vendor lock-in baru
- Con: data produk tetap di PostgreSQL. Sekarang ada dua sumber kebenaran yang harus disinkronkan
Option B: pgvector (yang dipilih)
Extension PostgreSQL yang menambah tipe data vector dan index untuk similarity search.
- Pro: satu database. Produk, chunk, embedding, tenant — semua di Postgres
- Pro: sudah jalan di stack yang ada. Tidak ada infra tambahan
- Con: di skala jutaan vector, ANN-nya kalah cepat dari dedicated vector DB
Option C: Qdrant / Weaviate self-hosted
- Pro: open source, fitur vector search lengkap
- Con: tetap satu service tambahan yang harus di-deploy, dimonitor, dan di-backup
Keputusan
pgvector. Alasannya bukan performa — tapi jumlah sumber kebenaran.
Kalau embedding di Pinecone dan produk di Postgres, tiap produk di-update aku harus sync ke dua tempat. Sync gagal = bot jawab pakai data basi. Dengan pgvector, update produk dan re-embedding terjadi dalam satu transaksi database yang sama.
Setup-nya:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE document_chunks (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
document_id uuid NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
content text NOT NULL,
embedding vector(1536) NOT NULL
);
CREATE INDEX ON document_chunks
USING hnsw (embedding vector_cosine_ops);
Query retrieval-nya sederhana:
SELECT content
FROM document_chunks
WHERE organization_id = $1
ORDER BY embedding <=> $2
LIMIT 5;
<=> adalah operator cosine distance dari pgvector. Multi-tenant isolation tetap enforced lewat organization_id — filter dulu, baru similarity search. Ini penting: filter kolom biasa dulu supaya search space kecil, bukan sebaliknya.
Chunking strategy
Dokumen dipotong sekitar 512 token per chunk, dengan overlap 128 token antar chunk. Overlap supaya konteks yang kepotong di batas chunk tidak hilang — kalimat yang kena potong tetap utuh di salah satu chunk.
Trade-off yang aku terima
- Di scale jutaan vector per tenant, pgvector akan jadi bottleneck. Solusiku: menerima risiko itu. Scale-ku sekarang di ribuan chunk per tenant, bukan jutaan. Kalau sampai jutaan, migrasi ke dedicated vector DB adalah masalah yang bagus untuk dimiliki.
- Index HNSW makan RAM. Ini biaya yang harus dipantau seiring data tumbuh.
- Re-embedding besar (misal ganti model embedding) berarti rewrite semua chunk. Aku belum pernah melakukannya di production — rencanaku: background job per tenant, bukan big-bang.
Catatan: RAG tidak dipakai untuk semua query
Satu keputusan yang sama pentingnya: query yang deterministic tidak lewat AI sama sekali. Pertanyaan “harga produk X” di-detect via keyword, langsung query database, format jawaban, kirim. Hemat 2–3 detik response time dan menghindari halusinasi.
Detail lengkapnya ada di case study, termasuk kenapa model AI tertentu gagal disiplin function-calling.
Consequences
- Satu backup strategy untuk semua data. Embedding ikut ke-backup bareng data produk.
- Tidak ada vendor lock-in di layer vector. Postgres jalan di mana saja.
- Response time bot: < 1 detik untuk query keyword, 3–5 detik untuk query yang lewat AI + RAG.
References
- pgvector — GitHub — extension, operator, dan tipe index (HNSW, IVFFlat)
- PostgreSQL docs —
CREATE EXTENSION, transaction behavior - Case study: AI WhatsApp Bot — angka lengkap: 40+ API routes, 15+ tables, 3 model AI
- Postmortem: try/catch middleware di Hono — bug nyata dari project yang sama