Mise en œuvre d’une RAG de base : tutoriel étape par étape

Ce tutoriel accessible aux débutants explique le fonctionnement d’une mise en œuvre RAG de base, présente les pratiques exemplaires et vous guide dans la création d’un système RAG fonctionnel en ligne de commande avec Python, ChromaDB et les modèles de plongement et de langage de Perplexity.

Basic RAG implementation process diagram: the interface sends input to the orchestrator, which retrieves data from a vector database, builds the input context for the LLM, and returns the output to the interface.

La RAG est une composante essentielle de l’infrastructure moderne fondée sur les LLM. En permettant aux modèles d’IA d’accéder à des données externes, elle aide à remédier à 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 renseignements sensibles ou exclusifs.

La mise en œuvre de la RAG peut être très complexe. Pourtant, un système RAG de base est étonnamment facile à créer. Pour les débutants, la création d’une architecture simple permet de comprendre comment la RAG fonctionne concrètement et sert de tremplin pour pousser l’expérimentation plus loin.

Dans cet article, nous décrirons une mise en œuvre RAG de base, passerons en revue les pratiques exemplaires, puis créerons un système fonctionnel à l’aide de Python, de ChromaDB et de deux modèles Perplexity, l’un pour les plongements et l’autre pour la génération des réponses.

Processus de mise en œuvre d’une RAG de base : aperçu général

Un système RAG de base comporte trois composantes principales : un orchestrateur, une source d’information et un LLM. Dans un flux de travail typique, l’utilisateur saisit une requête, que l’orchestrateur modifie pour interroger les sources d’information connectées. L’information récupérée est ensuite ajoutée au contexte d’entrée initial et envoyée au LLM afin qu’il génère une réponse.

Vous devrez tenir compte des étapes suivantes lors de la mise en œuvre de votre système RAG :

  1. Indexation et plongement : À cette étape, vos documents sont convertis en une source d’information que l’orchestrateur peut interroger. L’une des façons les plus courantes d’y parvenir consiste à créer un index vectoriel interrogeable. Nous utiliserons un modèle dédié de Perplexity pour convertir les segments de vos documents en plongements (embeddings). Nous stockerons ensuite ces plongements dans ChromaDB, une base de données vectorielle populaire à code source ouvert.
  2. Orchestration : Il s’agit de l’application qui fait le lien entre la source d’information externe (une base de données vectorielle, dans notre cas) et le LLM. Nous créerons un script Python simple qui jouera le rôle d’orchestrateur.
  3. Récupération et génération : Lorsqu’un utilisateur pose une question dans l’interface de clavardage, l’orchestrateur la prend en charge, effectue une recherche vectorielle et transmet l’entrée enrichie au LLM. Plutôt que de créer une interface frontale dédiée, nous utiliserons la ligne de commande pour communiquer avec notre orchestrateur Python.

Pratiques exemplaires : qu’est-ce qui fait l’efficacité d’une mise en œuvre RAG?

Il existe plusieurs types d’architecture RAG, et chaque cas d’utilisation exige une approche différente. Cela dit, certaines pratiques exemplaires s’appliquent dans tous les cas et garantissent des systèmes précis, rentables, évolutifs et faciles à maintenir.

Les pratiques exemplaires suivantes s’appliquent à tous les types de mise en œuvre RAG :

  • Assurez-vous d’avoir un pipeline d’ingestion propre : Vos données sources doivent être aussi propres que possible avant l’indexation. Vous devriez aussi utiliser un modèle de plongement adapté à votre contenu.
  • Utilisez la recherche hybride : Les meilleures méthodes de récupération, qu’il s’agisse de la recherche dans une base de données vectorielle, de la recherche Web par API, du parcours d’un graphe de connaissances, de la recherche par mots-clés ou d’autres méthodes, varient selon le cas d’utilisation. Il est important de bien choisir la combinaison de méthodes pour réduire les coûts au minimum.
  • Évaluez votre système : Après la mise en œuvre, vous devriez évaluer votre système selon trois mesures fondamentales : l’exactitude, la pertinence et la latence. L’exactitude renvoie à la justesse factuelle, la pertinence, à l’applicabilité de l’information récupérée aux requêtes des utilisateurs, et la latence, à la vitesse à laquelle l’information est récupérée.
  • Traitez l’information de façon sécurisée : Si votre système RAG s’appuie sur des renseignements internes privés, assurez-vous qu’ils sont stockés de façon sécurisée et que l’accès à l’interface du système est contrôlé. Les clés d’API ne doivent jamais être partagées.

Mise en œuvre d’une RAG de base : tutoriel en 7 étapes

Dans ce tutoriel, nous créerons une application en ligne de commande qui répond à des questions portant sur un seul document. Nous utiliserons Python, ChromaDB et l’API Perplexity.

Le but n’est pas de créer 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 : Il s’agit du langage de programmation que nous utiliserons pour créer l’orchestrateur qui coordonnera la circulation des données entre le modèle de plongement, 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 de plongement (qui transforme vos données en plongements vectoriels) et le LLM qui traitera la requête enrichie. Vous n’avez pas besoin d’un compte payant pour ce faire, mais l’opération entraînera un léger coût en crédits.

Étape 2 : Créer un dossier de projet

Commencez par créer un dossier intitulé rag-project et ouvrez-le dans VS Code en sélectionnant File > Open Folder. Ouvrez ensuite le terminal intégré au moyen de Terminal > New Terminal.

Saisissez la commande suivante pour créer un environnement virtuel Python :

bash
py -3.12 -m venv .venv

Vous 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 par API. ChromaDB crée la base de données vectorielle et s’exécute localement. Python-dotenv charge vos clés d’API de façon sécurisée à partir d’un fichier local, et NumPy est nécessaire pendant le processus d’ingestion.

Installez-les à l’aide de la commande suivante :

bash
.\.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 New File… dans la barre latérale Explorer :

  • index.py : Il s’agit de l’application qui indexera votre document. Vous pouvez la relancer pour ajouter du texte supplémentaire.
  • rag.py : Il s’agit de l’application Python qui jouera le rôle d’orchestrateur.
  • document.txt : Ce fichier contiendra la documentation que vous convertirez en base de données vectorielle.
  • .env : C’est dans ce fichier que vous conserverez votre clé d’API Perplexity.

Dans .env, saisissez ce qui suit :

plaintext
PERPLEXITY_API_KEY=your_api_key_here

Remplacez your_api_key_here par votre clé réelle. Pour l’obtenir, rendez-vous dans le tableau de bord d’accueil de la console API de Perplexity et sélectionnez Create an API key. Gardez cette clé d’API confidentielle.

Nous utiliserons deux modèles : pplx-embed-v1-0.6b de Perplexity, pour créer les plongements de notre documentation avant de les téléverser dans ChromaDB, et GPT-5.6-Luna (accessible au moyen de l’API de Perplexity), qui traitera l’information récupérée.

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, offert sur Project Gutenberg. Il s’agit d’un texte court, facile à comprendre et du domaine public.

Étape 4 : Écrire le programme d’indexation

Copiez et collez le code ci-dessous dans index.py. Chaque intertitre explique brièvement ce que fait le segment de code qui suit. Ce programme convertira vos documents sources en plongements vectoriels et les stockera dans une base de données ChromaDB à l’aide du modèle de plongement de Perplexity, pplx-embed-v1-0.6b, et de la bibliothèque NumPy.

Voici ce que fait le programme :

  1. Ouvre document.txt.
  2. Divise le texte en segments qui se chevauchent.
  3. Envoie ces segments au modèle de plongement pplx-embed-v1-0.6b de Perplexity.
  4. Décode et normalise les vecteurs renvoyés à l’aide de NumPy, une bibliothèque Python de fonctions de calcul.
  5. Stocke les vecteurs et les segments d’origine dans une base de données ChromaDB (vous la verrez apparaître dans le répertoire de votre projet).

Le programme est conçu pour ne pas réindexer votre document chaque fois que vous l’exécutez. Si vous ajoutez de l’information dans document.txt, il ne créera des plongements que pour le nouveau texte.

python
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 et collez le code ci-dessous dans rag.py. Il s’agit d’une mise en œuvre RAG complète, mais minimale, qui utilise le SDK Perplexity et la fonctionnalité de base de données vectorielle locale de ChromaDB.

Voici ce que fera le programme lorsque vous l’exécuterez :

  1. Se connecte à Perplexity et à votre nouvelle base de données ChromaDB.
  2. Vérifie que la base de données contient des documents indexés.
  3. Reçoit une question de l’utilisateur.
  4. Envoie la question au modèle de plongement de Perplexity.
  5. Décode et normalise le plongement obtenu à l’aide de NumPy.
  6. Recherche dans ChromaDB les trois segments de document les plus similaires.
  7. Construit une requête contenant les segments récupérés et la question de l’utilisateur.
  8. Envoie la requête à GPT-5.6 Luna au moyen de l’API Agent de Perplexity.
  9. Affiche la réponse et attend une autre question.
python
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 créer les plongements du contenu de document.txt :

bash
.\.venv\Scripts\python.exe index.py

Si votre document a bien été indexé, vous devriez voir une sortie semblable à celle-ci :

plaintext
Indexing complete! Unchanged chunks: 0 New or modified chunks: 58 Removed chunks: 0 Total stored chunks: 58

Il est maintenant temps d’exécuter l’application principale d’orchestration. Saisissez cette commande :

bash
.\.venv\Scripts\python.exe rag.py

Si l’exécution réussit, vous verrez ce qui suit :

plaintext
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 :

plaintext
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 créé

Le système que vous avez créé 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 mise en œuvre RAG de base effectue maintenant toutes les opérations suivantes :

  • Stockage vectoriel : Les plongements sont enregistrés dans votre base de données ChromaDB, dans votre environnement local, à partir de votre fichier de connaissances.
  • Indexation incrémentielle : Les segments de document inchangés ne font pas l’objet de nouveaux plongements, et vous pouvez mettre le document à jour quand bon vous semble.
  • Récupération sémantique : ChromaDB récupère les segments en fonction de la similarité vectorielle (à la demande 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 tout le texte contenu dans votre fichier de connaissances.
  • Connexion aux modèles par API : Toutes les réponses sont générées par GPT-5.6 Luna au moyen de Perplexity plutôt que par un modèle exécuté sur votre ordinateur.

Prochaines étapes : comment pousser cette mise en œuvre plus loin

Ce tutoriel vise à créer une mise en œuvre simple et élémentaire. Il couvre certaines des composantes fondamentales de l’architecture RAG présentes dans les systèmes modernes. Si vous voulez aller plus loin, il existe différentes façons de l’enrichir.

Voici quelques idées pour élargir la portée de votre mise en œuvre :

  • Faites l’essai de LangChain : LangChain est l’un des cadriciels d’orchestration à code source ouvert les plus populaires. Il contient des composants préconçus pour créer des applications capables d’exécuter des pipelines RAG complexes.
  • Élargissez les fonctionnalités de recherche : Combinez la recherche vectorielle dense avec une recherche lexicale (par mots-clés) comme BM25. L’ajout de la recherche Web au moyen de l’API Perplexity Search vous permettrait aussi d’ancrer les réponses dans des données à jour.
  • Ajoutez un modèle de reclassement : Intégrez un modèle de reclassement qui classe les passages récupérés par rapport à la requête initiale et sélectionne les plus pertinents pour les inclure dans le contexte d’entrée fourni au LLM.
  • Créez un système RAG adaptatif : La RAG adaptative utilise soit un LLM, soit un classificateur (une composante de l’orchestrateur) pour déterminer quelle méthode de récupération employer dans un système RAG modulaire. En créer un est une bonne façon d’explorer des mises en œuvre 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 offrir une aide avancée à la programmation. Elles conviennent parfaitement aux projets personnels et à l’expérimentation, et les coûts peuvent rester relativement bas.

Remarque : Ce tutoriel utilise GPT-5.6 Luna. La disponibilité des modèles peut changer; vous pourriez donc devoir mettre à jour l’appel d’API.