Implementation du flux RAG
Apres avoir compris le flux RAG conceptuellement, passons a l’implementation concrete. Nous allons construire un exemple complet qui demontre comment decouper du texte, generer des embeddings, les stocker dans une base vectorielle et effectuer des recherches par similarite.
Les cinq etapes de l’implementation
Notre implementation suit les cinq etapes vues precedemment :
- Decouper le texte par sections
- Generer les embeddings pour chaque chunk
- Creer un store vectoriel et y ajouter chaque embedding
- Generer un embedding pour la question de l’utilisateur
- Chercher dans le store les chunks les plus pertinents
Etape 1 : Decoupage du texte
On charge le document et on le decoupe en sections :
# Charger le document
with open("./report.md", "r") as f:
text = f.read()
# Decouper par sections (reutilise la fonction vue precedemment)
chunks = chunk_by_section(text)
chunks[2] # Verifier le contenu d'un chunk (ici la table des matieres)
On reutilise la fonction chunk_by_section de la lecon precedente pour diviser le document en sections logiques.
Etape 2 : Generation des embeddings
On cree les embeddings pour tous les chunks en une seule fois :
# Generer les embeddings pour tous les chunks d'un coup
embeddings = generate_embedding(chunks)
La fonction d’embedding a ete adaptee pour accepter aussi bien une chaine unique qu’une liste de chaines, ce qui rend le traitement par lots plus efficace.
Etape 3 : Stockage dans la base vectorielle
On cree notre store vectoriel et on le remplit avec les embeddings et le texte associe :
# Creer le store vectoriel
store = VectorIndex()
# Ajouter chaque embedding avec son contenu textuel original
for embedding, chunk in zip(embeddings, chunks):
store.add_vector(embedding, {"content": chunk})
Remarque importante : on stocke a la fois l’embedding et le texte original. C’est essentiel car lors de la recherche, on a besoin de recuperer le texte reel, pas juste les valeurs numeriques de l’embedding.
Pourquoi stocker le texte original ?
Quand on interroge la base vectorielle, recuperer uniquement les nombres de l’embedding n’a aucune utilite. On a besoin du texte qui a servi a generer ces embeddings. C’est pourquoi on associe le chunk de texte original (ou au minimum une reference vers celui-ci) a chaque embedding dans la base.
Etape 4 : Traitement des requetes utilisateur
Quand un utilisateur pose une question, on genere un embedding pour sa requete :
# Convertir la question en embedding
user_embedding = generate_embedding(
"Qu'a fait le departement ingenierie logicielle l'annee derniere ?"
)
Etape 5 : Recherche du contenu pertinent
On interroge le store vectoriel pour trouver les chunks les plus similaires :
# Chercher les 2 chunks les plus proches
results = store.search(user_embedding, 2)
# Afficher les resultats avec leur score de distance
for doc, distance in results:
print(distance, "\n", doc["content"][0:200], "\n")
Cette recherche retourne les deux chunks les plus pertinents avec leurs scores de similarite (distances cosinus).
Comprendre les resultats
Pour notre requete sur le departement ingenierie logicielle, on obtient :
| Chunk | Distance cosinus |
|---|---|
| Section 2 : Ingenierie logicielle | 0.71 (meilleure correspondance) |
| Section Methodologie | 0.72 (deuxieme correspondance) |
Les valeurs de distance les plus basses indiquent une similarite plus elevee. La Section 2 est donc le resultat le plus pertinent pour notre requete.
Et ensuite ?
Cette implementation fonctionne bien pour les cas basiques, mais il existe des scenarios ou elle ne donne pas les resultats attendus. Dans les lecons suivantes, nous explorerons des ameliorations pour rendre notre systeme RAG plus robuste et precis.
Le point cle a retenir : la RAG consiste fondamentalement a convertir du texte en nombres (embeddings), a stocker ces nombres efficacement, puis a utiliser la similarite mathematique pour trouver le contenu pertinent quand les utilisateurs posent des questions.
Exercice : Implementez votre propre pipeline RAG
En utilisant les extraits de code de cette lecon, construisez un pipeline RAG complet :
- Prenez un document Markdown de votre choix (un README, un article de blog, etc.)
- Decoupez-le en chunks par sections
- Generez les embeddings avec VoyageAI
- Stockez-les dans un
VectorIndex - Posez 3 questions differentes et observez les resultats
Bonus : Comparez les resultats en changeant le nombre de chunks retournes (1, 3, 5). A quel moment les resultats deviennent-ils moins pertinents ?