Lihtne RAG-lahendus: samm-sammuline õpetus
See algajasõbralik õpetus selgitab, kuidas lihtne RAG-lahendus töötab, käsitleb parimaid tavasid ja juhendab samm-sammult töötava käsurea RAG-süsteemi ehitamist Pythoni, ChromaDB ning Perplexity manustamis- ja keelemudelite abil.

RAG on tänapäevase LLM-põhise taristu oluline osa. Kuna see võimaldab tehisintellekti mudelitel välisandmetele ligi pääseda, aitab see lahendada selliseid probleeme nagu hallutsinatsioonid ja puudulikud treeningandmed. Samuti saavad ettevõtted tänu sellele kasutada sisemisi teadmusbaase, mis sisaldavad tundlikku või ärisaladusena kaitstud teavet.
RAG-i juurutamine võib olla väga keerukas. Lihtsa RAG-süsteemi ehitamine on aga üllatavalt lihtne. Algajale aitab lihtsa arhitektuuri loomine mõista, kuidas RAG tegelikkuses töötab, ning annab hea lähtepunkti edasisteks katsetusteks.
Selles artiklis kirjeldame lihtsa RAG-lahenduse ülesehitust, käsitleme parimaid tavasid ja ehitame seejärel töötava süsteemi, kasutades Pythonit, ChromaDB-d ning kahte Perplexity mudelit manustamiseks ja vastuste genereerimiseks.
Lihtsa RAG-lahenduse loomise protsess: üldülevaade
Lihtsal RAG-süsteemil on kolm põhikomponenti: orkestreerija, teabeallikas ja LLM. Tüüpilises töövoos sisestab kasutaja viiba ning orkestreerija muudab seda, et otsida ühendatud teabeallikatest. Leitud teave lisatakse seejärel algsele sisendkontekstile ja saadetakse LLM-ile, et see saaks vastuse genereerida.
RAG-lahenduse loomisel peate arvestama järgmiste etappidega:
- Indekseerimine ja manustamine: Selles etapis teisendatakse teie dokumendid teabeallikaks, millest orkestreerija saab otsida. Üks levinumaid viise selleks on otsitava vektorindeksi loomine. Kasutame Perplexity spetsiaalset mudelit, et teisendada teie dokumenditükid manusteks. Seejärel salvestame manused ChromaDB-sse, mis on populaarne avatud lähtekoodiga vektorandmebaas.
- Orkestreerimine: See on rakendus, mis asub välise teabeallika (meie puhul vektorandmebaasi) ja LLM-i vahel. Loome orkestreerijana toimiva lihtsa Pythoni skripti.
- Otsing ja genereerimine: Kui kasutaja esitab vestlusliidese kaudu küsimuse, võtab orkestreerija selle vastu, käivitab vektorotsingu ja edastab laiendatud sisendi LLM-ile. Spetsiaalse kasutajaliidese ehitamise asemel kasutame Pythoni orkestreerijaga suhtlemiseks käsurida.
Parimad tavad: mis teeb RAG-lahenduse tõhusaks?
RAG-arhitektuuri on mitut tüüpi ning erinevad kasutusjuhud nõuavad erinevaid lähenemisi. Sellegipoolest kehtivad mitmed parimad tavad kõigil juhtudel ja aitavad luua täpseid, kulutõhusaid, skaleeritavaid ning hooldatavaid süsteeme.
Järgmised parimad tavad kehtivad igat tüüpi RAG-lahenduste puhul:
- Tagage puhas andmete sisselugemise konveier: Teie lähteandmed peaksid olema enne indekseerimist võimalikult puhtad. Samuti peaksite kasutama teie sisule sobivat manustamismudelit.
- Kasutage hübriidotsingut: Parimad otsingumeetodid – olgu selleks vektorandmebaasist otsimine, API-põhine veebiotsing, teadmusgraafi läbimine, märksõnaotsing või muud meetodid – sõltuvad kasutusjuhust. Õige kombinatsiooni valimine on kulude minimeerimiseks oluline.
- Hinnake oma süsteemi: Pärast juurutamist peaksite süsteemi hindama kolme põhinäitaja alusel: täpsus, asjakohasus ja latentsus. Täpsus tähendab faktilist õigsust, asjakohasus seda, kui hästi leitud teave kasutaja päringutele vastab, ning latentsus kiirust, millega teave leitakse.
- Käsitlege teavet turvaliselt: Kui teie RAG-süsteem kasutab privaatset sisemist teavet, veenduge, et see oleks turvaliselt salvestatud ja et juurdepääsu süsteemi liidesele hallataks. API-võtmeid ei tohi kunagi jagada.
Lihtne RAG-lahendus: 7-sammuline õpetus
Selles õpetuses ehitame käsurearakenduse, mis vastab küsimustele ühe dokumendi kohta. Kasutame Pythonit, ChromaDB-d ja Perplexity API-t.
Eesmärk ei ole ehitada tootmisvalmis RAG-süsteemi. Pigem on see algajasõbralik õpetus, mis näitab, kuidas lihtne RAG-arhitektuur praktikas toimib.
1. samm: installige tarkvara
Veenduge, et teie arvutisse on installitud järgmised programmid ja et teil on Perplexity API konto:
- Python: See on programmeerimiskeel, millega ehitame orkestreerija, mis koordineerib andmevoogu manustamismudeli, ChromaDB ja Perplexity vahel.
- Visual Studio: Kasutame koodiredaktorina Visual Studiot. Pärast installimist avage paneel Extensions ja laadige alla laiendus Python.
- Perplexity API konto: Perplexity pakub nii manustamismudelit (mis muudab teie andmed vektormanusteks) kui ka LLM-i, mis töötleb laiendatud viipa. Selleks ei ole vaja tasulist kontot, kuigi kulub väike kogus krediite.
2. samm: looge projektikaust
Alustuseks looge kaust nimega rag-project ja avage see VS Code'is, valides File > Open Folder. Seejärel avage integreeritud terminal valikuga Terminal > New Terminal.
Pythoni virtuaalkeskkonna loomiseks sisestage järgmine käsk:
py -3.12 -m venv .venvNüüd peate installima neli Pythoni teeki: perplexityai, chromadb, python-dotenv ja numpy. Perplexity SDK võimaldab teil API kaudu Perplexity mudelitega ühenduse luua. ChromaDB loob vektorandmebaasi ja töötab kohalikult. Python-dotenv laadib teie API-võtmed turvaliselt kohalikust failist ning NumPy on vajalik andmete sisselugemise käigus.
Installige need järgmise käsuga:
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpy3. samm: seadistage failid
Lisage kausta rag-project (projekti juurkausta) järgmised failid, valides Exploreri külgribal käsu New File…:
- index.py: See on rakendus, mis indekseerib teie dokumendi. Täiendava teksti lisamiseks saate selle uuesti käivitada.
- rag.py: See on Pythoni rakendus, mis toimib orkestreerijana.
- document.txt: See sisaldab dokumentatsiooni, mille teisendate vektorandmebaasiks.
- .env: Siin hoiate oma Perplexity API-võtit.
Sisestage faili .env järgmine tekst:
PERPLEXITY_API_KEY=your_api_key_hereAsendage your_api_key_here oma tegeliku võtmega. Selleks avage Perplexity API Console'i avalehe juhtpaneel ja valige Create an API key. Hoidke see API-võti privaatsena.
Kasutame kahte mudelit: Perplexity mudelit pplx-embed-v1-0.6b, et manustada dokumentatsioon enne ChromaDB-sse üleslaadimist, ning mudelit GPT-5.6-Luna (millele pääseb ligi Perplexity API kaudu), mis töötleb leitud teavet.
Lisage faili document.txt tekst, millest teie RAG-konveier teavet otsib. Kui teil pole dokumenti käepärast, kasutage selle õpetuse jaoks William Blake'i teost Songs of Innocence and of Experience Project Gutenbergist. See on lühike, kergesti mõistetav avalikku omandisse kuuluv tekst.
4. samm: kirjutage indekseerimisprogramm
Kopeerige allolev kood ja kleepige see faili index.py. Iga alapealkiri selgitab lühidalt, mida järgnev koodilõik teeb. See programm teisendab teie lähtematerjali vektormanusteks ja salvestab need ChromaDB andmebaasi, kasutades Perplexity manustamismudelit pplx-embed-v1-0.6b ja teeki NumPy.
Programm teeb järgmist:
- Avab faili document.txt.
- Jagab teksti kattuvateks tükkideks.
- Saadab need tükid Perplexity manustamismudelile pplx-embed-v1-0.6b.
- Dekodeerib ja normaliseerib tagastatud vektorid NumPy abil, mis on arvutusfunktsioonide Pythoni teek.
- Salvestab vektorid ja algsed tükid ChromaDB andmebaasi (näete, kuidas see teie projektikataloogi ilmub).
Programm on seadistatud nii, et see ei indekseeri teie dokumenti igal käivitamisel uuesti. Kui lisate faili document.txt uut teavet, manustab see ainult uue teksti.
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())5. samm: kirjutage RAG-süsteemi orkestreerija
Kopeerige allolev kood ja kleepige see faili rag.py. See on täielik, kuid minimaalne RAG-lahendus, mis kasutab Perplexity SDK-d ja ChromaDB kohaliku vektorandmebaasi funktsioone.
Programmi käivitamisel toimub järgmine:
- Loob ühenduse Perplexityga ja teie uue ChromaDB andmebaasiga.
- Kontrollib, kas andmebaas sisaldab indekseeritud dokumente.
- Võtab kasutajalt vastu küsimuse.
- Saadab küsimuse Perplexity manustamismudelile.
- Dekodeerib ja normaliseerib saadud manuse NumPy abil.
- Otsib ChromaDB-st kolm kõige sarnasemat dokumenditükki.
- Koostab viiba, mis sisaldab leitud tükke ja kasutaja küsimust.
- Saadab viiba Perplexity Agent API kaudu mudelile GPT-5.6 Luna.
- Kuvab vastuse ja ootab järgmist küsimust.
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)6. samm: käivitage rakendused
Faili document.txt sisu manustamiseks sisestage VS Code'i PowerShelli terminali järgmine käsk:
.\.venv\Scripts\python.exe index.pyKui dokument on edukalt indekseeritud, peaksite nägema sellele sarnast väljundit:
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Nüüd on aeg käivitada peamine orkestreerimisrakendus. Sisestage see käsk:
.\.venv\Scripts\python.exe rag.pyKui käivitamine õnnestub, näete järgmist:
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Nüüd saate esitada küsimusi, millele vastamiseks kasutatakse teie loodud vektorandmebaasi, näiteks:
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.7. samm: mõistke, mille olete ehitanud
Teie ehitatud süsteem sisaldab kahte põhikonveierit, mis on olemas igas RAG-arhitektuuris: indekseerimis- ehk „sisselugemiskonveierit“ ning otsingu- ja genereerimiskonveierit.
Teie lihtne RAG-lahendus teeb nüüd järgmist:
- Vektorite salvestamine: Teie teadmusfaili põhjal loodud manused salvestatakse teie kohalikus keskkonnas olevasse ChromaDB andmebaasi.
- Järkjärguline indekseerimine: Muutmata dokumenditükke uuesti ei manustata ja saate dokumenti igal ajal uuendada.
- Semantiline otsing: ChromaDB leiab tükid vektorite sarnasuse põhjal (otsingu algatab orkestreerija).
- Allikatele tuginev vastuste genereerimine: LLM saab leitud lõigud kontekstina ja kaasab need vastusesse.
- Sõltumatu indekseerimine ja päringud: Saate esitada küsimusi ilma teadmusfaili kogu teksti uuesti töötlemata.
- API-põhine mudeliühendus: Kõik vastused genereeritakse Perplexity kaudu mudeliga GPT-5.6 Luna, mitte teie arvutis töötava mudeliga.
Järgmised sammud: kuidas seda lahendust edasi arendada
Selle õpetuse eesmärk on luua lihtne ja arusaadav põhilahendus. See hõlmab mõningaid tänapäevaste süsteemide RAG-arhitektuuri põhikomponente. Kui soovite minna kaugemale, saate seda mitmel viisil edasi arendada.
Siin on mõned ideed, kuidas oma lahenduse ulatust laiendada:
- Katsetage LangChaini: LangChain on üks populaarsemaid avatud lähtekoodiga orkestreerimisraamistikke. See sisaldab valmiskomponente rakenduste ehitamiseks, mis suudavad käitada keerukaid RAG-konveiereid.
- Laiendage otsingufunktsioone: Kombineerige tihe vektorotsing leksikaalse (märksõnapõhise) otsinguga, näiteks BM25-ga. Veebiotsingu lisamine Perplexity Search API kaudu võimaldaks teil ka vastustes tugineda ajakohastele andmetele.
- Lisage ümberjärjestamismudel: Integreerige ümberjärjestamismudel, mis järjestab leitud lõigud algse viiba suhtes ja valib neist kõige asjakohasemad, et lisada need LLM-ile antavasse sisendkonteksti.
- Ehitage adaptiivne RAG-süsteem: Adaptiivne RAG kasutab kas LLM-i või klassifikaatorit (orkestreerija komponenti), et otsustada, millist otsingumeetodit modulaarses RAG-süsteemis kasutada. Sellise süsteemi ehitamine on hea viis keerukamate RAG-lahendustega tutvumiseks.
Kuigi see kõik võib tunduda keeruline, pidage meeles, et levinud tehisintellektiplatvormid, nagu Perplexity, pakuvad koodi kirjutamisel täiustatud abi. Need sobivad suurepäraselt isiklikeks projektideks ja katsetamiseks ning kulud saab hoida suhteliselt väikesena.
Märkus: selles õpetuses kasutatakse mudelit GPT-5.6 Luna. Mudelite saadavus võib muutuda, seega peate võib-olla API-kutset uuendama.