Grundläggande RAG-implementering: en steg-för-steg-guide
Den här nybörjarvänliga guiden förklarar hur en grundläggande RAG-implementering fungerar, går igenom bästa praxis och visar steg för steg hur du bygger ett fungerande RAG-system för kommandoraden med Python, ChromaDB samt Perplexitys inbäddnings- och språkmodeller.

RAG är en central komponent i modern LLM-baserad infrastruktur. Genom att låta AI-modeller få tillgång till extern data hjälper det till att motverka problem som hallucinationer och ofullständig träningsdata. Det innebär också att företag kan använda interna kunskapsbaser som innehåller känslig eller företagsintern information.
En RAG-implementering kan vara mycket komplex. Ett grundläggande RAG-system är dock förvånansvärt enkelt att bygga. För nybörjare kan en enkel arkitektur tydliggöra hur RAG fungerar i praktiken och fungera som en språngbräda för vidare experimenterande.
I den här artikeln skissar vi upp en grundläggande RAG-implementering, går igenom bästa praxis och bygger sedan ett fungerande system med Python, ChromaDB och två Perplexity-modeller för inbäddning och svarsgenerering.
Processen för en grundläggande RAG-implementering: en översikt
Ett grundläggande RAG-system har tre huvudkomponenter: en orkestrerare, en informationskälla och en LLM. I ett typiskt arbetsflöde anger användaren en prompt, och orkestreraren omformulerar den för att söka i anslutna informationskällor. Den hämtade informationen läggs sedan till i den ursprungliga indatakontexten och skickas till LLM:en så att ett svar kan genereras.
Du behöver ta hänsyn till följande steg när du bygger din RAG-implementering:
- Indexering och inbäddning: I det här steget omvandlas dina dokument till en informationskälla som orkestreraren kan söka i. Ett av de vanligaste sätten att göra detta är att bygga ett sökbart vektorindex. Vi använder en dedikerad modell från Perplexity för att omvandla dina dokumentsegment till inbäddningar. Därefter lagrar vi inbäddningarna med ChromaDB, en populär vektordatabas med öppen källkod.
- Orkestrering: Detta är applikationen som sitter mellan den externa informationskällan (i vårt fall en vektordatabas) och LLM:en. Vi skapar ett enkelt Python-skript som fungerar som orkestrerare.
- Hämtning och generering: När en användare ställer en fråga via chattgränssnittet tar orkestreraren emot den, kör en vektorsökning och skickar den utökade indatan till LLM:en. Vi använder kommandoraden för att kommunicera med vår Python-orkestrerare i stället för att bygga en separat frontend.
Bästa praxis: Vad kännetecknar en effektiv RAG-implementering?
Det finns flera typer av RAG-arkitektur, och olika användningsfall kräver olika tillvägagångssätt. Samtidigt finns det ett antal beprövade metoder som gäller i alla lägen och som ger korrekta, kostnadseffektiva, skalbara och underhållsvänliga system.
Följande bästa praxis gäller för alla typer av RAG-implementeringar:
- Se till att ha en ren inläsningspipeline: Dina källdata bör vara så rena som möjligt före indexeringen. Du bör också använda en inbäddningsmodell som passar ditt innehåll.
- Använd hybridsökning: Vilka hämtningsmetoder som fungerar bäst – vektordatabassökning, API-baserad webbsökning, genomsökning av kunskapsgrafer, nyckelordssökning eller andra metoder – varierar mellan användningsfall. Att välja rätt kombination är viktigt för att hålla nere kostnaderna.
- Utvärdera ditt system: Efter implementeringen bör du utvärdera systemet utifrån tre centrala mått: noggrannhet, relevans och latens. Noggrannhet avser faktamässig korrekthet, relevans hur väl den hämtade informationen passar användarnas frågor och latens hur snabbt informationen hämtas.
- Hantera information säkert: Om ditt RAG-system bygger på privat intern information ska du se till att den lagras säkert och att åtkomsten till systemets gränssnitt hanteras. API-nycklar ska aldrig delas.
Grundläggande RAG-implementering: guide i 7 steg
I den här guiden bygger vi en kommandoradsapplikation som besvarar frågor om ett enskilt dokument. Vi använder Python, ChromaDB och Perplexity API.
Målet är inte att bygga ett produktionsklart RAG-system. Det här är snarare en nybörjarvänlig guide som är utformad för att visa hur en enkel RAG-arkitektur fungerar i praktiken.
Steg 1: Installera programvara
Se till att följande är installerat på din dator och att du har ett konto för Perplexity API:
- Python: Det här är programmeringsspråket vi använder för att bygga orkestreraren som samordnar dataflödet mellan inbäddningsmodellen, ChromaDB och Perplexity.
- Visual Studio: Vi använder Visual Studio som kodredigerare. När det är installerat öppnar du panelen Extensions och laddar ned tillägget Python.
- Konto för Perplexity API: Perplexity tillhandahåller både inbäddningsmodellen (som omvandlar dina data till vektorinbäddningar) och den LLM som bearbetar den utökade prompten. Du behöver inget betalkonto för detta, även om det går åt en liten mängd krediter.
Steg 2: Skapa en projektmapp
Börja med att skapa en mapp med namnet rag-project och öppna den i VS Code genom att välja File > Open Folder. Öppna sedan den integrerade terminalen via Terminal > New Terminal.
Ange följande för att skapa en virtuell Python-miljö:
py -3.12 -m venv .venvNu behöver du installera fyra Python-bibliotek: perplexityai, chromadb, python-dotenv och numpy. Med Perplexity SDK kan du ansluta till Perplexitys modeller via API. ChromaDB bygger vektordatabasen och körs lokalt. Python-dotenv läser in dina API-nycklar säkert från en lokal fil, och NumPy behövs under inläsningsprocessen.
Installera dem med följande kommando:
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpySteg 3: Konfigurera dina filer
Lägg till följande filer i rag-project (projektets rotmapp) genom att välja New File… i sidofältet Explorer:
- index.py: Det här är applikationen som indexerar ditt dokument. Du kan köra den igen för att lägga till mer text.
- rag.py: Det här är Python-applikationen som fungerar som orkestrerare.
- document.txt: Den här filen innehåller dokumentationen som du ska omvandla till en vektordatabas.
- .env: Här sparar du din API-nyckel för Perplexity.
Ange följande i .env:
PERPLEXITY_API_KEY=your_api_key_hereErsätt your_api_key_here med din faktiska nyckel. För att göra det går du till startsidan i Perplexity API Console och väljer Create an API key. Håll API-nyckeln hemlig.
Vi använder två modeller: Perplexitys pplx-embed-v1-0.6b för att bädda in vår dokumentation innan den laddas upp till ChromaDB, och GPT-5.6-Luna (som nås via Perplexitys API), som bearbetar den hämtade informationen.
Lägg till texten som din RAG-pipeline ska hämta i document.txt. Om du inte har något dokument till hands kan du använda William Blakes Songs of Innocence and of Experience från Project Gutenberg i den här guiden. Det är en kort och lättförståelig text som är allmän egendom.
Steg 4: Skriv indexeringsprogrammet
Kopiera och klistra in koden nedan i index.py. Varje underrubrik förklarar kortfattat vad det efterföljande kodavsnittet gör. Det här är programmet som omvandlar ditt källmaterial till vektorinbäddningar och lagrar dem i en ChromaDB-databas med hjälp av Perplexitys inbäddningsmodell pplx-embed-v1-0.6b och biblioteket NumPy.
Det här gör programmet:
- Öppnar document.txt.
- Delar upp texten i överlappande segment.
- Skickar segmenten till Perplexitys inbäddningsmodell pplx-embed-v1-0.6b.
- Avkodar och normaliserar de returnerade vektorerna med NumPy, ett Python-bibliotek med beräkningsfunktioner.
- Lagrar vektorerna och de ursprungliga segmenten i en ChromaDB-databas (du ser den dyka upp i din projektkatalog).
Programmet är konfigurerat så att det inte indexerar om ditt dokument varje gång du kör det. Om du lägger till information i document.txt bäddas bara den nya texten in.
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())Steg 5. Skriv orkestreraren för RAG-systemet
Kopiera och klistra in koden nedan i rag.py. Det är en komplett men minimal RAG-implementering som använder Perplexity SDK och ChromaDB:s lokala vektordatabasfunktioner.
Det här händer när du kör programmet:
- Ansluter till Perplexity och din nya ChromaDB-databas.
- Kontrollerar att databasen innehåller indexerade dokument.
- Tar emot en fråga från användaren.
- Skickar frågan till Perplexitys inbäddningsmodell.
- Avkodar och normaliserar den resulterande inbäddningen med NumPy.
- Söker i ChromaDB efter de tre mest liknande dokumentsegmenten.
- Skapar en prompt som innehåller de hämtade segmenten och användarens fråga.
- Skickar prompten till GPT-5.6 Luna via Perplexitys Agent API.
- Visar svaret och väntar på nästa fråga.
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)Steg 6: Kör applikationerna
Ange följande i PowerShell-terminalen i VS Code för att bädda in innehållet i document.txt:
.\.venv\Scripts\python.exe index.pyOm dokumentet har indexerats korrekt bör du se utdata som liknar följande:
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Nu är det dags att köra den huvudsakliga orkestreringsapplikationen. Ange det här kommandot:
.\.venv\Scripts\python.exe rag.pyOm den körs utan problem ser du följande:
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Nu kan du ställa frågor som besvaras utifrån vektordatabasen du har skapat, till exempel:
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.Steg 7: Förstå vad du har byggt
Systemet du har byggt innehåller de två centrala pipelines som finns i alla RAG-arkitekturer: en indexeringspipeline (även kallad ”inläsningspipeline”) och en pipeline för hämtning och generering.
Din grundläggande RAG-implementering gör nu allt följande:
- Vektorlagring: Inbäddningar baserade på din kunskapsfil sparas i ChromaDB-databasen i din lokala miljö.
- Inkrementell indexering: Oförändrade dokumentsegment bäddas inte in igen, och du kan uppdatera dokumentet när du vill.
- Semantisk hämtning: ChromaDB hämtar segment baserat på vektorlikhet (på initiativ av orkestreraren).
- Förankrad svarsgenerering: LLM:en tar emot hämtade textavsnitt som kontext och införlivar dem i ett svar.
- Oberoende indexering och frågehantering: Du kan ställa frågor utan att bearbeta om all text i din kunskapsfil.
- API-baserad modellanslutning: Alla svar genereras med GPT-5.6 Luna via Perplexity i stället för med en modell som körs på din dator.
Nästa steg: Så tar du implementeringen vidare
Syftet med den här guiden är att bygga en enkel, grundläggande implementering. Den täcker några av de centrala komponenterna i RAG-arkitekturen som finns i moderna system. Om du vill gå vidare finns det flera sätt att bygga vidare på den.
Här är några idéer för att utöka din implementering:
- Experimentera med LangChain: LangChain är ett av de mest populära ramverken för orkestrering med öppen källkod. Det innehåller färdiga komponenter för att bygga appar som kan köra komplexa RAG-pipelines.
- Utöka sökfunktionerna: Kombinera tät vektorsökning med lexikal sökning (nyckelordssökning), till exempel BM25. Om du lägger till webbsökning via Perplexity Search API kan du dessutom förankra svaren i aktuell data.
- Lägg till en omrankningsmodell: Integrera en omrankningsmodell som rangordnar de hämtade textavsnitten mot den ursprungliga prompten och väljer ut de mest relevanta för att ta med i indatakontexten som skickas till LLM:en.
- Bygg ett adaptivt RAG-system: Adaptiv RAG använder antingen en LLM eller en klassificerare (en komponent i orkestreraren) för att avgöra vilken hämtningsmetod som ska användas i ett modulärt RAG-system. Att bygga ett sådant är ett bra sätt att utforska mer avancerade RAG-implementeringar.
Även om allt detta kan låta komplicerat är det bra att komma ihåg att etablerade AI-plattformar som Perplexity kan ge avancerad hjälp med kodning. De passar utmärkt för egna projekt och experiment, och kostnaderna kan hållas relativt låga.
Obs! I den här guiden används GPT-5.6 Luna. Tillgången till modeller kan ändras, så du kan behöva uppdatera API-anropet.