Implementació bàsica de RAG: un tutorial pas a pas
Aquest tutorial per a principiants explica com funciona una implementació bàsica de RAG, repassa les bones pràctiques i mostra pas a pas com construir un sistema RAG funcional de línia d’ordres amb Python, ChromaDB i els models d’embeddings i de llenguatge de Perplexity.

La RAG és un component essencial de la infraestructura moderna basada en LLM. En permetre que els models d’IA accedeixin a dades externes, ajuda a resoldre problemes com les al·lucinacions i les dades d’entrenament incompletes. També permet que les empreses utilitzin bases de coneixement internes que contenen informació confidencial o de propietat.
La implementació de la RAG pot ser molt complexa. Tanmateix, un sistema RAG bàsic és sorprenentment fàcil de construir. Per als principiants, crear una arquitectura senzilla pot ajudar a entendre com funciona la RAG al món real i servir de punt de partida per continuar experimentant.
En aquest article, descriurem una implementació bàsica de RAG, repassarem les bones pràctiques i, a continuació, construirem un sistema funcional amb Python, ChromaDB i dos models de Perplexity per a la generació d’embeddings i de respostes.
Procés bàsic d’implementació de RAG: una visió general
Un sistema RAG bàsic té tres components principals: un orquestrador, una font d’informació i un LLM. En un flux de treball típic, l’usuari introdueix un prompt i l’orquestrador el modifica per cercar a les fonts d’informació connectades. Després, la informació recuperada s’afegeix al context d’entrada original i s’envia a l’LLM perquè generi una resposta.
Hauràs de tenir en compte aquests passos quan construeixis la teva implementació de RAG:
- Indexació i embeddings: En aquesta fase, els teus documents es converteixen en una font d’informació en què l’orquestrador pot cercar. Una de les maneres més habituals de fer-ho és construir un índex vectorial consultable. Utilitzarem un model dedicat de Perplexity per convertir els fragments dels teus documents en embeddings. Després, emmagatzemarem els embeddings amb ChromaDB, una base de dades vectorial de codi obert molt popular.
- Orquestració: És l’aplicació que se situa entre la font d’informació externa (en el nostre cas, una base de dades vectorial) i l’LLM. Crearem un script senzill de Python que farà d’orquestrador.
- Recuperació i generació: Quan un usuari fa una pregunta a través de la interfície de xat, l’orquestrador la rep, executa una cerca vectorial i envia l’entrada ampliada a l’LLM. En lloc de construir un frontend dedicat, utilitzarem la línia d’ordres per enviar prompts al nostre orquestrador de Python.
Bones pràctiques: què fa que una implementació de RAG sigui eficaç?
Hi ha diversos tipus d’arquitectura RAG, i cada cas d’ús requereix un enfocament diferent. Dit això, hi ha un seguit de bones pràctiques que s’apliquen en tots els casos i que garanteixen sistemes precisos, rendibles, escalables i fàcils de mantenir.
Les bones pràctiques següents s’apliquen a tots els tipus d’implementació de RAG:
- Garanteix un pipeline d’ingesta net: Les dades d’origen han de ser tan netes com sigui possible abans de la indexació. També hauries d’utilitzar un model d’embeddings adequat al teu contingut.
- Utilitza la cerca híbrida: Els millors mètodes de recuperació (ja sigui la cerca en bases de dades vectorials, la cerca web mitjançant API, el recorregut de grafs de coneixement, la cerca per paraules clau o altres mètodes) varien segons el cas d’ús. Triar la combinació adequada és important per minimitzar els costos.
- Avalua el teu sistema: Després de la implementació, hauries d’avaluar-lo segons tres mesures fonamentals: precisió, rellevància i latència. La precisió fa referència a la correcció factual; la rellevància, a l’adequació de la informació recuperada a les consultes dels usuaris, i la latència, a la velocitat amb què es recupera la informació.
- Tracta la informació de manera segura: Si el teu sistema RAG utilitza informació interna privada, assegura’t que s’emmagatzema de manera segura i que l’accés a la interfície del sistema està controlat. Les claus d’API no s’han de compartir mai.
Implementació bàsica de RAG: tutorial en 7 passos
En aquest tutorial, construirem una aplicació de línia d’ordres que respon preguntes sobre un únic document. Utilitzarem Python, ChromaDB i l’API de Perplexity.
L’objectiu no és construir un sistema RAG preparat per a producció. Es tracta, més aviat, d’un tutorial per a principiants dissenyat per il·lustrar com funciona a la pràctica una arquitectura RAG rudimentària.
Pas 1: instal·la el programari
Assegura’t que tens instal·lats els elements següents a l’ordinador i que disposes d’un compte de l’API de Perplexity:
- Python: És el llenguatge de programació que farem servir per construir l’orquestrador que coordinarà el flux de dades entre el model d’embeddings, ChromaDB i Perplexity.
- Visual Studio: Utilitzarem Visual Studio com a editor de codi. Un cop instal·lat, obre el tauler Extensions i baixa l’extensió Python.
- Compte de l’API de Perplexity: Perplexity proporcionarà tant el model d’embeddings (que converteix les teves dades en embeddings vectorials) com l’LLM que processarà el prompt ampliat. No cal un compte de pagament per fer-ho, tot i que hi haurà un petit cost en crèdits.
Pas 2: crea una carpeta de projecte
Comença creant una carpeta anomenada rag-project i obrint-la a VS Code amb File > Open Folder. A continuació, obre el terminal integrat mitjançant Terminal > New Terminal.
Introdueix el següent per crear un entorn virtual de Python:
py -3.12 -m venv .venvAra has d’instal·lar quatre biblioteques de Python: perplexityai, chromadb, python-dotenv i numpy. L’SDK de Perplexity et permetrà connectar-te als models de Perplexity mitjançant l’API. ChromaDB crea la base de dades vectorial i s’executarà localment. Python-dotenv carrega les teves claus d’API de manera segura des d’un fitxer local, i NumPy és necessari durant el procés d’ingesta.
Instal·la-les amb l’ordre següent:
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpyPas 3: configura els fitxers
Afegeix els fitxers següents a rag-project (l’arrel del projecte) seleccionant New File… a la barra lateral de l’Explorer:
- index.py: És l’aplicació que indexarà el teu document. Pots tornar-la a executar per afegir-hi més text.
- rag.py: És l’aplicació de Python que farà d’orquestrador.
- document.txt: Contindrà la documentació que convertiràs en una base de dades vectorial.
- .env: Aquí és on desaràs la teva clau de l’API de Perplexity.
A .env, introdueix el següent:
PERPLEXITY_API_KEY=your_api_key_hereSubstitueix your_api_key_here per la teva clau real. Per fer-ho, hauràs d’anar al tauler principal de la consola de l’API de Perplexity i seleccionar Create an API key. No comparteixis aquesta clau d’API amb ningú.
Utilitzarem dos models: pplx-embed-v1-0.6b de Perplexity, per generar els embeddings de la nostra documentació abans de carregar-la a ChromaDB, i GPT-5.6-Luna (al qual accedim a través de l’API de Perplexity), que processarà la informació recuperada.
A document.txt, afegeix el text que recuperarà el teu pipeline de RAG. Si no tens cap document a mà, per a aquest tutorial pots utilitzar Songs of Innocence and of Experience, de William Blake, disponible al Project Gutenberg. És un text breu, fàcil d’entendre i de domini públic.
Pas 4: escriu el programa d’indexació
Copia i enganxa el codi següent a index.py. Cada subtítol explica breument què fa el segment de codi que el segueix. Aquest és el programa que convertirà el teu material d’origen en embeddings vectorials i els emmagatzemarà en una base de dades de ChromaDB mitjançant el model d’embeddings de Perplexity, pplx-embed-v1-0.6b, i la biblioteca NumPy.
Això és el que fa el programa:
- Obre document.txt.
- Divideix el text en fragments que se superposen.
- Envia aquests fragments al model d’embeddings pplx-embed-v1-0.6b de Perplexity.
- Descodifica i normalitza els vectors retornats amb NumPy, una biblioteca de Python de funcions de càlcul.
- Emmagatzema els vectors i els fragments originals en una base de dades de ChromaDB (la veuràs aparèixer al directori del projecte).
S’ha configurat perquè no torni a indexar el document cada vegada que l’executis. Si afegeixes informació a document.txt, només generarà els embeddings del text nou.
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())Pas 5. Escriu l’orquestrador del sistema RAG
Copia i enganxa el codi següent a rag.py. És una implementació de RAG completa però mínima que utilitza l’SDK de Perplexity i la funcionalitat de base de dades vectorial local de ChromaDB.
Això és el que passarà quan executis el programa:
- Es connecta a Perplexity i a la teva nova base de dades de ChromaDB.
- Comprova que la base de dades conté documents indexats.
- Accepta una pregunta de l’usuari.
- Envia la pregunta al model d’embeddings de Perplexity.
- Descodifica i normalitza l’embedding resultant amb NumPy.
- Cerca a ChromaDB els tres fragments de document més semblants.
- Construeix un prompt que conté els fragments recuperats i la pregunta de l’usuari.
- Envia el prompt a GPT-5.6 Luna a través de l’Agent API de Perplexity.
- Mostra la resposta i espera una altra pregunta.
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)Pas 6: executa les aplicacions
Al terminal de PowerShell de VS Code, introdueix el següent per generar els embeddings del contingut de document.txt:
.\.venv\Scripts\python.exe index.pySi el document s’ha indexat correctament, hauries de veure una sortida semblant a aquesta:
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Ara és el moment d’executar l’aplicació principal de l’orquestrador. Introdueix aquesta ordre:
.\.venv\Scripts\python.exe rag.pySi s’executa correctament, veuràs el següent:
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Ara pots fer preguntes que extreguin informació de la base de dades vectorial que has creat, com ara:
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.Pas 7: entén què has construït
El sistema que has construït conté els dos pipelines fonamentals presents en tota arquitectura RAG: un pipeline d’indexació, o «d’ingesta», i un pipeline de recuperació i generació.
Ara, la teva implementació bàsica de RAG fa tot això:
- Emmagatzematge vectorial: Els embeddings es desen a la base de dades de ChromaDB del teu entorn local a partir del teu fitxer de coneixement.
- Indexació incremental: Els fragments de document que no han canviat no es tornen a convertir en embeddings, i pots actualitzar el document sempre que vulguis.
- Recuperació semàntica: ChromaDB recupera fragments en funció de la similitud vectorial (a petició de l’orquestrador).
- Generació de respostes fonamentades: L’LLM rep els passatges recuperats com a context i els incorpora a la resposta.
- Indexació i consultes independents: Pots fer preguntes sense tornar a processar tot el text del teu fitxer de coneixement.
- Connexió amb el model mitjançant API: Totes les respostes es generen amb GPT-5.6 Luna a través de Perplexity, en lloc d’un model que s’executi a la teva màquina.
Pròxims passos: com portar aquesta implementació més enllà
L’objectiu d’aquest tutorial és construir una implementació bàsica i senzilla. Inclou alguns dels components fonamentals de l’arquitectura RAG presents en els sistemes moderns. Si vols anar més enllà, hi ha diverses maneres d’ampliar-la.
Aquí tens algunes idees per ampliar l’abast de la teva implementació:
- Experimenta amb LangChain: LangChain és un dels frameworks d’orquestració de codi obert més populars. Inclou components predefinits per crear aplicacions capaces d’executar pipelines de RAG complexos.
- Amplia la funcionalitat de cerca: Combina la cerca vectorial densa amb la cerca lèxica (per paraules clau), com ara BM25. Afegir la cerca web mitjançant la Search API de Perplexity també et permetria fonamentar les respostes en dades actuals.
- Afegeix un model de reordenació: Integra un model de reordenació (reranking) que classifiqui els passatges recuperats en funció del prompt inicial i seleccioni els més rellevants per incloure’ls en el context d’entrada que es proporciona a l’LLM.
- Construeix un sistema RAG adaptatiu: La RAG adaptativa utilitza un LLM o un classificador (un component de l’orquestrador) per determinar quin mètode de recuperació s’ha de fer servir en un sistema RAG modular. Construir-ne un és una bona manera d’explorar implementacions de RAG més sofisticades.
Tot i que tot això pot semblar complex, tingues en compte que les principals plataformes d’IA, com Perplexity, poden oferir assistència avançada en programació. Són excel·lents per a projectes personals i per experimentar, i els costos es poden mantenir relativament baixos.
Nota: aquest tutorial utilitza GPT-5.6 Luna. La disponibilitat dels models pot canviar, de manera que potser hauràs d’actualitzar la crida a l’API.