Implémentation RAG basique : tutoriel pas à pas
Ce tutoriel accessible aux débutants explique le fonctionnement d’une implémentation RAG basique, présente les bonnes pratiques et vous guide dans la construction d’un système RAG fonctionnel en ligne de commande avec Python, ChromaDB et les modèles d’embedding et de langage de Perplexity.

La RAG est un composant essentiel de l’infrastructure moderne basée sur les LLM. En permettant aux modèles d’IA d’accéder à des données externes, elle aide à résoudre des problèmes comme les hallucinations et les données d’entraînement incomplètes. Elle permet aussi aux entreprises d’utiliser des bases de connaissances internes contenant des informations sensibles ou propriétaires.
La mise en œuvre de la RAG peut être très complexe. Pourtant, un système RAG basique est étonnamment facile à construire. Pour les débutants, créer une architecture simple permet de comprendre comment la RAG fonctionne en conditions réelles et constitue un tremplin pour aller plus loin dans l’expérimentation.
Dans cet article, nous allons décrire une implémentation RAG basique, passer en revue les bonnes pratiques, puis construire un système fonctionnel avec Python, ChromaDB et deux modèles Perplexity pour l’embedding et la génération de réponses.
Processus d’implémentation RAG basique : vue d’ensemble
Un système RAG basique comporte trois composants principaux : un orchestrateur, une source d’information et un LLM. Dans un flux de travail typique, l’utilisateur saisit un prompt, que l’orchestrateur modifie pour interroger les sources d’information connectées. Les informations récupérées sont ensuite ajoutées au contexte d’entrée initial et envoyées au LLM afin qu’il génère une réponse.
Vous devrez tenir compte de ces étapes lors de la construction de votre implémentation RAG :
- Indexation et embedding : À cette étape, vos documents sont convertis en une source d’information que l’orchestrateur peut interroger. L’une des méthodes les plus courantes consiste à construire un index vectoriel interrogeable. Nous utiliserons un modèle dédié de Perplexity pour convertir les fragments de vos documents en embeddings. Nous stockerons ensuite ces embeddings avec ChromaDB, une base de données vectorielle open source populaire.
- Orchestration : Il s’agit de l’application qui se place entre la source d’information externe (une base de données vectorielle dans notre cas) et le LLM. Nous créerons un simple script Python qui fera office d’orchestrateur.
- Récupération et génération : Lorsqu’un utilisateur pose une question via l’interface de chat, l’orchestrateur la prend en charge, effectue une recherche vectorielle et transmet l’entrée enrichie au LLM. Plutôt que de construire un frontend dédié, nous utiliserons la ligne de commande pour communiquer avec notre orchestrateur Python.
Bonnes pratiques : qu’est-ce qui fait une implémentation RAG efficace ?
Il existe plusieurs types d’architectures RAG, et chaque cas d’usage exige une approche différente. Cela dit, un certain nombre de bonnes pratiques s’appliquent dans tous les cas et garantissent des systèmes précis, rentables, évolutifs et faciles à maintenir.
Les bonnes pratiques suivantes s’appliquent à tous les types d’implémentation RAG :
- Garantissez un pipeline d’ingestion propre : Vos données sources doivent être aussi propres que possible avant l’indexation. Utilisez également un modèle d’embedding adapté à votre contenu.
- Utilisez la recherche hybride : Les meilleures méthodes de récupération, qu’il s’agisse de recherche dans une base de données vectorielle, de recherche web via API, de parcours de graphe de connaissances, de recherche par mots-clés ou d’autres méthodes, varient selon les cas d’usage. Choisir la bonne combinaison est important pour réduire les coûts.
- Évaluez votre système : Après l’implémentation, évaluez-le selon trois critères essentiels : la précision, la pertinence et la latence. La précision désigne l’exactitude factuelle, la pertinence l’adéquation des informations récupérées aux requêtes des utilisateurs, et la latence la vitesse à laquelle les informations sont récupérées.
- Traitez les informations de manière sécurisée : Si votre système RAG s’appuie sur des informations internes privées, assurez-vous qu’elles sont stockées de façon sécurisée et que l’accès à l’interface du système est contrôlé. Les clés API ne doivent jamais être partagées.
Implémentation RAG basique : tutoriel en 7 étapes
Dans ce tutoriel, nous allons construire une application en ligne de commande qui répond à des questions sur un document unique. Nous utiliserons Python, ChromaDB et l’API Perplexity.
L’objectif n’est pas de construire un système RAG prêt pour la production. Il s’agit plutôt d’un tutoriel accessible aux débutants, conçu pour illustrer le fonctionnement concret d’une architecture RAG rudimentaire.
Étape 1 : installer les logiciels
Assurez-vous que les éléments suivants sont installés sur votre ordinateur et que vous disposez d’un compte API Perplexity :
- Python : C’est le langage de programmation que nous utiliserons pour construire l’orchestrateur qui coordonnera le flux de données entre le modèle d’embedding, ChromaDB et Perplexity.
- Visual Studio : Nous utiliserons Visual Studio comme éditeur de code. Une fois l’installation terminée, ouvrez le panneau Extensions et téléchargez l’extension Python.
- Compte API Perplexity : Perplexity fournira à la fois le modèle d’embedding (qui transforme vos données en embeddings vectoriels) et le LLM qui traitera le prompt enrichi. Vous n’avez pas besoin d’un compte payant pour cela, mais l’opération consommera une petite quantité de crédits.
Étape 2 : créer un dossier de projet
Commencez par créer un dossier nommé rag-project et ouvrez-le dans VS Code en sélectionnant Fichier > Ouvrir le dossier. Ouvrez ensuite le terminal intégré via Terminal > Nouveau terminal.
Saisissez la commande suivante pour créer un environnement virtuel Python :
py -3.12 -m venv .venvVous devez maintenant installer quatre bibliothèques Python : perplexityai, chromadb, python-dotenv et numpy. Le SDK Perplexity vous permettra de vous connecter aux modèles de Perplexity via l’API. ChromaDB construit la base de données vectorielle et s’exécutera en local. Python-dotenv charge vos clés API de manière sécurisée à partir d’un fichier local, et NumPy est nécessaire lors du processus d’ingestion.
Installez-les avec la commande suivante :
.\.venv\Scripts\python.exe -m pip install perplexityai chromadb python-dotenv numpyÉtape 3 : configurer vos fichiers
Ajoutez les fichiers suivants à rag-project (racine du projet) en sélectionnant Nouveau fichier… dans la barre latérale de l’Explorateur :
- index.py : C’est l’application qui indexera votre document. Vous pouvez la relancer pour ajouter du texte.
- rag.py : C’est l’application Python qui fera office d’orchestrateur.
- document.txt : Ce fichier contiendra la documentation que vous convertirez en base de données vectorielle.
- .env : C’est ici que vous conserverez votre clé API Perplexity.
Dans .env, saisissez ce qui suit :
PERPLEXITY_API_KEY=your_api_key_hereRemplacez your_api_key_here par votre véritable clé. Pour l’obtenir, rendez-vous sur le tableau de bord d’accueil de la console API Perplexity et sélectionnez Create an API key. Gardez cette clé API confidentielle.
Nous utiliserons deux modèles : pplx-embed-v1-0.6b de Perplexity, pour générer les embeddings de notre documentation avant de les charger dans ChromaDB, et GPT-5.6-Luna (accessible via l’API de Perplexity), qui traitera les informations récupérées.
Dans document.txt, ajoutez le texte que votre pipeline RAG récupérera. Si vous n’avez pas de document sous la main, utilisez pour ce tutoriel Songs of Innocence and of Experience de William Blake, disponible sur le Projet Gutenberg. Il s’agit d’un texte court, facile à comprendre et appartenant au domaine public.
Étape 4 : écrire le programme d’indexation
Copiez-collez le code ci-dessous dans index.py. Chaque intertitre explique brièvement ce que fait le segment de code qui suit. C’est ce programme qui convertira votre contenu source en embeddings vectoriels et les stockera dans une base de données ChromaDB à l’aide du modèle d’embedding de Perplexity, pplx-embed-v1-0.6b, et de la bibliothèque NumPy.
Voici ce que fait le programme :
- Ouvre document.txt.
- Divise le texte en fragments qui se chevauchent.
- Envoie ces fragments au modèle d’embedding pplx-embed-v1-0.6b de Perplexity.
- Décode et normalise les vecteurs renvoyés à l’aide de NumPy, une bibliothèque Python de fonctions de calcul.
- Stocke les vecteurs et les fragments d’origine dans une base de données ChromaDB (vous la verrez apparaître dans le répertoire de votre projet).
Il est configuré pour ne pas réindexer votre document à chaque exécution. Si vous ajoutez des informations dans document.txt, seul le nouveau texte sera converti en embeddings.
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())Étape 5 : écrire l’orchestrateur du système RAG
Copiez-collez le code ci-dessous dans rag.py. Il s’agit d’une implémentation RAG complète mais minimale, qui utilise le SDK Perplexity et la fonctionnalité de base de données vectorielle locale de ChromaDB.
Voici ce qui se passera lorsque vous exécuterez le programme :
- Se connecte à Perplexity et à votre nouvelle base de données ChromaDB.
- Vérifie que la base de données contient des documents indexés.
- Reçoit une question de l’utilisateur.
- Envoie la question au modèle d’embedding de Perplexity.
- Décode et normalise l’embedding obtenu à l’aide de NumPy.
- Recherche dans ChromaDB les trois fragments de document les plus similaires.
- Construit un prompt contenant les fragments récupérés et la question de l’utilisateur.
- Envoie le prompt à GPT-5.6 Luna via l’API Agent de Perplexity.
- Affiche la réponse et attend une nouvelle question.
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)Étape 6 : exécuter les applications
Dans le terminal PowerShell de VS Code, saisissez la commande suivante pour générer les embeddings du contenu de document.txt :
.\.venv\Scripts\python.exe index.pySi votre document a bien été indexé, vous devriez voir une sortie semblable à celle-ci :
Indexing complete!
Unchanged chunks: 0
New or modified chunks: 58
Removed chunks: 0
Total stored chunks: 58Il est maintenant temps d’exécuter l’application principale d’orchestration. Saisissez cette commande :
.\.venv\Scripts\python.exe rag.pySi l’exécution réussit, vous verrez ce qui suit :
Connected to existing ChromaDB database.
Stored chunks: 58
Ask a question (or type exit): Vous pouvez maintenant poser des questions qui s’appuieront sur la base de données vectorielle que vous avez créée, par exemple :
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.Étape 7 : comprendre ce que vous avez construit
Le système que vous avez construit comprend les deux pipelines fondamentaux présents dans toute architecture RAG : un pipeline d’indexation, ou « d’ingestion », et un pipeline de récupération et de génération.
Votre implémentation RAG basique effectue désormais toutes les opérations suivantes :
- Stockage vectoriel : Les embeddings générés à partir de votre fichier de connaissances sont enregistrés dans votre base de données ChromaDB, dans votre environnement local.
- Indexation incrémentielle : Les fragments de document inchangés ne sont pas reconvertis en embeddings, et vous pouvez mettre à jour le document quand vous le souhaitez.
- Récupération sémantique : ChromaDB récupère les fragments en fonction de leur similarité vectorielle (à l’initiative de l’orchestrateur).
- Génération de réponses ancrées : Le LLM reçoit les passages récupérés comme contexte et les intègre à sa réponse.
- Indexation et interrogation indépendantes : Vous pouvez poser des questions sans retraiter l’intégralité du texte contenu dans votre fichier de connaissances.
- Connexion au modèle via API : Toutes les réponses sont générées par GPT-5.6 Luna via Perplexity, et non par un modèle exécuté sur votre machine.
Prochaines étapes : comment aller plus loin avec cette implémentation
L’objectif de ce tutoriel est de construire une implémentation simple et élémentaire. Il couvre certains des composants fondamentaux de l’architecture RAG présents dans les systèmes modernes. Si vous souhaitez aller plus loin, il existe plusieurs façons de l’enrichir.
Voici quelques idées pour élargir la portée de votre implémentation :
- Expérimentez avec LangChain : LangChain est l’un des frameworks d’orchestration open source les plus populaires. Il contient des composants prêts à l’emploi pour créer des applications capables d’exécuter des pipelines RAG complexes.
- Étendez les fonctionnalités de recherche : Combinez la recherche vectorielle dense avec une recherche lexicale (par mots-clés), comme BM25. Ajouter la recherche web via l’API Search de Perplexity vous permettrait également d’ancrer vos réponses dans des données actuelles.
- Ajoutez un modèle de reranking : Intégrez un modèle de reranking qui classe les passages récupérés par rapport au prompt initial et sélectionne les plus pertinents à inclure dans le contexte d’entrée fourni au LLM.
- Construisez un système RAG adaptatif : La RAG adaptative utilise soit un LLM, soit un classifieur (un composant de l’orchestrateur) pour déterminer quelle méthode de récupération employer dans un système RAG modulaire. En construire un est un bon moyen d’explorer des implémentations RAG plus sophistiquées.
Même si tout cela peut sembler complexe, gardez à l’esprit que les plateformes d’IA grand public comme Perplexity peuvent vous apporter une aide avancée à la programmation. Elles sont excellentes pour les projets personnels et l’expérimentation, et les coûts peuvent rester relativement faibles.
Remarque : ce tutoriel utilise GPT-5.6 Luna. La disponibilité des modèles pouvant évoluer, vous devrez peut-être mettre à jour l’appel API.