Osnovna implementacija RAG-a: vodič korak po korak
Ovaj vodič prilagođen početnicima objašnjava kako funkcioniše osnovna implementacija RAG-a, obrađuje najbolje prakse i vodi vas kroz izradu funkcionalnog RAG sistema za komandnu liniju pomoću jezika Python, baze ChromaDB i Perplexity modela za ugrađivanje i jezičkih modela.

RAG je ključna komponenta savremene infrastrukture zasnovane na LLM modelima. Pošto AI modelima omogućava pristup spoljnim podacima, pomaže u rešavanju problema kao što su halucinacije i nepotpuni podaci za obuku. To takođe znači da kompanije mogu da koriste interne baze znanja koje sadrže osetljive ili vlasničke informacije.
Implementacija RAG-a može biti veoma složena. Ipak, osnovni RAG sistem je iznenađujuće lako napraviti. Za početnike, izrada jednostavne arhitekture može da razjasni kako RAG funkcioniše u stvarnom svetu i da posluži kao odskočna daska za dalje eksperimentisanje.
U ovom članku ćemo opisati osnovnu implementaciju RAG-a, obraditi najbolje prakse, a zatim napraviti funkcionalan sistem pomoću jezika Python, baze ChromaDB i dva Perplexity modela – jednog za ugrađivanje (embedding), a drugog za generisanje odgovora.
Osnovni proces implementacije RAG-a: opšti pregled
Osnovni RAG sistem ima tri glavne komponente: orkestrator, izvor informacija i LLM. U tipičnom radnom toku korisnik unosi upit, a orkestrator ga prilagođava kako bi pretražio sve povezane izvore informacija. Preuzete informacije se zatim dodaju u prvobitni ulazni kontekst i šalju LLM-u kako bi se generisao odgovor.
Prilikom izrade svoje RAG implementacije moraćete da uzmete u obzir sledeće korake:
- Indeksiranje i ugrađivanje: U ovoj fazi vaši dokumenti se pretvaraju u izvor informacija koji orkestrator može da pretražuje. Jedan od najčešćih načina da se to uradi jeste izrada vektorskog indeksa koji se može pretraživati. Koristićemo namenski Perplexity model da delove vaših dokumenata pretvorimo u vektorska ugrađivanja. Zatim ćemo ugrađivanja sačuvati u bazi ChromaDB, popularnoj vektorskoj bazi podataka otvorenog koda.
- Orkestracija: Ovo je aplikacija koja se nalazi između spoljnog izvora informacija (u našem slučaju vektorske baze podataka) i LLM-a. Napravićemo jednostavnu Python skriptu koja će imati ulogu orkestratora.
- Preuzimanje i generisanje: Kada korisnik postavi pitanje putem interfejsa za ćaskanje, orkestrator će ga preuzeti, pokrenuti vektorsku pretragu i proslediti prošireni ulaz LLM-u. Umesto da pravimo namenski frontend, za slanje upita našem Python orkestratoru koristićemo komandnu liniju.
Najbolje prakse: šta čini RAG implementaciju efikasnom?
Postoji više tipova RAG arhitekture, a pojedinačni slučajevi upotrebe zahtevaju različite pristupe. Ipak, određene najbolje prakse važe u svim slučajevima i obezbeđuju tačne, isplative i skalabilne sisteme koji se lako održavaju.
Sledeće najbolje prakse važe za sve tipove RAG implementacije:
- Obezbedite čist cevovod za unos podataka: Vaši izvorni podaci treba da budu što čistiji pre indeksiranja. Takođe bi trebalo da koristite model za ugrađivanje prilagođen vašem sadržaju.
- Koristite hibridnu pretragu: Najbolje metode preuzimanja – bilo da je reč o pretrazi vektorske baze podataka, veb-pretrazi putem API-ja, prolasku kroz graf znanja, pretrazi po ključnim rečima ili nekoj drugoj metodi – razlikuju se u zavisnosti od slučaja upotrebe. Izbor prave kombinacije važan je za smanjenje troškova.
- Procenite svoj sistem: Nakon implementacije sistem treba da procenite na osnovu tri ključna merila: tačnosti, relevantnosti i latencije. Tačnost se odnosi na činjeničnu ispravnost, relevantnost na primenljivost preuzetih informacija na korisničke upite, a latencija na brzinu kojom se informacije preuzimaju.
- Bezbedno postupajte sa informacijama: Ako se vaš RAG sistem oslanja na privatne interne informacije, uverite se da su one bezbedno sačuvane i da je pristup interfejsu sistema kontrolisan. API ključeve nikada ne treba deliti.
Osnovna implementacija RAG-a: vodič u 7 koraka
U ovom vodiču napravićemo aplikaciju za komandnu liniju koja odgovara na pitanja o jednom dokumentu. Koristićemo Python, ChromaDB i Perplexity API.
Cilj nije da se napravi RAG sistem spreman za produkciju. Reč je o vodiču prilagođenom početnicima, osmišljenom da pokaže kako osnovna RAG arhitektura funkcioniše u praksi.
Korak 1: Instalirajte softver
Uverite se da je na vašem računaru instalirano sledeće i da imate Perplexity API nalog:
- Python: Ovo je programski jezik koji ćemo koristiti za izradu orkestratora koji će koordinisati tok podataka između modela za ugrađivanje, baze ChromaDB i servisa Perplexity.
- Visual Studio: Kao uređivač koda koristićemo Visual Studio. Nakon instalacije otvorite panel Extensions i preuzmite ekstenziju Python.
- Perplexity API nalog: Perplexity će obezbediti i model za ugrađivanje (koji vaše podatke pretvara u vektorska ugrađivanja) i LLM koji će obraditi prošireni upit. Za ovo vam nije potreban plaćeni nalog, ali će se potrošiti mali broj kredita.
Korak 2: Napravite fasciklu projekta
Počnite tako što ćete napraviti fasciklu pod nazivom rag-project i otvoriti je u programu VS Code izborom opcije File > Open Folder. Zatim otvorite integrisani terminal putem opcije Terminal > New Terminal.
Unesite sledeće da biste napravili virtuelno Python okruženje:
py -3.12 -m venv .venvSada treba da instalirate četiri Python biblioteke: perplexityai, chromadb, python-dotenv i numpy. Perplexity SDK će vam omogućiti da se putem API-ja povežete sa Perplexity modelima. ChromaDB pravi vektorsku bazu podataka i radiće lokalno. Python-dotenv bezbedno učitava vaše API ključeve iz lokalne datoteke, a NumPy je potreban tokom procesa unosa podataka.
Instalirajte ih sledećom komandom:
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpyKorak 3: Podesite datoteke
Dodajte sledeće datoteke u rag-project (koren projekta) izborom opcije New File… na bočnoj traci Explorer:
- index.py: Ovo je aplikacija koja će indeksirati vaš dokument. Možete je ponovo pokrenuti da biste dodali još teksta.
- rag.py: Ovo je Python aplikacija koja će imati ulogu orkestratora.
- document.txt: Ova datoteka će sadržati dokumentaciju koju ćete pretvoriti u vektorsku bazu podataka.
- .env: Ovde ćete čuvati svoj Perplexity API ključ.
U datoteku .env unesite sledeće:
PERPLEXITY_API_KEY=your_api_key_hereZamenite your_api_key_here svojim stvarnim ključem. Da biste to uradili, otvorite početnu kontrolnu tablu u Perplexity API Console i izaberite Create an API key. Čuvajte ovaj API ključ u tajnosti.
Koristićemo dva modela: Perplexity model pplx-embed-v1-0.6b za ugrađivanje naše dokumentacije pre otpremanja u ChromaDB i model GPT-5.6-Luna (kom se pristupa putem Perplexity API-ja), koji će obrađivati preuzete informacije.
U datoteku document.txt dodajte tekst koji će vaš RAG cevovod preuzimati. Ako nemate dokument pri ruci, za ovaj vodič upotrebite zbirku Songs of Innocence and of Experience Vilijama Blejka sa sajta Project Gutenberg. To je kratak i lako razumljiv tekst u javnom domenu.
Korak 4: Napišite program za indeksiranje
Kopirajte i nalepite kôd u nastavku u datoteku index.py. Svaki podnaslov ukratko objašnjava šta radi segment koda koji sledi. Ovo je program koji će vaš izvorni materijal pretvoriti u vektorska ugrađivanja i sačuvati ih u ChromaDB bazi podataka pomoću Perplexity modela za ugrađivanje pplx-embed-v1-0.6b i biblioteke NumPy.
Evo šta program radi:
- Otvara datoteku document.txt.
- Deli tekst na delove koji se preklapaju.
- Šalje te delove Perplexity modelu za ugrađivanje pplx-embed-v1-0.6b.
- Dekodira i normalizuje vraćene vektore pomoću NumPy-ja, Python biblioteke računskih funkcija.
- Čuva vektore i originalne delove u ChromaDB bazi podataka (videćete da se pojavila u direktorijumu projekta).
Program je podešen tako da ne indeksira vaš dokument iznova svaki put kada ga pokrenete. Ako dodate nove informacije u datoteku document.txt, napraviće ugrađivanja samo za novi tekst.
from pathlib import Path
from collections import defaultdict, deque
from hashlib import sha256
import base64
import numpy as np
import chromadb
from dotenv import load_dotenv
from perplexity import Perplexity
# 1. Connect to Perplexity and ChromaDB
load_dotenv()
ai = Perplexity()
db = chromadb.PersistentClient(path="./rag_database_perplexity")
collection = db.get_or_create_collection(
name="documents",
metadata={"hnsw:space": "cosine"}
)
# Convert Perplexity's encoded embeddings into numerical vectors
def decode_embedding(encoded):
vector = np.frombuffer(base64.b64decode(encoded), dtype=np.int8).astype(np.float32)
norm = np.linalg.norm(vector)
if norm == 0:
raise ValueError("Received a zero-length embedding vector.")
return (vector / norm).tolist()
# 2. Read the document and split it into chunks
text = Path("document.txt").read_text(encoding="utf-8")
words = text.split()
chunk_size = 180
overlap = 30
step = chunk_size - overlap
chunks = [" ".join(words[i:i + chunk_size]) for i in range(0, len(words), step)]
if not chunks:
raise ValueError("document.txt is empty.")
# 3. Retrieve the chunks already stored in ChromaDB
existing = collection.get(include=["documents"])
stored_chunks = defaultdict(deque)
existing_ids = set(existing["ids"])
for chunk_id, document in zip(existing["ids"], existing["documents"]):
stored_chunks[document].append(chunk_id)
# 4. Identify unchanged and new chunks
new_chunks = []
new_ids = []
kept_ids = set()
unchanged = 0
for chunk in chunks:
if stored_chunks[chunk]:
chunk_id = stored_chunks[chunk].popleft()
kept_ids.add(chunk_id)
unchanged += 1
else:
chunk_hash = sha256(chunk.encode("utf-8")).hexdigest()
chunk_id = f"chunk-{chunk_hash}"
suffix = 1
while chunk_id in existing_ids or chunk_id in kept_ids or chunk_id in new_ids:
chunk_id = f"chunk-{chunk_hash}-{suffix}"
suffix += 1
new_chunks.append(chunk)
new_ids.append(chunk_id)
kept_ids.add(chunk_id)
# 5. Generate embeddings in batches of up to 100 chunks
batch_size = 100
for i in range(0, len(new_chunks), batch_size):
batch_chunks = new_chunks[i:i + batch_size]
batch_ids = new_ids[i:i + batch_size]
embeddings = ai.embeddings.create(
model="pplx-embed-v1-0.6b",
input=batch_chunks,
encoding_format="base64_int8"
)
vectors = [decode_embedding(item.embedding) for item in embeddings.data]
# 6. Store each batch in ChromaDB
collection.upsert(
ids=batch_ids,
documents=batch_chunks,
embeddings=vectors
)
print(f"Indexed batch {(i // batch_size) + 1}")
# 7. Remove outdated chunks
old_ids = [chunk_id for chunk_id in existing["ids"] if chunk_id not in kept_ids]
if old_ids:
collection.delete(ids=old_ids)
# 8. Display indexing results
print("Indexing complete!")
print("Unchanged chunks:", unchanged)
print("New or modified chunks:", len(new_chunks))
print("Removed chunks:", len(old_ids))
print("Total stored chunks:", collection.count())Korak 5. Napišite orkestrator za RAG sistem
Kopirajte i nalepite kôd u nastavku u datoteku rag.py. To je potpuna, ali minimalna RAG implementacija koja koristi Perplexity SDK i funkcionalnost lokalne vektorske baze podataka ChromaDB.
Evo šta će se desiti kada pokrenete program:
- Povezuje se sa servisom Perplexity i vašom novom ChromaDB bazom podataka.
- Proverava da li baza podataka sadrži indeksirane dokumente.
- Prihvata pitanje od korisnika.
- Šalje pitanje Perplexity modelu za ugrađivanje.
- Dekodira i normalizuje dobijeno ugrađivanje pomoću NumPy-ja.
- Pretražuje ChromaDB i pronalazi tri najsličnija dela dokumenta.
- Sastavlja upit koji sadrži preuzete delove i korisnikovo pitanje.
- Šalje upit modelu GPT-5.6 Luna putem Perplexity Agent API-ja.
- Prikazuje odgovor i čeka sledeće pitanje.
import base64
import numpy as np
import chromadb
from dotenv import load_dotenv
from perplexity import Perplexity
# 1. Connect to Perplexity and the existing ChromaDB database
load_dotenv()
ai = Perplexity()
db = chromadb.PersistentClient(path="./rag_database_perplexity")
collection = db.get_collection("documents")
# Convert Perplexity's encoded embeddings into numerical vectors
def decode_embedding(encoded):
vector = np.frombuffer(base64.b64decode(encoded), dtype=np.int8).astype(np.float32)
norm = np.linalg.norm(vector)
if norm == 0:
raise ValueError("Received a zero-length embedding vector.")
return (vector / norm).tolist()
# 2. Check that the database contains indexed documents
count = collection.count()
if count == 0:
raise ValueError("The database is empty. Run index.py first.")
print("Connected to existing ChromaDB database.")
print("Stored chunks:", count)
# 3. Accept questions from the user
while True:
question = input("\nAsk a question (or type exit): ")
if question.lower().strip() == "exit":
break
if not question.strip():
continue
# 4. Convert the question into a Perplexity embedding
question_response = ai.embeddings.create(
model="pplx-embed-v1-0.6b",
input=[question],
encoding_format="base64_int8"
)
question_vector = decode_embedding(question_response.data[0].embedding)
# 5. Retrieve the most similar document chunks from ChromaDB
results = collection.query(
query_embeddings=[question_vector],
n_results=min(3, count)
)
context = "\n\n".join(results["documents"][0])
# 6. Construct a prompt and send it to the fixed LLM
response = ai.responses.create(
model="openai/gpt-5.6-luna",
instructions=(
"Answer using only the supplied document excerpts. "
"Do not use external information. "
"If the answer is not present, say you don't know."
),
input=f"Document excerpts:\n{context}\n\nQuestion: {question}"
)
# 7. Display the answer
print("\nAnswer:\n", response.output_text)Korak 6: Pokrenite aplikacije
U PowerShell terminalu u programu VS Code unesite sledeće da biste napravili ugrađivanja za sadržaj datoteke document.txt:
.\.venv\Scripts\python.exe index.pyAko je vaš dokument uspešno indeksiran, trebalo bi da vidite izlaz sličan ovom:
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Sada je vreme da pokrenete glavnu aplikaciju orkestratora. Unesite ovu komandu:
.\.venv\Scripts\python.exe rag.pyAko se aplikacija uspešno pokrene, videćete sledeće:
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Sada možete da postavljate pitanja na koja će se odgovori zasnivati na vektorskoj bazi podataka koju ste napravili, na primer:
Ask a question (or type exit): What animals does William Blake talk about?
Answer: The excerpts mention sheep, lambs, birds, beasts, wolves, tigers, and a lion.Korak 7: Shvatite šta ste napravili
Sistem koji ste napravili sadrži dva ključna cevovoda koja postoje u svakoj RAG arhitekturi: cevovod za indeksiranje, odnosno „unos podataka“, i cevovod za preuzimanje i generisanje.
Vaša osnovna RAG implementacija sada radi sve sledeće:
- Vektorsko skladištenje: Ugrađivanja nastala na osnovu vaše datoteke znanja čuvaju se u ChromaDB bazi podataka u vašem lokalnom okruženju.
- Inkrementalno indeksiranje: Za nepromenjene delove dokumenta ugrađivanja se ne prave ponovo, a dokument možete da ažurirate kad god želite.
- Semantičko preuzimanje: ChromaDB preuzima delove na osnovu vektorske sličnosti (na zahtev orkestratora).
- Generisanje utemeljenih odgovora: LLM dobija preuzete odlomke kao kontekst i uključuje ih u odgovor.
- Nezavisno indeksiranje i postavljanje upita: Možete da postavljate pitanja bez ponovne obrade celog teksta iz vaše datoteke znanja.
- Povezivanje sa modelom putem API-ja: Svi odgovori se generišu pomoću modela GPT-5.6 Luna putem servisa Perplexity, a ne pomoću modela koji radi na vašem računaru.
Sledeći koraci: kako da dodatno unapredite ovu implementaciju
Cilj ovog vodiča je da se napravi jednostavna, osnovna implementacija. Ona obuhvata neke od ključnih komponenti RAG arhitekture prisutnih u savremenim sistemima. Ako želite da idete korak dalje, postoje različiti načini da je nadogradite.
Evo nekoliko ideja za proširenje obima vaše implementacije:
- Eksperimentišite sa okvirom LangChain: LangChain je jedan od najpopularnijih okvira za orkestraciju otvorenog koda. Sadrži unapred napravljene komponente za izradu aplikacija koje mogu da pokreću složene RAG cevovode.
- Proširite funkcionalnost pretrage: Kombinujte gustu vektorsku pretragu sa leksičkom pretragom (po ključnim rečima), kao što je BM25. Dodavanje veb-pretrage putem Perplexity Search API-ja takođe bi vam omogućilo da odgovore utemeljite na aktuelnim podacima.
- Dodajte model za ponovno rangiranje: Integrišite model za ponovno rangiranje koji rangira preuzete odlomke u odnosu na početni upit i bira najrelevantnije za uključivanje u ulazni kontekst koji se prosleđuje LLM-u.
- Napravite adaptivni RAG sistem: Adaptivni RAG koristi LLM ili klasifikator (komponentu unutar orkestratora) da bi odredio koju metodu preuzimanja treba koristiti u modularnom RAG sistemu. Izrada takvog sistema dobar je način da istražite naprednije RAG implementacije.
Iako sve ovo može zvučati složeno, imajte na umu da popularne AI platforme kao što je Perplexity mogu da pruže naprednu pomoć pri programiranju. Odlične su za lične projekte i eksperimentisanje, a troškovi se mogu održati relativno niskim.
Napomena: U ovom vodiču koristi se model GPT-5.6 Luna. Dostupnost modela se može promeniti, pa ćete možda morati da ažurirate API poziv.