Grundlæggende RAG-implementering: en trin-for-trin-vejledning
Denne begyndervenlige vejledning forklarer, hvordan en grundlæggende RAG-implementering fungerer, gennemgår bedste praksis og viser, hvordan du bygger et fungerende kommandolinjebaseret RAG-system med Python, ChromaDB og Perplexitys embedding- og sprogmodeller.

RAG er en central komponent i moderne LLM-baseret infrastruktur. Ved at give AI-modeller adgang til eksterne data hjælper det med at løse problemer som hallucinationer og ufuldstændige træningsdata. Det betyder også, at virksomheder kan bruge interne vidensbaser, der indeholder følsomme eller proprietære oplysninger.
RAG-implementering kan være meget kompleks. Et grundlæggende RAG-system er dog overraskende nemt at bygge. For begyndere kan det at opbygge en simpel arkitektur give indblik i, hvordan RAG fungerer i praksis, og være et springbræt til videre eksperimenter.
I denne artikel skitserer vi en grundlæggende RAG-implementering, gennemgår bedste praksis og bygger derefter et fungerende system med Python, ChromaDB og to Perplexity-modeller til embedding og generering af svar.
Grundlæggende RAG-implementering: et overblik over processen
Et grundlæggende RAG-system har tre hovedkomponenter: en orkestrator, en informationskilde og en LLM. I en typisk arbejdsproces indtaster en bruger en prompt, og orkestratoren tilpasser den for at søge i de tilknyttede informationskilder. De hentede oplysninger føjes derefter til den oprindelige inputkontekst og sendes til LLM'en, så der kan genereres et svar.
Du skal tage højde for disse trin, når du bygger din RAG-implementering:
- Indeksering og embedding: I denne fase konverteres dine dokumenter til en informationskilde, som orkestratoren kan søge i. En af de mest almindelige måder at gøre det på er at bygge et søgbart vektorindeks. Vi bruger en dedikeret model fra Perplexity til at konvertere dine dokumentstykker til embeddings. Derefter gemmer vi dem i ChromaDB, en populær open source-vektordatabase.
- Orkestrering: Det er den applikation, der befinder sig mellem den eksterne informationskilde (i vores tilfælde en vektordatabase) og LLM'en. Vi opretter et simpelt Python-script, der fungerer som orkestrator.
- Hentning og generering: Når en bruger stiller et spørgsmål via chatgrænsefladen, modtager orkestratoren det, kører en vektorsøgning og sender det udvidede input til LLM'en. Vi bruger kommandolinjen til at kommunikere med vores Python-orkestrator i stedet for at bygge en dedikeret frontend.
Bedste praksis: Hvad kendetegner en effektiv RAG-implementering?
Der findes flere typer RAG-arkitektur, og forskellige anvendelsestilfælde kræver forskellige tilgange. Når det er sagt, gælder en række principper for bedste praksis i alle tilfælde, og de sikrer nøjagtige, omkostningseffektive, skalerbare og vedligeholdelsesvenlige systemer.
Følgende bedste praksis gælder for alle typer RAG-implementering:
- Sørg for en ren indlæsningspipeline: Dine kildedata bør være så rene som muligt før indeksering. Du bør også bruge en embeddingmodel, der passer til dit indhold.
- Brug hybridsøgning: De bedste hentningsmetoder – hvad enten det er søgning i vektordatabaser, API-baseret websøgning, gennemløb af vidensgrafer, søgeordssøgning eller andre metoder – varierer afhængigt af anvendelsestilfældet. Det er vigtigt at vælge den rette kombination for at minimere omkostningerne.
- Evaluer dit system: Efter implementeringen bør du evaluere ud fra tre centrale mål: nøjagtighed, relevans og latens. Nøjagtighed handler om faktuel korrekthed, relevans om, hvor anvendelige de hentede oplysninger er i forhold til brugernes forespørgsler, og latens om, hvor hurtigt oplysningerne hentes.
- Behandl oplysninger sikkert: Hvis dit RAG-system trækker på private interne oplysninger, skal du sikre, at de opbevares sikkert, og at adgangen til systemets brugerflade styres. API-nøgler bør aldrig deles.
Grundlæggende RAG-implementering: vejledning i 7 trin
I denne vejledning bygger vi en kommandolinjeapplikation, der besvarer spørgsmål om et enkelt dokument. Vi bruger Python, ChromaDB og Perplexity API.
Målet er ikke at bygge et produktionsklart RAG-system. Det er snarere en begyndervenlig vejledning, der skal illustrere, hvordan en enkel RAG-arkitektur fungerer i praksis.
Trin 1: Installer software
Sørg for, at følgende er installeret på din computer, og at du har en Perplexity API-konto:
- Python: Dette er det programmeringssprog, vi bruger til at bygge orkestratoren, der koordinerer dataflowet mellem embeddingmodellen, ChromaDB og Perplexity.
- Visual Studio: Vi bruger Visual Studio som kodeeditor. Når det er installeret, skal du åbne panelet Extensions og downloade udvidelsen Python.
- Perplexity API-konto: Perplexity leverer både embeddingmodellen (som omdanner dine data til vektor-embeddings) og den LLM, der behandler den udvidede prompt. Du behøver ikke en betalt konto for at gøre dette, selvom det vil koste nogle få kreditter.
Trin 2: Opret en projektmappe
Start med at oprette en mappe med navnet rag-project, og åbn den i VS Code ved at vælge File > Open Folder. Åbn derefter den integrerede terminal via Terminal > New Terminal.
Indtast følgende for at oprette et virtuelt Python-miljø:
py -3.12 -m venv .venvDu skal nu installere fire Python-biblioteker: perplexityai, chromadb, python-dotenv og numpy. Med Perplexity SDK kan du oprette forbindelse til Perplexitys modeller via API. ChromaDB bygger vektordatabasen og kører lokalt. Python-dotenv indlæser dine API-nøgler sikkert fra en lokal fil, og NumPy skal bruges under indlæsningsprocessen.
Installer dem med følgende kommando:
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpyTrin 3: Konfigurer dine filer
Tilføj følgende filer til rag-project (projektets rodmappe) ved at vælge New File… i sidepanelet Explorer:
- index.py: Dette er applikationen, der indekserer dit dokument. Du kan køre den igen for at tilføje mere tekst.
- rag.py: Dette er Python-applikationen, der fungerer som orkestrator.
- document.txt: Denne fil indeholder den dokumentation, du konverterer til en vektordatabase.
- .env: Det er her, du opbevarer din Perplexity API-nøgle.
Indtast følgende i .env:
PERPLEXITY_API_KEY=your_api_key_hereErstat your_api_key_here med din faktiske nøgle. For at få den skal du gå til startdashboardet i Perplexity API Console og vælge Create an API key. Hold denne API-nøgle privat.
Vi bruger to modeller: Perplexitys pplx-embed-v1-0.6b til at lave embeddings af vores dokumentation, før den uploades til ChromaDB, og GPT-5.6-Luna (tilgået via Perplexitys API), som behandler de hentede oplysninger.
I document.txt skal du tilføje den tekst, som din RAG-pipeline skal hente. Hvis du ikke har et dokument ved hånden, kan du bruge William Blakes Songs of Innocence and of Experience fra Project Gutenberg til denne vejledning. Det er en kort, letforståelig tekst, som ikke længere er beskyttet af ophavsret.
Trin 4: Skriv indekseringsprogrammet
Kopiér koden nedenfor, og indsæt den i index.py. Hver underoverskrift giver en kort forklaring på, hvad det efterfølgende kodesegment gør. Dette er programmet, der konverterer dit kildemateriale til vektor-embeddings og gemmer dem i en ChromaDB-database ved hjælp af Perplexitys embeddingmodel, pplx-embed-v1-0.6b, og NumPy-biblioteket.
Programmet gør følgende:
- Åbner document.txt.
- Opdeler teksten i overlappende tekststykker.
- Sender disse tekststykker til Perplexitys embeddingmodel pplx-embed-v1-0.6b.
- Afkoder og normaliserer de returnerede vektorer med NumPy, et Python-bibliotek med beregningsfunktioner.
- Gemmer vektorerne og de oprindelige tekststykker i en ChromaDB-database (du vil se den dukke op i din projektmappe).
Programmet er sat op, så det ikke genindekserer dit dokument, hver gang du kører det. Hvis du tilføjer flere oplysninger i document.txt, laver det kun embeddings af den nye 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())Trin 5. Skriv orkestratoren til RAG-systemet
Kopiér koden nedenfor, og indsæt den i rag.py. Det er en komplet, men minimal RAG-implementering, der bruger Perplexity SDK og ChromaDB's lokale vektordatabasefunktionalitet.
Her er, hvad der sker, når du kører programmet:
- Opretter forbindelse til Perplexity og din nye ChromaDB-database.
- Kontrollerer, at databasen indeholder indekserede dokumenter.
- Modtager et spørgsmål fra brugeren.
- Sender spørgsmålet til Perplexitys embeddingmodel.
- Afkoder og normaliserer den resulterende embedding med NumPy.
- Søger i ChromaDB efter de tre dokumentstykker, der ligner mest.
- Opbygger en prompt, der indeholder de hentede tekststykker og brugerens spørgsmål.
- Sender prompten til GPT-5.6 Luna via Perplexitys Agent API.
- Viser svaret og venter på et nyt spørgsmål.
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)Trin 6: Kør applikationerne
Indtast følgende i PowerShell-terminalen i VS Code for at lave embeddings af indholdet i document.txt:
.\.venv\Scripts\python.exe index.pyHvis dit dokument er blevet indekseret korrekt, bør du se et output, der ligner dette:
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Nu er det tid til at køre den primære orkestratorapplikation. Indtast denne kommando:
.\.venv\Scripts\python.exe rag.pyHvis den kører korrekt, vil du se følgende:
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Du kan nu stille spørgsmål, der trækker på den vektordatabase, du har oprettet, for eksempel:
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.Trin 7: Forstå, hvad du har bygget
Det system, du har bygget, indeholder de to centrale pipelines, som findes i enhver RAG-arkitektur: en indekseringspipeline, også kaldet »ingestion«-pipeline, og en pipeline til hentning og generering.
Din grundlæggende RAG-implementering gør nu alt følgende:
- Vektorlagring: Embeddings baseret på din vidensfil gemmes i din ChromaDB-database i dit lokale miljø.
- Inkrementel indeksering: Der laves ikke embeddings af uændrede dokumentstykker igen, og du kan opdatere dokumentet, når du vil.
- Semantisk hentning: ChromaDB henter tekststykker baseret på vektorlighed (igangsat af orkestratoren).
- Forankret svargenerering: LLM'en modtager de hentede passager som kontekst og indarbejder dem i et svar.
- Uafhængig indeksering og forespørgsel: Du kan stille spørgsmål uden at genbehandle al teksten i din vidensfil.
- API-baseret modelforbindelse: Alle svar genereres med GPT-5.6 Luna via Perplexity i stedet for med en model, der kører på din maskine.
Næste skridt: Sådan videreudvikler du implementeringen
Formålet med denne vejledning er at bygge en enkel, grundlæggende implementering. Den dækker nogle af de centrale RAG-arkitekturkomponenter, der findes i moderne systemer. Hvis du vil gå videre, kan du bygge videre på den på forskellige måder.
Her er nogle idéer til at udvide omfanget af din implementering:
- Eksperimentér med LangChain: LangChain er et af de mest populære open source-frameworks til orkestrering. Det indeholder færdigbyggede komponenter til at bygge apps, der kan køre komplekse RAG-pipelines.
- Udvid søgefunktionaliteten: Kombiner tæt vektorsøgning med leksikalsk søgning (søgeordssøgning) som BM25. Ved også at tilføje websøgning via Perplexity Search API kan du forankre svarene i aktuelle data.
- Tilføj en reranking-model: Integrer en reranking-model, der rangerer de hentede passager i forhold til den oprindelige prompt og udvælger de mest relevante, så de kan indgå i den inputkontekst, som LLM'en får.
- Byg et adaptivt RAG-system: Adaptiv RAG bruger enten en LLM eller en klassifikator (en komponent i orkestratoren) til at afgøre, hvilken hentningsmetode der skal bruges i et modulært RAG-system. At bygge et sådant system er en god måde at udforske mere avancerede RAG-implementeringer på.
Selvom alt dette kan lyde komplekst, skal du huske, at udbredte AI-platforme som Perplexity kan give avanceret hjælp til kodning. De er fremragende til personlige projekter og eksperimenter, og omkostningerne kan holdes relativt lave.
Bemærk: Denne vejledning bruger GPT-5.6 Luna. Udvalget af tilgængelige modeller kan ændre sig, så du skal muligvis opdatere API-kaldet.