Simple RAG Menggunakan Python, Langchain, OpenAI dan Chroma

Lintang Gilang Pratama
7 min readJun 7, 2024

--

Photo by Dhru J on Unsplash

Teknik Retrieval Augmented Generation (RAG) tengah menjadi sorotan. RAG menggabungkan pengambilan informasi dari sumber eksternal dengan kemampuan Large Language Model (LLM) untuk menciptakan kalimat-kalimat baru yang relevan dan informatif. Teknik ini biasanya diterapkan dalam sistem yang memanfaatkan model LLM dan Vector Database.

Bayangkan memiliki sebuah robot pintar yang mampu membaca dan memahami berbagai informasi. RAG berperan seperti robot ini, membantu kita menemukan jawaban atas pertanyaan dengan cepat dan mudah, seolah-olah membuka banyak buku sekaligus.

Analogikan RAG adalah dengan memiliki perpustakaan besar di dalam komputer Anda. Ketika Anda ingin mengetahui sesuatu, RAG akan membuka “buku-buku” tersebut, membaca isinya, dan menyatukan informasi yang relevan menjadi sebuah jawaban yang mudah dipahami.

Misalnya, saat Anda bertanya, “Apa ibu kota Indonesia?” RAG akan mencari dalam semua “buku,” menemukan bagian yang membahas ibu kota Indonesia, lalu menyatukan informasi tersebut menjadi jawaban yang jelas: “Ibu kota Indonesia adalah Jakarta.”

Dalam artikel ini, kita akan mengeksplorasi cara membangun sistem RAG sederhana menggunakan teknologi seperti Python, Langchain, OpenAI, dan Chroma. Berikut adalah panduan langkah demi langkah untuk membangun solusi End-to-End RAG. Berikut arsitektur nya

Install Library

!pip install langchain
!pip install langchain-community langchain-core
!pip install -U langchain-openai
!pip install langchain-chroma
  1. API OpenAI adalah sebuah layanan yang memungkinkan developer untuk mengakses dan menggunakan model bahasa besar (LLM) milik OpenAI pada aplikasi nya sendiri
  2. LangChain adalah open-source framework yang memudahkan developer untuk membangun aplikasi LLM
  3. ChromaDB adalah database vektor sumber terbuka yang dirancang khusus untuk menyimpan dan mengelola representasi vektor dari data teks.

Import Library

# Untuk membagi teks panjang menjadi bagian-bagian yang lebih kecil berdasarkan karakter tertentu
from langchain.text_splitter import RecursiveCharacterTextSplitter

# untuk berinteraksi dengan model bahasa besar (LLM) OpenAI dengan cara percakapan
from langchain.chat_models import ChatOpenAI

# untuk membuat promt Template
from langchain.prompts import PromptTemplate

# menggabungkan Retriever dengan rantai QA
from langchain.chains import RetrievalQA

# untuk menghasilkan embedding menggunakan LLM OpenAI.
from langchain_openai import OpenAIEmbeddings

# untuk berinteraksi dengan model bahasa besar (LLM) OpenAI dengan cara percakapan
from langchain_openai import ChatOpenAI

# Import chromadb
from langchain_chroma import Chroma
import chromadb

# Merapingkan print
import pprint

Diatas adalah library yang di gunakan juga keterangan singkat tujuan dan kegunaan nya

Data Preparation

texts =  [
"There is ample evidence to show that the Earth is round.",
"First, satellite images orbiting the Earth clearly depict our planet's round shape.",
"Additionally, during a lunar eclipse, the Earth's shadow cast on the Moon is always curved, which can only happen if the Earth is round.",
"Navigation of ships also provides evidence, as ships moving away from the shore gradually disappear from view bottom first, indicating the Earth's curved surface.",
"Observing stars from different parts of the world shows that constellations change positions due to the Earth's curvature.",
"Eratosthenes' ancient experiment measuring the shadow lengths at two different locations in Egypt also provided strong evidence of the Earth's curvature.",
"If the Earth were flat, the shadow lengths would be the same in both places.",
"Airplane flights support this fact, as long-distance flight paths often curve rather than follow a straight line to take advantage of the Earth's curvature.",
"The horizon phenomenon also shows that we cannot see very distant objects because the Earth curves.",
"GPS satellites that help us navigate can only function optimally if the Earth is round.",
"Gravity experiments show that gravity pulls towards the center of mass, causing the Earth to be round.",
"Photos from the Apollo missions that landed on the Moon also show the Earth's round shape from a distance.",
"Weather observations from satellites show cloud movement and storm patterns consistent with a round Earth.",
"The light we see at dawn and dusk also indicates the Earth's curvature.",
"The height of radio towers and antennas is determined by considering the Earth's curvature to optimize signal range.",
"Experiments using high-flying drones show a curved horizon.",
"International space missions, like the ISS, also show the Earth as round from low orbit.",
"The phenomenon of tides is also related to the gravity of a round Earth.",
"Satellite communication systems orbiting the Earth require coordination that considers the planet's curvature.",
"Geodesy research, the science of measuring and mapping the Earth, also shows that the Earth is a geoid, or round with slight deviations at the poles.",
"Moreover, the pattern of day and night distribution around the world is only possible if the Earth is round.",
"All this evidence consistently supports the fact that our Earth is round."
]


# Menggabungkan semua elemen dalam list menjadi satu string dengan newline sebagai pemisah
combined_text = "\n".join(texts)

# Melakukan "RecursiveCharacterTextSplitter" agar data nya bisa memiliki object "page_content"
# Code ini memecah teks menjadi karakter yang dipisahkan "\n", dengan setiap karakter dalam potongan terpisah.
text_splitter = RecursiveCharacterTextSplitter(separators=["\n"], chunk_size=1, chunk_overlap=0)
texts = text_splitter.create_documents([combined_text])

Diatas adalah code yang di gunakan juga keterangan singkat tujuan dan kegunaan nya, berikut adalah output yang diberikan

Embedding

embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)

Proses ini bertujuan untuk memungkinkan menghasilkan representasi numerik (embedding) dari data teks menggunakan model terlatih OpenAI. Embedding ini menangkap hubungan semantik antar kata dan dapat digunakan untuk berbagai tugas pemrosesan bahasa alami (NLP).

Outputnya berupa vektor bilangan floating point. Jarak antara dua vektor mengukur keterkaitannya. Jarak yang kecil menunjukkan keterkaitan yang tinggi, dan jarak yang jauh menunjukkan keterkaitan yang rendah.

Store ke Chroma DB

persist_directory = "chroma_db"

# save ke local
db = Chroma.from_documents(
documents=texts, embedding=embeddings, persist_directory=persist_directory
)


# load dari lokal
db = Chroma(persist_directory = persist_directory, embedding_function=embeddings)
#Testing
query = "Why earth like a ball?"
docs = db.similarity_search(query)
print(docs)

Prompt Enginering

template = """

Role: You are a Scientist.
Input: Use the following context to answer the question.
Context: {context}
Question: {question}
Steps: Answer politely and say I hope you are healthy, then focus on answering the question.
Expectation: Provide accurate and relevant answers based on the context provided.
Narrowing:
1. Limit your responses to the context given. Focus only on questions about Earth.
2. If you don't know the answer, just say you don't know.
3. If there are words or questions outside the earth, just say let's talk about earth.

Answer:

"""

# {context} adalah data yang berasal dari vektor DB yang mempunyai kemiripan dengan pertanyaan
# {quetion} adalah pertanyaan yang akan ditanyakan ke aplikasi

PROMPT = PromptTemplate(
template = template,
input_variables=["context", "question"]
)

Part ini digunakan untuk mendesain template prompt, baiknya menggunakan framework RISEN dimana merupakan pendekatan Prompt Enginering yang dapat di gunakan dimana merupakan singkatan dari Role, Input, Steps, Expectation, Narrowing berikut penjelasan nya

Define LLM

# Definisikan nilai parameter
temperature = 0.2

param = {
"top_p": 0.4,
"frequency_penalty":0.1,
"presence_penalty":0.7
}

# Buat objek LLM dengan parameter yang diubah
llm = ChatOpenAI(
temperature=temperature,
api_key=openai_api_key,
model_kwargs= param
)

Proses ini bertujuan untuk membuat parameter model LLM yang akan digunakan seperti

  1. temperature adalah parameter untuk mengontrol keacakan dan kreativitas respons ChatGPT. Nilai yang lebih tinggi menghasilkan respons yang lebih bervariasi dan tidak dapat diprediksi, sedangkan nilai yang lebih rendah menghasilkan respons yang lebih konservatif dan dapat diprediksi. Sesuaikan parameter ini sesuai dengan tingkat kreativitas yang Anda inginkan.
  2. top_p adalah parameter yang mengontrol keragaman respon ChatGPT. Nilai yang lebih tinggi menghasilkan respons yang lebih beragam, sedangkan nilai yang lebih rendah menghasilkan respons yang lebih konservatif dan dapat diprediksi. Hal ini dapat disesuaikan tergantung pada konteks dan hasil yang diinginkan.
  3. frequency_penalty mempengaruhi kemungkinan menghasilkan kata-kata yang telah digunakan dalam respons. Nilai yang lebih tinggi menghasilkan respons yang lebih bervariasi, sedangkan nilai yang lebih rendah menghasilkan respons yang lebih berulang. Gunakan parameter ini untuk meminimalkan pengulangan pada keluaran ChatGPT.
  4. presence_penalty memberikan penalti terhadap kemungkinan menghasilkan kata-kata yang tidak ada dalam prompt input. Nilai yang lebih tinggi menghasilkan tanggapan yang lebih relevan, sedangkan nilai yang lebih rendah menghasilkan tanggapan yang lebih tidak relevan. Sesuaikan parameter ini untuk memastikan keluaran tetap fokus dan relevan.

RetrievalQA

qa_with_source = RetrievalQA.from_chain_type(
llm = llm,
chain_type = 'stuff',
retriever = db.as_retriever(search_kwargs={"k": 5}),
chain_type_kwargs={"prompt":PROMPT,},
return_source_documents=True,
)

RetrievalQA adalah metode untuk tugas menjawab pertanyaan, memanfaatkan indeks untuk mengambil dokumen atau potongan teks yang relevan, cocok untuk aplikasi Tanya Jawab sederhana. RetrievalQAChain menggabungkan Retriever dan rantai QA. Ini digunakan untuk mengambil dokumen dari Retriever dan kemudian menggunakan rantai QA untuk menjawab pertanyaan berdasarkan dokumen yang diambil.

Asking Question

pprint.pprint(
qa_with_source("Earth is Flat !!!")
)

What Next?

  1. Buat User Interface dengan Streamliat
  2. Gabungkan dengan FastAPI
  3. Store pertanyaan dan jawaban ke Database

Best Regards

Lintang Gilang

--

--