Implémentation Python de RAG et de la recherche de connaissances

Ce chapitre présente la technologie de génération augmentée par récupération (RAG).

RAG est l'une des technologies clés pour construire des agents à forte intensité de connaissances.

En combinant la recherche vectorielle avec des modèles de génération de langage, le RAG donne aux agents la capacité d'accéder à des connaissances externes et de les utiliser, plutôt que de s'appuyer uniquement sur le contenu « mémorisé » dans les paramètres du modèle.


Principes fondamentaux du RAG

L'idée centrale du RAG est de combiner deux étapes, « la recherche d'informations » et « la génération de langage », pour former un pipeline complet de questions-réponses.

Lorsqu'un utilisateur pose une question, le système récupère d'abord le contenu pertinent pour la question dans la base de connaissances.

Ensuite, le système fournit le contenu récupéré comme contexte au modèle de génération, ce qui l'aide à produire des réponses plus précises et mieux étayées.

Pourquoi le RAG est nécessaire

Les modèles de langage ont une date de coupure des connaissances et ne peuvent pas percevoir les événements survenus après la fin de l'entraînement.

Les paramètres du modèle sont finis, et il est impossible d'y mémoriser toutes les connaissances du monde.

Si le modèle s'appuie entièrement sur le « rappel » des connaissances à partir des paramètres, lorsqu'il rencontre un contenu qu'il ne peut pas se rappeler précisément ou qu'il n'a jamais appris, il fabrique souvent des réponses avec aplomb. C'est ce qu'on appelle communément « hallucination ».

L'approche du RAG consiste à faire consulter des données réelles au modèle avant de répondre, transformant ainsi la « réponse de mémoire » en « réponse à livre ouvert ». La source de connaissances peut également être mise à jour à tout moment sans réentraîner le modèle.

Architecture centrale

Un système RAG complet se compose généralement de trois composants essentiels :

Récupérateur: Responsable de la recherche des extraits d'informations les plus pertinents dans la base de connaissances.

Stockage vectoriel: Stocke les représentations vectorielles du contenu des documents, prenant en charge une recherche de similarité à grande échelle et à faible latence.

Générateur: Génère la réponse finale en langage naturel en se basant sur le contenu récupéré et la question originale de l'utilisateur.

La relation entre les trois peut être comprise ainsi : le récupérateur est responsable de « trouver des matériaux », le stockage vectoriel est responsable de « stocker des matériaux et trouver rapidement des matériaux similaires », et le générateur est responsable d'« organiser la réponse en regardant les matériaux ».

Workflow

Étape 1 :Phase d'indexation. Découpez les documents originaux en plusieurs segments de texte, vectorisez-les un par un, et stockez-les dans la base de données vectorielle. Cette étape est généralement effectuée hors ligne et à l'avance.

Étape 2 :Phase de récupération. Lorsqu'un utilisateur pose une requête, la requête est également vectorisée, et une recherche de similarité est effectuée dans la base de données vectorielle pour trouver les segments de texte les plus pertinents.

Étape 3 :Phase d'augmentation. Concaténez les segments de texte pertinents récupérés avec la question originale de l'utilisateur pour construire un prompt plus complet.

Étape 4 :Phase de génération. Le modèle de génération produit la réponse finale en se basant sur ce contexte augmenté.

Parmi ces quatre étapes, seule la première est un prétraitement hors ligne ; les trois autres se produisent en temps réel lorsque l'utilisateur pose sa question. Par conséquent, la vitesse et la qualité de la récupération déterminent directement la vitesse de réponse et la qualité des réponses de l'ensemble du système.

Implémentation du code

Implémentation RAG de base

class SimpleRAG:
    """
Implémentation simplifiée d'un système RAG
Contient trois composants principaux : embedder, vector store, generator
    """


    def __init__(self, embedder, vector_store, generator):
        # Embedder : responsable de la conversion du texte en vecteurs
        self.embedder = embedder
        # Base de données vectorielle : responsable du stockage des vecteurs et de la prise en charge de la recherche de similarité
        self.vector_store = vector_store
        # Générateur : génère des réponses en fonction du contexte
        self.generator = generator

    def add_documents(self, documents):
        """
Ajouter des documents à la base de connaissances
:param documents: liste de documents originaux (chaque élément est un texte complet)
        """

        # Étape 1 : découper les documents longs en petits fragments de texte pour une récupération précise
        chunks = self.chunk_documents(documents)

        # Étape 2 : Convertir tous les segments de texte en vecteurs
        embeddings = self.embedder.embed(chunks)

        # Étape 3 : Stocker les vecteurs avec le texte original correspondant dans la base de données vectorielle
        self.vector_store.add(embeddings, chunks)

    def chunk_documents(self, documents, chunk_size=500, overlap=50):
        """
Découpage de documents : découper les documents longs en segments de texte de longueur fixe avec un certain chevauchement.

:param documents: liste de documents bruts
:param chunk_size: nombre de caractères par segment de texte
:param overlap: nombre de caractères qui se chevauchent entre segments de texte adjacents (pour éviter que la sémantique soit coupée au point de découpage)
:return: liste des segments de texte après découpage
        """

        chunks = []
        for doc in documents:
            # Découpage glissant avec un pas de (chunk_size - overlap), en conservant une certaine zone de chevauchement
            for i in range(0, len(doc), chunk_size - overlap):
                chunk = doc[i:i + chunk_size]
                chunks.append(chunk)
        return chunks

    def query(self, question, top_k=5):
        """
Traiter la requête de l'utilisateur et renvoyer la réponse générée

:param question: question posée par l'utilisateur
:param top_k: nombre de segments de texte pertinents renvoyés lors de la récupération
:return: réponse finale donnée par le modèle de génération
        """

        # 1. Convertir la question en un vecteur afin qu'elle puisse être comparée aux vecteurs de la base de connaissances
        question_embedding = self.embedder.embed([question])[0]

        # 2. Récupérer les top_k segments de texte les plus similaires depuis la base de données vectorielle
        results = self.vector_store.search(question_embedding, top_k)

        # 3. Concaténer les segments de texte récupérés dans le contexte
        context = "\n".join([doc for doc, _ in results])

        # 4. Organiser le contexte et la question d'origine dans un prompt
        prompt = f"Répondez à la question en vous basant sur le contenu suivant :\n{context}\n\nQuestion : {question}"

        # 5. Le transmettre au modèle de génération pour produire la réponse finale
        return self.generator.generate(prompt)

Cette implémentation de base peut déjà exécuter le pipeline RAG complet, mais elle est souvent insuffisante dans les projets réels : la méthode de découpage est trop grossière, et le classement de la récupération ne repose que sur un seul calcul de similarité vectorielle, ce qui limite la précision. Voici quelques idées d'optimisation courantes.


RAG avancé

Les problèmes courants du RAG de base incluent : une mauvaise qualité du contenu récupéré, une précision de classement insuffisante et des informations non pertinentes mélangées au contexte.

Le RAG avancé optimise davantage le pipeline de base en introduisant des techniques telles que le reclassement et la recherche hybride, améliorant ainsi la précision de la réponse finale.

Reclassement

La recherche vectorielle dans le RAG de base est rapide, mais la précision du classement est limitée, et elle peut facilement placer plus haut un contenu moins pertinent sur le plan sémantique.

L’approche de reclassement consiste à : d’abord utiliser la recherche vectorielle pour filtrer rapidement un ensemble de textes candidats (par ex. top-20), puis utiliser un encodeur croisé (Cross-Encoder) plus coûteux en calcul mais plus précis pour noter chaque candidat un par un, les reclasser et extraire les quelques textes réellement les plus pertinents (par ex. top-5).

Cette approche en deux étapes, « filtrage grossier d’abord, puis classement précis », équilibre la vitesse et la précision de la recherche.

RAG avec reclassement

class AdvancedRAG:
    """
Système RAG avancé
Ajouter une étape de reclassement au-dessus du pipeline de base
    """


    def __init__(self, embedder, vector_store, reranker, generator):
        # Embedder
        self.embedder = embedder
        # Base de données vectorielle
        self.vector_store = vector_store
        # Modèle de reranking (cross-encoder) pour un classement fin
        self.reranker = reranker
        # Générateur
        self.generator = generator

    def query(self, question, initial_k=20, final_k=5):
        """
Traite la requête, incluant la récupération en deux étapes de "filtrage grossier + classement précis"

: :param question: question de l'utilisateur
: :param initial_k: Le nombre de candidats retournés par la première étape de la récupération vectorielle.
:param final_k: Le nombre d'éléments finalement conservés après reranking.
        """

        # ==================== Phase 1 : Récupération initiale (filtrage grossier) ====================
        Convertir le problème en vecteur.
        question_embedding = self.embedder.embed([question])[0]

        # Rappeler rapidement un lot de textes candidats à l'aide de la similarité vectorielle (rapide, précision moyenne)
        initial_results = self.vector_store.search(
            question_embedding,
            initial_k
        )

        # ==================== Phase 2 : Reclassement (Classement fin) ====================
        Construisez des paires (question, document candidat) et fournissez-les au cross-encoder pour les noter une par une.
        doc_pairs = [(question, doc) for doc, _ in initial_results]

        Les cross-encoders encodent simultanément la question et le document, ce qui permet de juger plus précisément leur pertinence.
        reranked = self.reranker.rerank(doc_pairs)

        # Prendre les final_k éléments véritablement les plus pertinents après le reclassement.
        final_context = "\n".join([doc for doc, _ in reranked[:final_k]])

        # ==================== Étape 3 : Génération =====================
        prompt = fContexte : {final_context}\n\nQuestion : {question}
        return self.generator.generate(prompt)

Récupération hybride

La récupération hybride combine les avantages de la récupération dense et de la récupération éparse.

La récupération dense est basée sur la similarité vectorielle et excelle à capturer la pertinence sémantique, en faisant correspondre les requêtes utilisateur et les documents même lorsqu’ils n’utilisent pas exactement les mêmes mots.

La récupération éparse (comme BM25) est basée sur des statistiques de fréquence des mots-clés, excelle dans la correspondance littérale exacte et est souvent plus fiable que la récupération vectorielle pour des scénarios tels que les noms propres, les nombres et les extraits de code.

Les deux ont des angles morts : la récupération vectorielle peut « comprendre le sens mais échouer à trouver les mots-clés exacts », tandis que la récupération par mots-clés peut « correspondre aux mots mais échouer à comprendre la sémantique ». La récupération hybride fusionne les résultats des deux chemins de récupération, en complétant mutuellement leurs forces et faiblesses.

RAG de récupération hybride

class HybridRAG:
    """
RAG de récupération hybride
Combinaison de la récupération dense (vectorielle) et de la récupération éparse (par mots-clés)
    """


    def __init__(self, dense_retriever, sparse_retriever, fusion_fn):
        # Récupérateur dense : basé sur la similarité vectorielle, excelle dans la correspondance sémantique.
        self.dense_retriever = dense_retriever
        # Récupérateur sparse : basé sur des statistiques de mots-clés (par ex. BM25), excelle dans la correspondance exacte.
        self.sparse_retriever = sparse_retriever
        # Fonction de fusion : utilisée pour fusionner les résultats de deux récupérations, par ex. RRF (voir l'implémentation ci-dessous)
        self.fusion_fn = fusion_fn

    def query(self, question, top_k):
        """
Effectuer une récupération hybride et renvoyer les résultats classés fusionnés.

: :param question: question de l'utilisateur
:param top_k: Le nombre final de résultats à renvoyer.
        """

        # ==================== Récupération dense =====================
        # Récupérer plus de candidats (top_k * 2) pour laisser de la place au filtrage lors de la fusion
        dense_results = self.dense_retriever.search(question, top_k * 2)

        # ==================== Récupération creuse ====================
        # Récupération par mots-clés, récupérer également plus de candidats
        sparse_results = self.sparse_retriever.search(question, top_k * 2)

        # ==================== Fusion des résultats ====================
        # Utiliser des stratégies comme Reciprocal Rank Fusion (RRF) pour fusionner les résultats de classement des deux canaux
        fused = self.fusion_fn(dense_results, sparse_results)

        # Prendre les top_k éléments avec le classement fusionné le plus élevé
        return fused[:top_k]


def reciprocal_rank_fusion(results_a, results_b, k=60):
    """
Algorithme de Reciprocal Rank Fusion (RRF)
Utilisé pour fusionner les résultats de classement de deux (ou plusieurs) canaux de récupération en un classement unifié

Idée principale : ne regarder que le "rang" de chaque document dans les résultats de chaque canal, et non le score spécifique,
Cela évite le problème que les scores de similarité vectorielle et les scores BM25 ont des échelles différentes et ne peuvent pas être directement comparés.

:param results_a: Résultats de récupération A, formatés sous la forme [(doc, score), ...]
:param results_b: Résultats de récupération B, formatés sous la forme [(doc, score), ...]
:param k: Constante de lissage, utilisée pour réduire la différence de poids pour les documents moins bien classés, généralement définie à 60
:return: Liste de [(doc, score), ...] triée par score fusionné du plus élevé au plus faible
    """

    scores = {}

    # Traiter les résultats A : plus le rang est élevé, plus le score apporté est élevé
    for rank, (doc, _) in enumerate(results_a):
        scores[doc] = scores.get(doc, 0) + 1 / (k + rank + 1)

    # Traiter les résultats B, accumuler de la même manière les scores par rang
    for rank, (doc, _) in enumerate(results_b):
        scores[doc] = scores.get(doc, 0) + 1 / (k + rank + 1)

    # Trier par le score fusionné cumulé, du plus élevé au plus faible
    sorted_docs = sorted(scores.items(), key=lambda x: -x[1])

    return sorted_docs

Autres stratégies d'optimisation

Expansion de requête: Développer la requête originale en ajoutant des synonymes ou des termes associés afin d'élargir la portée de rappel et d'améliorer le taux de rappel.

Réécriture de requête: Utiliser des modèles pour comprendre l'intention réelle de l'utilisateur, en reformulant des questions familières ou ambiguës en formulations plus adaptées à la récupération.

Compression de contexte: Avant de transmettre les résultats de récupération au modèle de génération, supprimer les parties redondantes et non pertinentes, en ne conservant que les informations clés. Cela réduit le coût et diminue également le risque que le modèle de génération soit perturbé par du contenu non pertinent.


Base de données vectorielle

Une base de données vectorielle est l'infrastructure du système RAG, chargée de stocker massivement des vecteurs de grande dimension et de prendre en charge la récupération par similarité à grande échelle et à faible latence.

Concepts fondamentaux

Plongement: Le processus de conversion de texte (ou d'images, d'audio, etc.) en un ensemble de vecteurs numériques denses, où un contenu sémantiquement similaire est plus proche dans l'espace vectoriel.

Dimension vectorielleLa longueur du vecteur de plongement. Plus la dimension est élevée, plus les informations sémantiques qu'il peut théoriquement exprimer sont riches, mais les coûts de stockage et de calcul augmenteront également en conséquence.

Mesure de similarité.: Une méthode de calcul spécifique utilisée pour mesurer la « similarité » ou la « distance » entre deux vecteurs. Différentes métriques conviennent à différents scénarios.

Métriques de similarité courantes

méthode de mesure formule Fonctionnalités Scénarios applicables
Similarité cosinus. cos(A,B) = A·B/(|A||B|) Mesure uniquement la similarité directionnelle, indépendamment de la longueur du vecteur, avec une plage de valeurs de [-1,1] Similarité document/texte
Distance euclidienne d(A,B) = sqrt(sum((Ai-Bi)^2)) Mesure la distance spatiale absolue entre vecteurs, avec une plage de valeurs de [0,+∞) Appariement de caractéristiques d'image
produit scalaire A·B = sum(Ai*Bi) Influencé à la fois par la direction et la longueur, avec une efficacité de calcul élevée système de recommandation

Comparaison des bases de données vectorielles les plus courantes

base de données Type Fonctionnalités Scénarios applicables
Pinecone service cloud Service entièrement géré, facile à démarrer, mise à l'échelle automatique, aucune opération manuelle requise Environnements de production qui doivent être mis en service rapidement
Weaviate Open source Prend nativement en charge la recherche hybride (vectorielle + mots-clés), hautement modulaire Scénarios nécessitant une personnalisation flexible de la logique de récupération
Milvus Open source Haute disponibilité, mise à l'échelle horizontale facile, peut prendre en charge des échelles vectorielles de plusieurs milliards et plus Recherche vectorielle à très grande échelle
Chroma Open source Léger, API simple, peut être opérationnel avec seulement quelques lignes de code Développement de prototypes, enseignement et tests locaux
Qdrant Open source Développé en Rust, excellentes performances, prend en charge des conditions de filtrage riches Scénarios nécessitant un débit élevé et un filtrage complexe

Exemples de code

Utilisation de la base de données vectorielle Chroma

import chroma_client
from chroma_client import ChromaClient

# Créer un client (peut se connecter à une instance locale ou à un service distant)
client = ChromaClient()

# Créer ou obtenir une collection, équivalent à une 'table' dans une base de données relationnelle
collection = client.get_or_create_collection("knowledge_base")

# Ajouter des documents : ID, vecteur, texte original et métadonnées doivent correspondre un à un
collection.add(
    ids=["doc1", "doc2", "doc3"],  # Identifiant unique pour chaque document
    embeddings=[
        [0.1, 0.2, 0.3],  # Vecteur correspondant au document 1 (la dimension réelle est généralement bien supérieure à 3 dimensions)
        [0.4, 0.5, 0.6],  # Vecteur correspondant au document 2
        [0.7, 0.8, 0.9],  # Vecteur correspondant au document 3
    ],
    documents=[
        L'intelligence artificielle est une branche de l'informatique.,
        "L'apprentissage automatique est un sous-domaine de l'intelligence artificielle",
        "L'apprentissage profond est un sous-domaine de l'apprentissage automatique"
    ],
    metadatas=[
        {"source": “textbook”},  # Informations sur la source du document 1, pouvant être utilisées pour un filtrage ultérieur
        {"source": Paper},
        {"source": Paper}
    ]
)

# Récupérer : passer le vecteur de requête, renvoyer les n_results résultats les plus similaires
results = collection.query(
    query_embeddings=[[0.15, 0.25, 0.35]],  # Vecteur correspondant à la requête
    n_results=2  # Renvoyer les 2 résultats les plus similaires
)

# Afficher les résultats de récupération
print(results["documents"])   # Contenu textuel original correspondant
print(results["distances"])   # Score de distance/similarité correspondant ; des valeurs plus petites indiquent généralement une similarité plus élevée

Lors du choix d'une base de données vectorielle, vous devez prendre en compte de manière globale l'échelle des données, les exigences de latence des requêtes, le mode de déploiement (hébergé dans le cloud ou auto-hébergé) et les capacités opérationnelles de l'équipe. Pour le développement de prototypes à petite échelle, privilégiez Chroma ; pour un environnement de production prêt à l'emploi, choisissez Pinecone ; pour les scénarios à très grande échelle nécessitant autonomie et contrôle, Milvus ou Qdrant sont plus adaptés.


GraphRAG

GraphRAG est une solution avancée qui combine un graphe de connaissances avec le RAG.

Il améliore les capacités de recherche et de raisonnement du système en construisant une structure de graphe composée d'entités et de relations.

Pourquoi GraphRAG est nécessaire

Le RAG traditionnel est basé sur la recherche par similarité sur des segments de texte, ce qui rend difficile le traitement des problèmes qui nécessitent un "raisonnement multi-hop" (c'est-à-dire des réponses qui nécessitent de connecter plusieurs informations).

Le RAG traditionnel a également du mal à capturer explicitement les relations sémantiques entre entités, telles que des informations structurées comme "qui est le supérieur de qui" ou "quelle entreprise a acquis quelle entreprise."

GraphRAG organise explicitement ces entités et relations dans une structure de graphe, permettant au système de raisonner le long de chemins de relations au lieu de simplement "trouver du texte similaire."

Avantages principaux

Peut capturer les relations sémantiques entre entités, formant un réseau de connaissances structuré plutôt que des fragments de texte dispersés.

Prend en charge le raisonnement basé sur les chemins et peut mieux répondre aux questions relationnelles.

Peut gérer des problèmes complexes nécessitant un raisonnement multi-sauts, tels que « qui est le conseiller du conseiller de quelqu'un », qui exigent de parcourir plusieurs nœuds de relation en séquence pour déduire la réponse.

Implémentation du code

Implémentation de GraphRAG

class GraphRAG:
    """
Système GraphRAG
Combine la récupération dans les graphes de connaissances et la récupération vectorielle, en équilibrant le raisonnement relationnel et la similarité sémantique.
    """


    def __init__(self, kg_builder, embedder, vector_store, generator):
        # Constructeur de graphe de connaissances : responsable de l'extraction d'entités/relations et des requêtes sur le graphe
        self.kg_builder = kg_builder
        # Embedder : utilisé pour convertir des documents et des questions en vecteurs
        self.embedder = embedder
        # Base de données vectorielle : sert de canal supplémentaire pour la récupération dans le graphe de connaissances
        self.vector_store = vector_store
        # Generator : génère la réponse finale à partir du contexte fusionné
        self.generator = generator

    def index_documents(self, documents):
        """
Indexer les documents à la fois dans le graphe de connaissances et dans la base de données vectorielle
:param documents: liste de documents
        """

        for doc in documents:
            # Extraire les entités des documents
            # Par exemple, extraire de "OpenAI a été fondée en 2015"
            # Entité : OpenAI (organisation), 2015 (temps)
            entities = self.kg_builder.extract_entities(doc)

            # Extraire les relations entre les entités à partir des documents
            # Par exemple, extraire un triplet de relation : (OpenAI, fondée en, 2015)
            relations = self.kg_builder.extract_relations(doc)

            # Écrire les entités et les relations dans le graphe de connaissances
            self.kg_builder.add_entities(entities)
            self.kg_builder.add_relations(relations)

            # Vectoriser simultanément le texte original et le stocker dans une base de données vectorielle pour compléter la recherche sémantique
            embedding = self.embedder.embed([doc])
            self.vector_store.add(embedding, [doc])

    def query(self, question):
        """
Gérer les requêtes : combiner le raisonnement sur le graphe de connaissances et la recherche vectorielle
        """

        # ==================== Récupération dans le graphe de connaissances ====================
        # Identifier d'abord les entités pertinentes mentionnées dans la question
        # Par exemple, "Qui a fondé OpenAI ?" -> identifier l'entité "OpenAI"
        relevant_entities = self.kg_builder.query_entities(question)

        # À partir de ces entités, extraire du graphe le sous-graphe directement lié à celles-ci
        # Le sous-graphe contient les entités pertinentes ainsi que leurs nœuds adjacents et les arêtes de connexion
        subgraph = self.kg_builder.get_subgraph(relevant_entities)

        # ==================== Récupération vectorielle ====================
        # En tant que canal complémentaire, récupérer du contenu textuel sémantiquement similaire
        vector_results = self.vector_store.search(question, top_k=5)

        # ==================== Fusion des résultats ====================
        # Fusionner les résultats du raisonnement sur graphe et de la récupération vectorielle dans un contexte unifié
        combined_context = self.fuse_results(subgraph, vector_results)

        # ==================== Génération ====================
        return self.generator.generate(combined_context, question)

    def fuse_results(self, subgraph, vector_results):
        """
Fusionner le sous-graphe du graphe de connaissances et les résultats de récupération vectorielle en un texte de contexte lisible par un modèle génératif
        """

        # Convertir le sous-graphe en descriptions en langage naturel (par ex., "OpenAI -fondé en-> 2015")
        kg_text = subgraph.to_text()

        # Concaténer les segments de texte originaux récupérés par la recherche vectorielle
        vector_text = "\n".join([doc for doc, _ in vector_results])

        return f"{kg_text}\n{vector_text}"


class KnowledgeGraphBuilder:
    """Constructeur de graphe de connaissances (implémentation illustrative ; dans les projets réels, des modèles dédiés d'extraction NER/relations sont généralement appelés)"""

    def extract_entities(self, text):
        """
# Extraire les entités nommées du texte, généralement effectué avec des modèles NER (Named Entity Recognition)
# Les types d'entités courants incluent PERSON (personne), ORG (organisation), TIME (temps), etc.
        """

        entities = []
        return entities

    def extract_relations(self, text):
        """
# Extraire les relations entre entités à partir du texte, généralement à l'aide de modèles d'extraction de relations
# Les relations sont généralement représentées sous forme de triplets : (entité de tête, type de relation, entité de queue)
        """

        relations = []
        return relations

    def query_entities(self, question):
        """D'après la question de l'utilisateur, identifier les entités impliquées dans la question pour la récupération ultérieure du sous-graphe"""
        return []

Scénarios d'application

GraphRAG est particulièrement adapté aux scénarios suivants :

Questions-réponses nécessitant la compréhension des relations entre entités, par ex. : "Qui est le PDG de cette entreprise ?"

Questions nécessitant un raisonnement multi-sauts pour parvenir à une réponse, par ex. : "Qui est le conseiller du conseiller de Zhang San ?"

Scénarios nécessitant l'extraction de relations implicites dans la base de connaissances qui ne sont pas explicitement écrites.

Il convient de noter que la construction et la maintenance d'un graphe de connaissances entraînent en elles-mêmes certains coûts d'ingénierie (précision de l'extraction d'entités/relations, mise à jour et maintenance du graphe, etc.), de sorte qu'il est plus adapté aux scénarios présentant des exigences claires en matière de raisonnement relationnel, et n'est pas recommandé comme point de départ par défaut pour tous les projets RAG.


Comparaison des solutions et recommandations

Solution Approche principale Avantages Limites Scénarios applicables
RAG de base Récupération vectorielle + génération directe Simple à implémenter, faible coût, démarrage rapide Précision de récupération limitée, tendance à récupérer du contenu pas assez pertinent Questions-réponses simples, validation rapide de prototype
RAG avancé (reranking) Filtrage grossier vectoriel + classement fin par cross-encoder Améliore significativement la précision du classement de récupération Ajoute une passe d'inférence de modèle supplémentaire, augmentant la latence et le coût Scénarios avec des exigences élevées en matière de précision des réponses
Récupération hybride Fusion de la récupération vectorielle et de la récupération par mots-clés Équilibre la correspondance sémantique et la correspondance précise par mots-clés Nécessite de maintenir simultanément deux index de récupération Bases de connaissances comportant de nombreux noms propres, code et identifiants
GraphRAG Fusion graphe de connaissances + récupération vectorielle Prend en charge le raisonnement relationnel et les questions-réponses multi-sauts Coûts élevés de construction et de maintenance du graphe Scénarios avec des exigences claires en matière de raisonnement relationnel et multi-sauts

Résumé du chapitre

Ce chapitre présente les technologies fondamentales de RAG et de la récupération de connaissances.

Principes de base de RAG: En combinant récupération et génération, il permet aux agents de répondre à des questions en utilisant des connaissances externes plutôt que de s'appuyer entièrement sur la mémoire dans les paramètres du modèle.

RAG avancé: Grâce à des techniques telles que le reclassement et la récupération hybride, il améliore encore la qualité de la récupération et la précision des réponses par rapport au pipeline de base.

Base de données vectorielle: Elle constitue l'infrastructure des systèmes RAG, chargée de stocker et de récupérer efficacement les représentations vectorielles des documents ; le choix de la solution doit être fait en fonction de l'échelle des données et du mode de déploiement.

GraphRAG: Combiné aux graphes de connaissances, il améliore le raisonnement relationnel et les capacités de questions-réponses multi-sauts, mais apporte aussi des coûts supplémentaires de construction et de maintenance.

La clé pour choisir une solution RAG appropriée est de d'abord comprendre les besoins réels du scénario métier : pour des scénarios de questions-réponses simples, le RAG de base suffit souvent ; lorsqu'une précision de récupération plus élevée est requise, le reranking peut être introduit ; lorsque la base de connaissances contient de nombreux noms propres/mots-clés, la recherche hybride est adaptée ; lorsqu'une grande quantité de raisonnement relationnel et de questions-réponses multi-sauts est impliquée, envisagez d'introduire GraphRAG. Plus la technologie est complexe, plus les coûts d'ingénierie et de maintenance sont élevés, il est donc plus important de choisir en fonction des besoins réels que de poursuivre aveuglément « des solutions plus avancées ».

Autres extensions