Créez votre base de données vectorielle

Dans le cadre du projet de Génération Augmentée par Récupération (RAG) pour la mairie de Trifouillis-sur-Loire, la mise en place d'une base de données vectorielle est une étape cruciale. Cette base permettra à l'agent conversationnel de rechercher rapidement et précisément des informations pertinentes au sein du vaste corpus de documents municipaux.

Pourquoi une base de données vectorielle est-elle cruciale pour un RAG ?

  1. Recherches rapides et précises : En représentant les documents sous forme de vecteurs numériques, une base de données vectorielle facilite des recherches basées sur la similarité, garantissant ainsi l'identification rapide des informations les plus pertinentes, même dans de grands ensembles de données.

  2. Compréhension du contexte sémantique : Grâce aux mesures de similarité entre vecteurs, la base de données saisit les relations sémantiques entre les textes, offrant des réponses plus contextualisées et pertinentes.

  3. Intégration avec les grands modèles de langage (LLMs) : Les systèmes RAG, tels que celui que nous développons, combinent des bases de données vectorielles avec des LLMs pour enrichir les réponses aux requêtes en s'appuyant sur des informations précises et factuelles.

Comprenez ce qu’est une BDD vectorielle

Une base de données vectorielle stocke des données sous forme de vecteurs numériques et permet des recherches rapides basées sur la similarité. Elle est particulièrement adaptée pour gérer des données à haute dimensionnalité, comme des représentations de texte ou d'images, et est essentielle pour des applications nécessitant une récupération d'information efficace et précise.

Quelles sont les spécificités des bases de données vectorielles ?

Voici un aperçu de ces spécificités :

  • Représentation des données : Contrairement aux bases de données relationnelles qui stockent les informations sous forme de tables avec des lignes et des colonnes, les bases de données vectorielles représentent chaque donnée comme un point dans un espace à haute dimension. Chaque dimension du vecteur correspond à une caractéristique ou propriété spécifique de la donnée originale.

  • Indexation et recherche : Elles utilisent des structures d'indexation spécialisées et des algorithmes avancés pour effectuer des recherches efficaces basées sur la similarité. Par exemple, des techniques comme la recherche du plus proche voisin approximatif permettent d'identifier rapidement des vecteurs similaires, ce qui est essentiel pour des applications telles que la recherche sémantique ou les systèmes de recommandation.

  • Gestion de la haute dimensionnalité : Les bases de données vectorielles sont conçues pour gérer des vecteurs à haute dimensionnalité, ce qui est crucial pour des applications d'intelligence artificielle et de machine learning où les données peuvent avoir des centaines, voire des milliers de dimensions. Elles emploient des techniques telles que la quantification ou le hachage pour optimiser le stockage et la recherche de ces vecteurs complexes.

Quelles différences par rapport aux bases de données traditionnelles ?

Ces différences sont au nombre de trois :

  • Type de données gérées : Les bases de données relationnelles traditionnelles sont optimisées pour des données structurées et des requêtes précises, tandis que les bases de données vectorielles excellent dans la gestion de données non structurées et la recherche de similarités.

  • Méthodologie de recherche : Alors que les bases de données traditionnelles reposent sur des correspondances exactes pour les recherches, les bases de données vectorielles évaluent la similarité entre les vecteurs en calculant des distances dans l'espace multidimensionnel, permettant ainsi des correspondances approximatives basées sur le contexte et le sens.

  • Scalabilité et flexibilité : Les bases de données vectorielles offrent une scalabilité et une flexibilité accrues, permettant d'apporter des modifications dynamiques aux données, d'effectuer des sauvegardes et de garantir des fonctionnalités de sécurité, ce qui les rend adaptées aux applications modernes nécessitant une gestion efficace de grandes quantités de données non structurées.

Choisissez la BDD vectorielle

Comment choisir la base de données vectorielle appropriée ?

Lors de la sélection d'une base de données vectorielle pour notre projet, plusieurs critères doivent être pris en compte :

  • Volume de données : La capacité de la base à gérer efficacement le volume de données prévu.

  • Performance de la recherche : Le temps nécessaire pour retrouver les informations pertinentes.

  • Facilité d'intégration : La compatibilité avec nos outils existants, tels que LangChain.

  • Coûts en production : L'impact financier en fonction de la taille de la base et de la fréquence des requêtes.

  • Fonctionnalités spécifiques : Par exemple, la prise en charge des mises à jour incrémentales ou des fonctionnalités de sécurité avancées.

Voici un benchmark rapide de ces 4 solutions :

Base de données

Avantages

Limites

Faiss

- Optimisé pour des recherches de similarité rapides sur de grands ensembles de données

- Open-source avec une communauté active

- Support limité aux ressources communautaires

Pinecone

Solution managée facile à déployer

- Offre des fonctionnalités avancées telles que le filtrage

- Disponible uniquement en mode SaaS

- Non open-source

Weaviate

- Intégration avec des graphes de connaissances

- Schéma flexible adaptable à différents types de données

- Fonctionnalités avancées peuvent nécessiter une courbe d'apprentissage

Milvus

- Conçu pour des écosystèmes d’IA à grande échelle

- Prend en charge plusieurs types d'index vectoriels

- Nécessite une configuration appropriée pour des performances optimales

Pour la suite de notre projet, nous utiliserons FAISS pour sa simplicité d’utilisation.

Prenez en main un framework pour orchestrer la vectorisation

Pourquoi choisir un framework ?

Les frameworks comme LangChain et Llama Index standardisent et accélèrent le développement de systèmes RAG. Ils offrent :

  1. Une intégration native avec les bases de données vectorielles (Faiss, Pinecone, etc.).

  2. Des pipelines prêts à l’emploi pour la recherche et la génération de réponses.

  3. L’abstraction des complexités techniques, comme la gestion du contexte ou le chunking.

Ces outils permettent :

  • Une intégration native avec des bases de données vectorielles comme Faiss.

  • La création de chaînes de traitement pour les recherches et les modèles de langage.

  • Une simplification des fonctionnalités avancées (e.g., récupération contextuelle).

Voici un tableau comparatif de ces deux frameworks :

Critères

Langchain

LLama Index

Objectif Principal

Orchestrer des modèles de langage avec des workflows complexes

Gérer, structurer et interroger des données non structurées via des LLMs

Intégration

interface standardisée pour interagir avec divers modèles de langage, simplifiant le passage d'un modèle à un autre.

abstractions pour gérer les pipelines de récupération, facilitant l'intégration de différentes composantes comme les embeddings et les LLMs.

Gestion du Contexte

capacités de gestion de la mémoire, permettant de conserver le contexte des interactions précédentes pour des conversations plus cohérentes.

moteurs de chat contextuels pour des requêtes interactives, en s'appuyant sur des segments de documents stockés.

Personnalisation

création de workflows complexes intégrant plusieurs outils et appels de LLM

composants pour l'évaluation des pipelines RAG, permettant de tester des éléments individuels comme le récupérateur, le moteur de requête et la génération de réponses.

Découpez vos données en petits bouts (chunking)

Les LLM perdent en cohérence quand ils traitent des textes trop longs. Un découpage intelligent segmente l'information en unités sémantiquement autonomes, ce qui préserve le sens et permet aux mécanismes de récupération (comme les embeddings) d'identifier les passages pertinents avec précision.

Le principal challenge du RAG est la gestion des documents très longs. En effet, la taille d'un document est généralement plus grande que le nombre de token maximal que peut prendre un LLM en entrée.

Ceci implique l'utilisation des techniques qui permettent de découper le texte en des petits morceaux tout en préservant le contexte et la pertinence du document. Ce découpage est appelé Chunking.

La stratégie de chunking influence votre système de RAG. Un mauvais découpage peut conduire à la perte de cohérence, perte d'information dans la mémoire non paramétrique de votre RAG.

Examinons plusieurs stratégies :

1. Découpage récursif avec chevauchement 

Cette méthode segmente le texte en morceaux de taille définie, avec un chevauchement entre les segments pour préserver le contexte. Par exemple, en utilisant une taille de segment de 1 000 caractères avec un chevauchement de 200 caractères, chaque segment partage une portion avec le précédent, assurant ainsi une continuité contextuelle.

Exemple en Python avec Langchain :

from langchain.text_splitter import RecursiveCharacterTextSplitter

# Initialisation du splitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, # Taille de chaque segment
    chunk_overlap=200 # Chevauchement entre les segments)
    
# Découpage du texte
segments = text_splitter.split_text("Votre texte ici")

Cette approche est particulièrement utile pour les textes où le contexte entre les segments est crucial pour la compréhension globale.

2. Découpage basé sur les balises (Markdown ou HTML)

Pour les documents structurés en Markdown ou HTML, le découpage peut s'effectuer en se basant sur les balises présentes, telles que les titres, les paragraphes ou les listes. Cette méthode préserve la structure logique du document et assure que chaque segment représente une unité sémantique cohérente.

from bs4 import BeautifulSoup

def chunk_by_tags(html_content, tags):
    soup = BeautifulSoup(html_content, 'html.parser')
    segments = []
    for tag in tags:
        elements = soup.find_all(tag)
            for elem in elements:
                segments.append(elem.get_text())
    return segments

# Exemple d'utilisation
html_content = "<h1>Titre</h1><p>Paragraphe 1</p><p>Paragraphe 2</p>"
tags = ['h1', 'p']
segments = chunk_by_tags(html_content, tags)

Cette technique est efficace pour les documents bien structurés, garantissant que chaque segment conserve une signification sémantique claire.

3. Découpage sémantique à l'aide de modèles NLP

Cette approche utilise des modèles de traitement du langage naturel pour segmenter le texte en unités sémantiquement cohérentes, telles que des phrases ou des paragraphes, en se basant sur la structure grammaticale et le sens du texte.

Exemple en Python avec spaCy :

import spacy

# Charger le modèle français de spaCy
nlp = spacy.load("fr_core_news_sm")

def semantic_chunking(text, max_chunk_size=150):
    doc = nlp(text)
    segments = []
    current_segment = []
    for sent in doc.sents:
        if len(" ".join(current_segment)) + len(sent.text) &lt;= max_chunk_size:
            current_segment.append(sent.text)
        else:
            segments.append(" ".join(current_segment))
        current_segment = [sent.text]
        if current_segment:
            segments.append(" ".join(current_segment))
    return segments
    
# Exemple d'utilisation
text = "Votre texte ici."
segments = semantic_chunking(text, max_chunk_size=150)

Cette méthode assure que chaque segment est sémantiquement cohérent, ce qui est particulièrement bénéfique pour les applications nécessitant une compréhension approfondie du texte.

Comparons ces différentes techniques :

Technique

Avantages

Inconvénients

Découpage récursif avec chevauchement

Préserve le contexte entre les segments

Génère des redondances, augmente le volume de données

Découpage basé sur les balises

Respecte la structure logique du document

Dépend de la qualité de la structure du document

Découpage sémantique

Maintient la cohérence sémantique des segments

Nécessite des ressources NLP, peut être plus lent.

Ces techniques sont dépendantes du type de données auxquelles nous sommes confrontés.

Dans cette vidéo, nous avons vu : 

  • Nous avons exploré comment diviser le texte en segments de taille fixe avec un chevauchement entre eux pour préserver le contexte.

  • Nous avons démontré comment utiliser les balises structurelles pour segmenter le contenu de manière logique.

  • Nous avons illustré l'utilisation de modèles de traitement du langage naturel pour segmenter le texte en unités sémantiquement cohérentes.

Créez et interrogez l’index Faiss

C’est le moment de tester notre solution pour la mairie. Suite à notre benchmark, nous avons opté pour une solution construite avec Faiss.

1. Installation de Faiss

Pour commencer, assurez-vous d'avoir Faiss installé dans votre environnement Python. Vous pouvez l'installer via pip :

pip install faiss-cpu
pip install mistralai==0.4.2

2. Préparation des données

Nous disposons d'un ensemble de documents textuels liés à la mairie. Notre objectif est de créer un index qui permettra de retrouver rapidement les documents les plus pertinents en fonction d'une requête utilisateur.

Tout d'abord, nous devons convertir ces documents en vecteurs numériques (embeddings). Pour ce faire, nous utilisons les model d’embedding mis à disposition par Mistral.

from mistralai.client import MistralClient
from mistralai.models.chat_completion import ChatMessage
import os

# Initialisation du client avec votre clé API
api_key = os.environ["MISTRAL_API_KEY"]
client = MistralClient(api_key=api_key)

def embed_text(text):
    # Appel de l'API d'embedding
    embeddings_batch = client.embeddings(
    model="mistral-embed",
    input=text)
    return embeddings_batch.data[0].embedding

3. Création de l'index Faiss

Une fois les embeddings générés pour chaque document, nous pouvons créer un index Faiss et y ajouter nos vecteurs.

import faiss
import numpy as np

# documents est une liste de textes
documents = ["Texte du document 1", "Texte du document 2", ...]

# Génération des embeddings pour chaque document
embeddings = np.array([embed_text(doc) for doc in documents])

# Initialisation de l'index Faiss
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)

# Ajout des embeddings à l'index
index.add(embeddings)

# Sauvegarde de l'index sur le disque
faiss.write_index(index, "faiss_index.idx")

4. Interrogation de l'index

Pour rechercher les documents les plus pertinents par rapport à une requête utilisateur, nous procédons comme suit :

# Requête utilisateur
query = "Informations sur les horaires d'ouverture de la mairie"

# Génération de l'embedding de la requête
query_embedding = embed_text

# Recherche des k documents les plus similaires
k = 5
distances, indices = index.search(np.array([query_embedding]), k)

# Affichage des résultats
for idx in indices[0]:
print(f"Document {idx}: {documents[idx]}")

Dans cet exemple, nous recherchons les 5 documents les plus similaires à la requête de l'utilisateur en calculant la distance entre l'embedding de la requête et ceux des documents présents dans l'index.

Dans cette vidéo, nous avons vu : 

  • comment installer Faiss

  • comment charger des vecteurs de données dans un index Faiss afin de faciliter des recherches efficaces.

  • la manière d'effectuer des requêtes sur l'index Faiss pour identifier des vecteurs similaires, en utilisant des exemples concrets.

À vous de jouer

Contexte

Vous disposez du document sur les réglementations municipales.

Votre tâche consiste à choisir une technique de découpage (chunking) appropriée, à justifier votre choix et à l'implémenter en Python.

Consignes

Étant donné la longueur du document, il est essentiel de le diviser en segments plus petits pour faciliter l'indexation et la recherche. Opter pour la technique de chunking appropriée.

En résumé 

  • Une base de données vectorielle permet une recherche rapide et contextuelle.

  • LangChain et Llama Index facilitent la création de pipelines pour interroger ces bases.

  • Le découpage des données en chunks améliore la précision de la recherche.

  • Faiss est un outil puissant pour construire des indexes basés sur la similarité des vecteurs.

Dans la partie suivante, nous explorerons comment intégrer ces concepts pour créer un système RAG fonctionnel et efficace.

Et si vous obteniez un diplôme OpenClassrooms ?
  • Formations jusqu’à 100 % financées
  • Date de début flexible
  • Projets professionnalisants
  • Mentorat individuel
Trouvez la formation et le financement faits pour vous