Ritreval Augmented Generation 1
Bogor, 16 Desember 2025: Hujan, Noah nangis ngamuk2 mau cookies
Pada catatan ini insyaAllah akan terdapat bagaimana cara
- Memberi indeks pada kumpulan dokumen dan bagaimana cara membersihkan (biasa disebut dengan preprocessing) sehingga aplikasi yg kita bentuk dapat menemukan informasi yang relevan terhadap pertanyaan.
- Mengambil atau menarik data eksternal melalui indeks tersebut dan menggunakan sebagai konteks untuk LLM sehingga dapat menghasilkan nilai keluaran yang berlandaskan data.
Pertama catatan ini akan menjelaskan bagaimana melibatkan proses awal (preprocessing) pada dokumen (misalkan PDF, word, atau data dalam bentuk dokumen lainnya) kedalam format yang dapat dipahami dan dicari oleh LLM. Teknik tersebut adalah RAG, retrieaval-augmented generation.
Untuk menggapainya ada 4 langkah;
- Mengambil nilai text dari dokumen.
- Memecahnya kedalam bentuk yang teratur.
- Mengkonversi kalimat atau kata kedalam bentuk angka yang dapat dipahami oleh komputer.
- Menyimpan kumpulan angka representasi dari text sehingga dapat mudah dicari dan dipanggil yang berguna sebagai data atau konteks yg relevan untuk menjawab pertanyaan.
Image

Embeddings (Konversi text kedalam angka)
Embedding adalah sebuah proses merubah tipe data text kedalam deret angka. Namun kita tidak dapat mengembalikan deret angka tersebut ke bentuk text awalnya, maka dari itu proses ini akan menyimpan text dan nilai embedding-nya.
Embeddings sebelum adanya LLM
Lama sebelum LLM, proses embedding ini sudah dilakukan, misalkan untuk mencari full-text dari sebah website atau klasifikasi apakah sebuah email ini spam atau tidak. Contohnya dapat dilihat disini
- What a sunny day
- Such bright skies today
- I haven't seen a sunny day in weeks.
Kalimat I haven't seen a sunny day in weeks memliki nilai sequance 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 1. Deret angka tersebut adalah sparse embedding atau sparse vector. Kita dapat menggunakan sparse vector untuk beberapa hal, misalkan; mencari text pada beberapa dokumen, kita dapat menghitung dari dokumen-dokumen tersebut kata kunci yang sesuai pada dokumen yang dicari.
Kekurangan model tersebut adalah tidak memperhatikan makna dari kata, hanya menfokuskan apakah nilai yang dicari mengandung kata tersebut atau tidak. Misalkan kalimat Sunny Day dan Bright Skies adalah makna yang sama, akan tetapi dengan model embedding ini kata tersebut dianggap tidak sama.
InsyaAllah pada catatan ini juga akan dibahas terkait Semantic Embeddings, dimana metode tersebut mampu menghadapi limitasi dengan memanfaatkan deret angka dalam memahami text alih-alih hanya menggunakan arti makna satu kata.
Embeddings pada LLM
Kita akan memahami apa itu Embeddings Model. Embeddings model adalah salah satu cabang atau salah satu bagian dari proses pelatihan LLM. Pada awal catatan ini, kita mengetahui bahwa saat proses pelatihan (supply data) LLM dilatih menggunakan informasi dalam bentuk kata-kata yang sangat banyak sehingga membuat model dapat memprediksi dan men-generate kalimat selanjutan dari input yang diberikan.
Kemampuan dalam melanjutkan kata ini berasal dari pemahaman dari makna kata (semantics, understanding of meaning), belajar untuk memahami bagaimana kata digunakan, bagaimana makna kata digabung dengan kata lainnya. Makna kata dirubah kedalam bentuk vektor menggunakan model embedding sehingga dapat digunakan untuk beberapa tujuan tertentu.
Pada praktiknya, Embeddings model ini dibangun khusus untuk tujuan tersebut sehingga kualitas dari proses embeddings ini berkualitas. Embeddings model adalah sebuah algoritma yang menerima nilai masukan dalam betuk text dan nilai keluaran dalam bentuk kumpulan angka. Bisa dalam bentuk vector atau dense/matrix.
Info
Banyak embedding model yang ada diluar, berikut saya lampirkan rangking embedding model yang tersedia pada HuggingFace. Embedding Leaderboard
Penjelasan Semantic Embeddings
Katakan ada 3 kata Pet, Dog dan Lion, kira2 dari ketiga kata tersebut yang mana yang mirip dengan yang lainnya. Umumnya kita akan menjawab yang mirip adalah pet dan dog. Namun komputer tidak memahami hal tersebut, ingat komputer hanya memahami angka. Dibelakang layar kata tersebut harus dirubah kedalam bentuk vektor menggunakan proses embeddings. Vektor tersebut digunakan sebagai nilai input cosine similiarity guna mengetahui kemiripan dari setiap kata. Jika nilai Cosine Similiarty sama dengan 1 atau mendekati satu maka kemiripan dari kata tersebut tinggi dan jika mendekati ke atau hingga ke nilai 0 maka tingkat kemiripan rendah.
Lab cosine similiarity
Lalu apa benang merahnya ?
Dengan proses embeddings yang merubah data dengan bentuk kata atau text bersamaan dengan maknanya kedalam bentuk vektor membuat LLM dapat menemukan data yang relevan atas pertanyaan yang diterima.
Merubah dokumen ke dalam text
Dokumen dapat berupa PDF, text, CSV atau bisa didalam bentuk Web. Langchain memliki beberapa class loader yang dapat membantu mengambil nilai dalam format tertentu kedalam bentuk text menggunakan class Document.
Code
from langchain_community.document_loaders import TextLoader
text_data = TextLoader("C:/Users/Administrator/Documents/LangChainLabAssets/Data.txt")
text_data.load()
## [Document(metadata={'source': 'C:/Users/Administrator/Documents/LangChainLabAssets/Data.txt'}, page_content="I'm the data inside file name Data.txt")]
More detail lihat di lab document;
Beberapa contoh diatas, salah satunya melakukan ekstraksi dari dokumen kedalam class Document. Namun ada masalah lain, yaitu bagaimana jika dokumen memiliki banyak halaman dan mengandung banyak kalimat informasi. Untuk mengatasi masalah ini kita harus memecah data tersebut kedalam potongan yang dapat diatur. Setelah pemotongan tersebutlah kita baru melakukan embedding dan melakukan pencarian makna (semantic search). Oke next step kita akan membahas hal tersebut.
Splitting Text kedalam bentuk Chunks
Sekilas jika dipikirkan memang terlihat sulit untuk memecah kumpulan kalimat kedalam pecahan2 namun dengan mempertahankan makna dari setiap kata. Untungnya langchain memliki RecursiveCharacterTextSplitter untuk mempermudah memecah kalimat kedalam bentuk yang lebih kecil namun masih memliki makna.
Yg dilakukan oleh RecursiveCharacterTextSplitter adalah sebagai berikut;
- Membuat list seperator paragraf
\n\n, new line\ndan space - Memotong berdasarkan
chunk size, katakan 1000, maka maksimal kalimat yang diambil tidak bisa lebih dari 1000. Jika paragraf melebih besaranchunk sizemaka yang diambil kedalam class document adalah text yang dipotong berdasarkan makna, sehingga pada class document bisa jadi berisi kurang dari 1000 karakter. - Jika class document sudah semuanya terpenuhi sesuai besaran
chunk sizemaka class document selanjutnya berisi panjang kata (makna) sebesarchunk_overlap. Pelakukan yang sama yang diambil adalah kata dengan makna maksimal sebesarchunk_overlaptidak langsung potong.
Create Documents class from raw text
Katakan data yang kita miliki tidak bisa digunakan pada document loader, misalkan kita sudah memliki text mentah raw string. Kita dapat menggunakan method create_documents untuk membtuh documents class.
Generating Text Embeddings
Langchain memliki Embedding class untuk berinteraksi dengan Embeddings Model. Class tersebut menyediakan 2 fungsi;
- Untuk embeddings document
- Untuk embeddings query (pertanyaan)
Kita akan menggunakan interface OllamaEmbeddings untuk beriteraksi dengan model ollama khusus untuk embeddings2. Pada catatan kali ini saya menggunakan model nomic-embed-text. Setelah membuat object Ollama Embeddings kita dapat memanggil fungsi embed_documents atau embed_query.
Lab
Untuk hands-on dapat melihat pada lab embeddings text
Menyimpan Embeddings pada Vector Store
Warning
Ketika catatan bagian ini sudah hampir 70% saya selesaikan, ternyata ketika baca documentasi saat catatan ini dibuat (22 Desember 2025) dari PGVector lebih baik kita menggunakan PGVectorStore alih-alih PGVector. Maka dari itu beberapa lab saya buat as is, namun saya buat juga lab ke-2 yang menggunakan PGVectorStore. Jadi setelah bagian Adding documents kedalam vector store beralih ke lab yang menggunakan PGVectorStore.

Vector store adalah sebuah database yang dibentuk untuk menyimpan vector dan melakukan berbagaimacam kalkulasi seperti consine similiarity dsb. Berbeda dengan database umum lainnya yang menyimpan dalam bentuk yang terstruktur, vector store dapat menampung unstructured data seperti text dan gambar. Namun mirip dengan DB pada umunnya vector store juga dapat menjalankan operasi CRUD.
alur data

Gambar diatas menjelaskan bagaimana data dirubah kedalam bentuk vector, disimpan lalu dipanggil kembali ketika membutuhkan informasi.
Diluar sana ada beberapa penyedia vector store, kita dapat memilih sesuai kebutuhan kita. Vector store mana yang kita pilih tergantung kebutuhan misalkan dari sisi biaya, ukurannya, meta data filteringnya, serta performa, dan masih banyak lainnya.
InsyaAllah pada catatan kali ini saya akan menggunakan Postgresl SQL, kita bisa menggunakan PSQL umumnya namun dengan tambahan ekstensi pgvector.
Another provicers
Ada providers lain yang saya sudah buatkan catatan-nya. Yaitu ChromaDB, untuk melihatnya dapat merujuk ke chroma DB
Berkenalan dengan PSQL ekstensi pgvector
Saat ini saya menggungnakan pgvector yang sudah tinggal pakai menggunakan docker. Images yang digunakan adalah images PSQL yang sudah terinstall ekstensi pgvector sehingga kita tida perlu lagi menginstall ekstension tersebut. Berikut adalah image yang digunakan berikut syntax men-download image pgvcetor.
How to run
Untuk installasi pgevector dapat merujuk ke how to install ekstension of pgvector
Jika images sudah berjalan, kita perlu menjalankan images, kita dapat menggunakan perintah run pada docker seperti dibawah ini
Code
docker run
--name pg_vector_farras
-p 6060:5432
-d
-e POSTGRES_USER=farras
-e POSTGRES_PASSWORD=farras
-e POSTGRES_DB=farraslang
pgvector/pgvector:pg18-trixie
Sedikit catatan tentang Doceker (qaddarullah catatan hilang, masih ada di drive lama dan kemungkinan besar hilang) perintah diatas untuk membuat sebuah container (images yang berjalan) dengan nama container pg_vector_farras.
Parameter -p adalah untuk membypas port pada container yang mana 5432 adalah default psql ke port outside 6060, sehingga psql dapat kita akses menggunakan port tersebut.
Parameter -d adalah perintah detach agar container jalan dibackgroud.
Parameter -e adalah perintah ke docker agar membuat parameter dengan key-value yang diberikan.
Teriakhir adalah image yang ingin dijalankan, pada case ini kita mau menjalankan image pg_vecto yang baru saja kita pull.
List env pg_vector
Diatas kita melihat baha parameter -e memberikan nilai key-value, untuk melihat daftar env yang tersedia pada image dapat dilihat pada docker hub env psql
Jika kita seudah menjalankan perintah run pada docker, insyaALlah jika tidak ada error maka akan muncul ID container. Untuk memastikan apakah container sudah berjalan atau belum kita dapat menggunakan perintah berikut;
Code
Selanjutnya kita perlu masuk kedalam container tersebut menggunakan perintah exec. Hmmm ini seperti kita masuk ke terminal linux server atau linux menggunakan cli alih-alih user interface, Namun yang membedakan adalah dengan perintah ini kita dapat langsung memberikan instruksi pada container untuk menjalan perintah apa. pada case ini kita akan menjalan perintah psql untuk masuk kedalam database-nya.
Code
Jika sudah masuk, berikan perintah \l untuk me-listing daftar database yang ada. Kita akan melihat bahwa database yang kita buat diawal saat me-running image ada.
psql (18.1 (Debian 18.1-1.pgdg13+2))
Type "help" for help.
farraslang=# \l
List of databases
Name | Owner | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules | Access privileges
------------+--------+----------+-----------------+------------+------------+--------+-----------+-------------------
farraslang | farras | UTF8 | libc | en_US.utf8 | en_US.utf8 | | |
postgres | farras | UTF8 | libc | en_US.utf8 | en_US.utf8 | | |
template0 | farras | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/farras +
| | | | | | | | farras=CTc/farras
template1 | farras | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/farras +
| | | | | | | | farras=CTc/farras
(4 rows)
farraslang=#
Test Ekstensi pg_vector
Saat belajar saya menggunakan referensi dari dokumentasi pada github/pgvector.
Code
farraslang=# CREATE EXTENSION vector;
CREATE EXTENSION
CREATE TABLE contoh_table1 (id bigserial PRIMARY KEY, embedding vector(3));
CREATE TABLE
insert into contoh_table1 (embedding) VALUES ('[3,4,5]'),('[1,2,3]');
INSERT 0 2
farraslang=# select * from contoh_table1;
id | embedding
----+-----------
1 | [3,4,5]
2 | [1,2,3]
(2 rows)
Menggunakan vector pada langchain
Pertama kita harus menginstall library langchain_postgrest untuk menggunakan pg_vector.
Code
Untuk hands-on dapat melihat pada lab Menyimpan, mengakses dan merubah data pad vector store
from langchain_postgres.vectorstores import PGVector
text_data_store_vector = TextLoader(f'{root_path}/BigData.txt')
## Memeuat loader kedalam bentuk class Documents
docs = text_data_store_vector.load()
## Potong big data kedalam potongan2an
splitter_store_vector = RecursiveCharacterTextSplitter(
chunk_size = 1000,
chunk_overlap = 200
)
## Class document baru setelah di potong
new_docs = splitter_store_vector.split_documents(docs)
## Import langchain Ollama
model_embeddings = OllamaEmbeddings(model="nomic-embed-text")
## Dsini kita tidak perlu memanggil embeed documents lagi, kita langsung masukan kedalam parameter PGVector
connection = "postgresql+psycopg://farras:farras@localhost:6060/farraslang"
class_vector_store = PGVector.from_documents(documents=new_docs,embedding=model_embeddings,connection=connection)
Kode diatas adalah gabungan dari apa yang telah kita lalui diatas, seperti memuat text dan menjadikannya dalam bentuk documents, lalu memotong setiap data pada bagian tertentu tanpa menghilangkan makna dari kalimat, merubah kedalam bentuk embeddings dan menyimpannya dalam vectore store (catatan ini menggunakan pgstore).
from_documents
Fungsi from_documents secara otomatis akan membuat table yang dibutuhkan, dan meng-embed dokumen dan memasukannya kedalam database.
Semantic query (mencari makna terdekat dari vector)
Data yang telah dikonversi kedalam vector sudah tersimpan didalam vector store. Selanjutnya kita pasti butuh untuk mengambil data tersebut sesuai dengan yang kita mau. Pencarian makna, permintaan atau semantic query seperti yang telah kita bahas saat membicaran tentang perbedaan dari 2 kata menggunakan consine similiarty.
Alhamdulillah Langchain PGVector memilki method similiary_search 3 yang mengembalikan documents yang paling mirip.
Method ini memiliki 2 parameter yang bisa kita gunakan;
kberapa banyak documents pada nilai keluaranfilterpenyaringan nilai kembalian berdasarkan metadata
Berdasarkan dokumentasi langchain, kemiripan penyematan (embedding similiary) dihitung menggunakan
- Cosine Similiary
- Euclidean Distance
- Dot Product
Code
Untuk hands-on dapat melihat pada lab Mencari similiary data
docs_for_similiary_search = class_vector_store.similarity_search("visi utama", k=1)
docs_for_similiary_search
[Document(id='79564502-be51-4076-8bd7-b678b35e95ef', metadata={'source': 'C:/Users/maruf/Documents/LangChainLabAssets/BigData.txt'}, page_content='Visi utama dari VenSys adalah menjadi perusahaan teknologi informasi terkemuka di Indonesia. Untuk mencapai visi tersebut, perusahaan menawarkan rangkaian solusi berkualitas yang memberikan keseimbangan terbaik antara nilai investasi dan kesuksesan bagi para pelanggan, mitra, karyawan, dan pemegang saham. Komitmen perusahaan tercermin dalam empat pilar utama: memberikan layanan berkualitas tinggi, menjadi organisasi yang berorientasi pada pelanggan (customer-oriented), melakukan pengembangan sumber daya manusia secara berkelanjutan melalui jalur karier terstruktur dan transfer pengetahuan, serta membangun hubungan jangka panjang yang didasari oleh komitmen konstan terhadap peningkatan solusi dan layanan.')]
Untuk hands-on dapat melihat pada lab Mencari similiary data
docs_for_similiary_search = class_vector_store.similarity_search("jenenge sopo", k=1)
docs_for_similiary_search
[Document(id='79564502-be51-4076-8bd7-b678b35e95ef', metadata={'source': 'C:/Users/maruf/Documents/LangChainLabAssets/BigData.txt'}, page_content='Visi utama dari VenSys adalah menjadi perusahaan teknologi informasi terkemuka di Indonesia. Untuk mencapai visi tersebut, perusahaan menawarkan rangkaian solusi berkualitas yang memberikan keseimbangan terbaik antara nilai investasi dan kesuksesan bagi para pelanggan, mitra, karyawan, dan pemegang saham. Komitmen perusahaan tercermin dalam empat pilar utama: memberikan layanan berkualitas tinggi, menjadi organisasi yang berorientasi pada pelanggan (customer-oriented), melakukan pengembangan sumber daya manusia secara berkelanjutan melalui jalur karier terstruktur dan transfer pengetahuan, serta membangun hubungan jangka panjang yang didasari oleh komitmen konstan terhadap peningkatan solusi dan layanan.')]
Dari dua contoh diatas kita memberikan parameter k dengan nilai 1, artinya return value adalah hanya 1 document yg memiliki kemiripan paling tinggi, ingat, kemiripan yang paling tinggi. Pertama kita mencari kata kunci "visi utama" yg mana kita dapat melihat retur value-nya mengandung informasi terkait visi misi. Akan tetapi pada percobaan kedua dengan kata kunci "jenenge sopo" yang mana dokumen yang kita berikan sama sekali tidak mengandung informasi tersebut namun method similiary_search tetap mengembalikan value, karena method tersebut mengembalian derajat kemiripin yang palin tinggi diantara semua record pada vector store.
Informasi yang tidak relavan yang diberikan oleh LLM sangat tidak baik, karena bisa membuat jawaban menjadi BIAS. Bagusnya, Langchain menyediakan method lain, similarity_search_with_relevance_scores yang mana selain mengemabalikan document juga mengembalikan relevan scores dengan nilai [0-1];
- Semakin mendekati 0 maka semakin tidak cocok.
- Semakin mendekati 1 maka semakin cocok.
Official Documentations
Berikut adalah dokumentasi resmi untuk mengetahui lebih dalam method similiary_search_with_relevance_scores
Code
Untuk hands-on dapat melihat pada lab Mencari similiary data dengan score
Untuk hands-on dapat melihat pada lab Mencari similiary data dengan score
Menyimpan Embedding pada vector store (menggunakan PGVectorStore the new way)
Intro Pada catatan diatas saya menggnakan PGVector untuk menyimpang data vector seperti syntax berikut PGVector.from_documents. Namun penggunaan tersebut sudah deprecated diganti dengan PGVectorStore berdasarkan dokumentasi resminya.
Official Documentations
Alasan mengapa migrasi dan cara migrasi dari PGVector ke PGVectorStore migrate_pgvector_to_pgvectorstore.ipynb
Why migrate?
Migrating to the PGVectorStore interface provides the following benefits:
- Simplified management: A single table contains data corresponding to a single collection, making it easier to query, update, and maintain.
- Improved metadata handling: It stores metadata in columns instead of JSON, resulting in significant performance improvements.
- Schema flexibility: The interface allows users to add tables into any database schema.
- Improved performance: The single-table schema can lead to faster query execution, especially for large collections.
- Clear separation: Clearly separate table and extension creation, allowing for distinct permissions and streamlined workflows.
- Secure Connections: The PGVectorStore interface creates a secure connection pool that can be easily shared across your application using the engine object.
Maka pada bagian ini SANGAT MENYARANKAN untuk menggunakan catatan lab berikut
Lab
Untuk hands-on dapat melihat pada PGVectorStore
Untuk menambahkan konten dokumen ke database vector menggunakan class PgVectorStore kita dapat memanfaatkan method add_document dari object PGVectorStore.
Code
Untuk hands-on dapat melihat pada lab inisiasi object PGVectore Store
model_embeddings = OllamaEmbeddings(model="nomic-embed-text")
class_vector_store = await PGVectorStore.create(
engine=pg_engine,
table_name=TABLE_NAME,
embedding_service=model_embeddings
)
Untuk hands-on dapat melihat pada lab store data ke vector store
from langchain_core.documents import Document
from uuid import uuid4
## Membuat documentsa
contents = ['Bismillah, semoga Allah luluskan aku pada kali ini menjadi Aparatur Sipil Negara',
'Allah maha menerima doa hambanya, Allah selalu mendeger suara hambanya, Allah maha mengabulkan doa hambanya']
documents = [Document(content, metadata={'jenis':f'nasihat ke {angka}','author':'muhammad farras'}) for angka, content in enumerate(contents)]
class_vector_store.add_documents(documents)
Menghapus data
Kita dapat menghapus data vector menggunakan function delete dari object PGVectorStore. Function tersebut mebutuhkan setidaknya 1 parameter id dalam bentuk list untuk memberitahu PGVectorStroe untuk menghapus data yang dimaksud.
Code
Untuk hands-on dapat melihat pada lab inisiasi object PGVectore Store
Semantic query
Untuk pencarian makna kita dapat menggunakan method yang sama dengan pgvector, karena object dari class class 'langchain_postgres.v2.vectorstores.PGVectorStore' memilki fungsi pencarian seperti 'search', 'similarity_search', 'similarity_search_by_vector', 'similarity_search_with_relevance_scores', 'similarity_search_with_score', 'similarity_search_with_score_by_vector'.
Code
Untuk hands-on dapat melihat pada lab Mencari similiary data dengan score
Untuk hands-on dapat melihat pada lab Mencari similiary data dengan score
Menggunakan index pada PGVectorStore
Penggunaan index pada sebuah database akan meningkatkan pencarian makna secara signifikan terutama untuk data vector yang semakin banyak. PGVectorStore atau penyedia data collection vector store lainnya memanfaatkan HNSW (Hierarchical Navigable Small World)4. Untuk implementasinya insyaAllah akan menyusul
Melacakan perubahan data pada vector store
Saat menyimpan data pada vector store diatas kita hanya menggunakan insert dan delete saja, lalu bagaimana seandainya kita salah memasukan data kedalam vector store atau ingin mengupdate-nya ? Kita dapat menggunakan SQLRecordManager dan Index yang tersedia pada module langchain_classic.
Lab
Untuk hands-on dapat melihat pada Tracking Change of your data
Referensi
- Docker Hub postgrest
- Cara extend image psql
- Docker Hub pgvector/pgvector
- pg_vector github
- Langchain PGVector
- Langchain Similiary Search
- Langchain Similiary Saerch with Score
- Langchain Document
- PGVectorStore
- Migration from pGVector to PGVectorStore
- hnsw
-
Lab cara menghitung sparse vectorize Embeddings Words example ↩