Techniques avancées de RAG partie 1 : Traitement des données
Discuter et mettre en œuvre des techniques susceptibles d'améliorer les performances du RAG. Partie 1 sur 2, se concentrant sur le traitement et l'ingestion des données d'un pipeline RAG avancé.
Voici la première partie de notre exploration des techniques avancées de RAG. Cliquez ici pour la deuxième partie !
L'article récent intitulé Searching for Best Practices in Retrieval-Augmented Generation évalue de manière empirique l'efficacité de diverses techniques d'amélioration des RAG, dans le but de converger vers un ensemble de meilleures pratiques pour les RAG.

Le pipeline RAG recommandé par Wang et ses collègues.
Nous mettrons en œuvre quelques-unes des meilleures pratiques proposées, notamment celles qui visent à améliorer la qualité de la recherche (Sentence Chunking, HyDE, Reverse Packing).
Par souci de concision, nous omettons les techniques axées sur l'amélioration de l'efficacité (classification des requêtes et résumé).
Nous mettrons également en œuvre quelques techniques qui n'ont pas été abordées, mais que je trouve personnellement utiles et intéressantes (Metadata Inclusion, Composite Multi-Field Embeddings, Query Enrichment).
Enfin, nous effectuerons un petit test pour voir si la qualité de nos résultats de recherche et des réponses générées s'est améliorée par rapport à la base de référence. C'est parti !
Vue d'ensemble du RAG
RAG vise à améliorer les LLM en récupérant des informations dans des bases de connaissances externes afin d'enrichir les réponses générées. En fournissant des informations spécifiques au domaine, les LLM peuvent être rapidement adaptés à des cas d'utilisation qui sortent du cadre de leurs données de formation ; cela coûte beaucoup moins cher qu'un réglage fin et il est plus facile de les tenir à jour.
Les mesures visant à améliorer la qualité du RAG se concentrent généralement sur deux axes :
Améliorer la qualité et la clarté de la base de connaissances.
Améliorer la couverture et la spécificité des requêtes de recherche.
Ces deux mesures permettront d'améliorer les chances que le LLM ait accès à des faits et des informations pertinents, et qu'il soit donc moins susceptible d'halluciner ou de s'appuyer sur ses propres connaissances - qui peuvent être dépassées ou non pertinentes.
La diversité des méthodes est difficile à expliquer en quelques phrases. Pour plus de clarté, passons directement à la mise en œuvre.

Figure 1 : Le pipeline RAG utilisé par l'auteur.
Table des matières
Mise en place
Tout le code peut être trouvé dans le repo de Searchlabs.
Commençons par le commencement. Vous aurez besoin des éléments suivants :
Déploiement d'un nuage élastique
Une API LLM - Nous utilisons un déploiement GPT-4o sur Azure OpenAI dans ce carnet.
Python version 3.12.4 ou ultérieure
Nous allons exécuter tout le code du cahier main.ipynb.
Allez-y et clonez git le repo, naviguez vers supporting-blog-content/advanced-rag-techniques, puis exécutez les commandes suivantes :
# Create a new virtual environment named 'rag_env'
python -m venv rag_env
# Activate the virtual environment (for Unix-based systems)
source rag_env/bin/activate
# (For Windows)
.\rag_env\Scripts\activate
# Install packages listed in requirements.txt
pip install -r requirements.txtUne fois que c'est fait, créez un fichier .env et remplissez les champs suivants (référencés dans l'exemple .env). Remerciements à mon co-auteur, Claude-3.5, pour ses commentaires utiles.
# Elastic Cloud: Found in the 'Deployment' page of your Elastic Cloud
# console
ELASTIC_CLOUD_ENDPOINT=""
ELASTIC_CLOUD_ID=""
# Elastic Cloud: Created during deployment setup or in 'Security'
# settings
ELASTIC_USERNAME=""
ELASTIC_PASSWORD=""
# Elastic Cloud: The name of the index you created in Kibana or via API
ELASTIC_INDEX_NAME=""
# Azure AI Studio: Found in 'Keys and Endpoint' section of your Azure
# OpenAI resource
AZURE_OPENAI_KEY_1=""
AZURE_OPENAI_KEY_2=""
AZURE_OPENAI_REGION=""
AZURE_OPENAI_ENDPOINT=""
# Azure AI Studio: Found in 'Deployments' section of your Azure OpenAI
# resource
AZURE_OPENAI_DEPLOYMENT_NAME=""
# Using BAAI/bge-small-en-v1.5 because I think it is a good balance of
# resource efficiency and performance.
HUGGINGFACE_EMBEDDING_MODEL="BAAI/bge-small-en-v1.5"Ensuite, nous allons choisir le document à ingérer et le placer dans le dossier documents. Pour cet article, nous utiliserons le rapport annuel 2023 d'Elastic N.V. Il s'agit d'un document assez difficile et dense, parfait pour tester nos techniques RAG.

Rapport annuel d'Elastic 2023
Maintenant que tout est prêt, passons à l'ingestion. Ouvrez main.ipynb et exécutez les deux premières cellules pour importer tous les paquets et initialiser tous les services.
Acquisition, traitement et intégration de documents
Ingestion des données
Note personnelle : je suis stupéfait par la commodité de LlamaIndex. Avant les LLM et LlamaIndex, l'ingestion de documents de différents formats était un processus pénible de collecte de paquets ésotériques provenant d'un peu partout. Aujourd'hui, il se réduit à un seul appel de fonction. Sauvage.
La commande SimpleDirectoryReader chargera chaque document contenu dans les fichiers directory_path. et .pdf. Elle renvoie une liste d'objets document, que je convertis en dictionnaires Python parce que je trouve qu'ils sont plus faciles à manipuler.
# llamaindex_processor.py
from llama_index.core import SimpleDirectoryReader
class LlamaIndexProcessor:
def __init__(self):
pass
def load_documents(self, directory_path):
'''
Load all documents in directory
'''
reader = SimpleDirectoryReader(input_dir=directory_path)
return reader.load_data()
# main.ipynb
llamaindex_processor=LlamaIndexProcessor()
documents=llamaindex_processor.load_documents('./documents/')
documents=[dict(doc_obj) for doc_obj in documents]Chaque dictionnaire contient le contenu clé du champ text. Il contient également des métadonnées utiles telles que le numéro de page, le nom du fichier, sa taille et son type.
{
'id_': '5f76f0b3-22d8-49a8-9942-c2bbab14f63f',
'metadata': {'page_label': '5',
'file_name': 'Elastic_NV_Annual-Report-Fiscal-Year-2023.pdf',
'file_path': '/Users/han/Desktop/Projects/truckasaurus/documents/Elastic_NV_Annual-Report-Fiscal-Year-2023.pdf',
'file_type': 'application/pdf',
'file_size': 3724426,
'creation_date': '2024-07-27',
'last_modified_date': '2024-07-27'},
'text': 'Table of Contents\nPage\nPART I\nItem 1. Business 3\n15 Item 1A. Risk Factors\nItem 1B. Unresolved Staff Comments 48\nItem 2. Properties 48\nItem 3. Legal Proceedings 48\nItem 4. Mine Safety Disclosures 48\nPART II\nItem 5. Market for Registrant's Common Equity, Related Stockholder Matters and Issuer Purchases of \nEquity Securities49\nItem 6. [Reserved] 49\nItem 7. Management's Discussion and Analysis of Financial Condition and Results of Operations 50\nItem 7A. Quantitative and Qualitative Disclosures About Market Risk 64\nItem 8. Financial Statements and Supplementary Data 66\nItem 9. Changes in and Disagreements With Accountants on Accounting and Financial Disclosure 100\n100\n101Item 9A. Controls and Procedures\nItem 9B. Other Information\nItem 9C. Disclosure Regarding Foreign Jurisdictions That Prevent Inspections 101\nPART III\n102\n102\n102\n102Item 10. Directors, Executive Officers and Corporate Governance\nItem 11. Executive Compensation\nItem 12. Security Ownership of Certain Beneficial Owners and Management, and Related Stockholder Matters \nItem 13. Certain Relationships and Related Transactions, and Director Independence\nItem 14. Principal Accountant Fees and Services 102\nPART IV\n103\n105Item 15. Exhibits and Financial Statement Schedules \nItem 16. Form 10-K Summary\nSignatures 106\ni',
...
}Chunking au niveau de la phrase, par jetons
La première chose à faire est de réduire nos documents en morceaux d'une longueur standard (pour assurer la cohérence et la maniabilité). Les modèles d'intégration ont des limites de jetons uniques (taille d'entrée maximale qu'ils peuvent traiter). Les jetons sont les unités de base du texte que les modèles traitent. Pour éviter la perte d'informations (tronquage ou omission de contenu), nous devrions fournir un texte qui ne dépasse pas ces limites (en divisant les textes plus longs en segments plus petits).
Le découpage a un impact significatif sur les performances. Idéalement, chaque morceau devrait représenter un élément d'information autonome, capturant des informations contextuelles sur un seul sujet. Les méthodes de découpage comprennent le découpage au niveau des mots, où les documents sont divisés en fonction du nombre de mots, et le découpage sémantique qui utilise un LLM pour identifier les points de rupture logiques.
Le découpage au niveau des mots est bon marché, rapide et facile, mais il risque de diviser les phrases et donc de briser le contexte. Le découpage sémantique devient lent et coûteux, surtout s'il s'agit de documents tels que le rapport annuel Elastic de 116 pages.
Choisissons une approche intermédiaire. Le découpage en phrases est encore simple, mais il permet de préserver le contexte plus efficacement que le découpage en mots, tout en étant nettement moins coûteux et plus rapide. En outre, nous mettrons en œuvre une fenêtre coulissante pour capturer une partie du contexte environnant et atténuer l'impact du découpage des paragraphes.
# chunker.py
import uuid
import re
class Chunker:
def __init__(self, tokenizer):
self.tokenizer = tokenizer
def split_into_sentences(self, text):
"""Split text into sentences."""
return re.split(r'(?<=[.!?])\s+', text)
def sentence_wise_tokenized_chunk_documents(self, documents, chunk_size=512, overlap=20, min_chunk_size=50):
'''
1. Split text into sentences.
2. Tokenize using the provided tokenizer method.
3. Build chunks up to the chunk_size limit.
4. Create an overlap based on tokens - to preserve context.
5. Only keep chunks that meet the minimum token size requirement.
'''
chunked_documents = []
for doc in documents:
sentences = self.split_into_sentences(doc['text'])
tokens = []
sentence_boundaries = [0]
# Tokenize all sentences and keep track of sentence boundaries
for sentence in sentences:
sentence_tokens = self.tokenizer.encode(sentence, add_special_tokens=True)
tokens.extend(sentence_tokens)
sentence_boundaries.append(len(tokens))
# Create chunks
chunk_start = 0
while chunk_start < len(tokens):
chunk_end = chunk_start + chunk_size
# Find the last complete sentence that fits in the chunk
sentence_end = next((i for i in sentence_boundaries if i > chunk_end), len(tokens))
chunk_end = min(chunk_end, sentence_end)
# Create the chunk
chunk_tokens = tokens[chunk_start:chunk_end]
# Check if the chunk meets the minimum size requirement
if len(chunk_tokens) >= min_chunk_size:
# Create a new document object for this chunk
chunk_doc = {
'id_': str(uuid.uuid4()),
'chunk': chunk_tokens,
'original_text': self.tokenizer.decode(chunk_tokens),
'chunk_index': len(chunked_documents),
'parent_id': doc['id_'],
'chunk_token_count': len(chunk_tokens)
}
# Copy all other fields from the original document
for key, value in doc.items():
if key != 'text' and key not in chunk_doc:
chunk_doc[key] = value
chunked_documents.append(chunk_doc)
# Move to the next chunk start, considering overlap
chunk_start = max(chunk_start + chunk_size - overlap, chunk_end - overlap)
return chunked_documents
# main.ipynb
# Initialize Embedding Model
HUGGINGFACE_EMBEDDING_MODEL = os.environ.get('HUGGINGFACE_EMBEDDING_MODEL')
embedder=EmbeddingModel(model_name=HUGGINGFACE_EMBEDDING_MODEL)
# Initialize Chunker
chunker=Chunker(embedder.tokenizer)La classe Chunker utilise le tokenizer du modèle d'intégration pour encoder et décoder le texte. Nous allons maintenant construire des blocs de 512 jetons chacun, avec un chevauchement de 20 jetons. Pour ce faire, nous divisons le texte en phrases, nous tokenisons ces phrases, puis nous ajoutons les phrases tokenisées à notre morceau actuel jusqu'à ce que nous ne puissions plus en ajouter sans dépasser notre limite de tokens.
Enfin, nous décodons les phrases pour les ramener au texte d'origine afin de les intégrer, en les stockant dans un champ appelé original_text. Les morceaux sont stockés dans un champ appelé chunk. Pour réduire le bruit (c'est-à-dire les documents inutiles), nous éliminons tous les documents dont la longueur est inférieure à 50 tokens.
Passons-le en revue nos documents :
chunked_documents=chunker.sentence_wise_tokenized_chunk_documents(documents, chunk_size=512)Et vous obtenez des morceaux de texte qui ressemblent à ceci :
print(chunked_documents[4]['original_text'])
[CLS] the aggregate market value of the ordinary shares held by non - affiliates of the registrant,
based on the closing price of the shares of ordinary shares on the new york stock exchange on
october 31, 2022 ( the last business day of the registrant 's second fiscal quarter ), was
approximately $ 6. 1 billion. [SEP] [CLS] as of may 31, 2023, the registrant had 97, 390, 886
ordinary shares, par value €0. 01 per share, outstanding. [SEP] [CLS] documents incorporated by
reference portions of the registrant 's definitive proxy statement relating to the registrant 's 2
023 annual general meeting of shareholders are incorporated by reference into part iii of this annual
...
...Inclusion et génération de métadonnées
Nous avons découpé nos documents en morceaux. Il est maintenant temps d'enrichir les données. Je souhaite générer ou extraire des métadonnées supplémentaires. Ces métadonnées supplémentaires peuvent être utilisées pour influencer et améliorer les performances de recherche.
Nous allons définir une classe DocumentEnricher, dont le rôle est de recevoir une liste de documents (dictionnaires Python) et une liste de fonctions du processeur. Ces fonctions s'exécutent sur la colonne original_text des documents et stockent leurs résultats dans de nouveaux champs.
Tout d'abord, nous extrayons les phrases clés à l'aide de TextRank. TextRank est un algorithme basé sur un graphe qui permet d'extraire des phrases et des expressions clés d'un texte en classant leur importance sur la base des relations entre les mots.
Ensuite, nous allons générer des questions potentielles à l'aide de GPT-4o.
Enfin, nous extrairons les entités à l'aide de Spacy.
Le code de chacun d'entre eux étant assez long et complexe, je m'abstiendrai de le reproduire ici. Si vous êtes intéressé, les fichiers sont indiqués dans les exemples de code ci-dessous.
Lançons l'enrichissement des données :
# documentenricher.py
from tqdm import tqdm
class DocumentEnricher:
def __init__(self):
pass
def enrich_document(self, documents, processors, text_col='text'):
for doc in tqdm(documents, desc="Enriching documents using processors: "+str(processors)):
for (processor, field) in processors:
metadata=processor(doc[text_col])
if isinstance(metadata, list):
metadata='\n'.join(metadata)
doc.update({field: metadata})
# main.ipynb
# Initialize processor classes
nltkprocessor=NLTKProcessor() // nltk_processor.py
entity_extractor=EntityExtractor() // entity_extractor.py
gpt4o = LLMProcessor(model='gpt-4o') // llm.py
# Initialize LLM
documentenricher=DocumentEnricher()
# Create new fields in the documents - These are the outputs of the processor functions.
processors=[
(nltkprocessor.textrank_phrases, "keyphrases"),
(gpt4o.generate_questions, "potential_questions"),
(entity_extractor.extract_entities, "entities")
]
# .enrich_document() will modify chunked_docs in place.
# To view the results, we'll print chunked_docs in the next few cells!
documentenricher.enrich_document(chunked_docs, text_col='original_text', processors=processors)Et regardez les résultats :
Phrases clés extraites par TextRank
Ces phrases clés sont des substituts des thèmes centraux de la rubrique. Si une requête a trait à la cybersécurité, le score de ce morceau sera augmenté.
print(chunked_documents[25]['keyphrases'])
'elastic agent stop', 'agent stop malware',
'stop malware ransomware', 'malware ransomware environment',
'ransomware environment wide', 'environment wide visibility',
'wide visibility threat', 'visibility threat detection',
'sep cl key', 'cl key feature'Questions potentielles générées par le GPT-4o
Ces questions potentielles peuvent correspondre directement aux requêtes des utilisateurs, ce qui permet d'améliorer le score. Nous demandons à GPT-4o de générer des questions auxquelles il est possible de répondre en utilisant les informations trouvées dans le morceau actuel.
print(chunked_documents[25]['potential_questions'])
1. What are the primary functions that Elastic Agent provides in terms of cybersecurity?
2. Describe how Logstash contributes to data management within an IT environment.
3. List and explain any key features of Logstash mentioned in the document.
4. How does Elastic Agent enhance environment-wide visibility in threat detection?
5. What capabilities does Logstash offer for handling data beyond simple collection?
6. In what ways does the document suggest that Elastic Agent stops malware and ransomware?
7. Can you identify any relationships between the functionalities of Elastic Agent and Logstash in an integrated environment?
8. What implications might the advanced threat detection capabilities of Elastic Agent have for organizational security policies?
9. Compare and contrast the roles of Elastic Agent and Logstash based on their described functions.
10. How might the centralized collection ability of Logstash support the threat detection capabilities of Elastic Agent?Entités extraites par Spacy
Ces entités ont un objectif similaire à celui des phrases clés, mais elles capturent les noms des organisations et des individus, ce que l'extraction des phrases clés peut ne pas faire.
print(chunked_documents[29]['entities'])
'appdynamics', 'apm data', 'azure sentinel',
'microsoft', 'mcafee', 'broadcom', 'cisco',
'dynatrace', 'coveo', 'lucidworks'Enchâssement composite de champs multiples
Maintenant que nous avons enrichi nos documents avec des métadonnées supplémentaires, nous pouvons exploiter ces informations pour créer des encastrements plus robustes et tenant compte du contexte.
Faisons le point sur l'état actuel du processus. Nous avons quatre champs d'intérêt dans chaque document.
{
"chunk": "...",
"keyphrases": "...",
"potential_questions": "...",
"entities": "..."
}Chaque champ représente une perspective différente sur le contexte du document, mettant potentiellement en évidence un domaine clé sur lequel le LLM devrait se concentrer.

Pipeline d'enrichissement des métadonnées
Il s'agit d'intégrer chacun de ces champs, puis de créer une somme pondérée des intégrations, appelée intégration composite.
Avec un peu de chance, cette intégration composite permettra au système de mieux tenir compte du contexte, tout en introduisant un autre hyperparamètre réglable pour contrôler le comportement de recherche.
Tout d'abord, intégrons chaque champ et mettons à jour chaque document en place, en utilisant notre modèle d'intégration défini localement et importé au début du bloc-notes main.ipynb.
# EmbeddingModel defined in embedding_model.py
embedder=EmbeddingModel(model_name=HUGGINGFACE_EMBEDDING_MODEL)
cols_to_embed=['keyphrases', 'potential_questions', 'entities']
embedding_cols=[]
for col in cols_to_embed:
# Works on text input
embedding_col=embedder.embed_documents_text_wise(chunked_documents, text_field=col)
embedding_cols.append(embedding_col)
# Works on token input
embedding_col=embedder.embed_documents_token_wise(chunked_documents, token_field="chunk")
embedding_cols.append(embedding_col)Chaque fonction d'intégration renvoie le champ de l'intégration, qui est simplement le champ d'entrée original avec un postfixe _embedding.
Définissons maintenant les pondérations de notre encastrement composite :
embedding_cols=[
'keyphrases_embedding',
'potential_questions_embedding',
'entities_embedding',
'chunk_embedding']
combination_weights=[
0.1,
0.15,
0.05,
0.7
]Les pondérations vous permettent d'attribuer des priorités à chaque composant, en fonction de votre cas d'utilisation et de la qualité de vos données. Intuitivement, la taille de ces pondérations dépend de la valeur sémantique de chaque composant. Étant donné que le morceau de texte lui-même est de loin le plus riche, je lui attribue une pondération de 70%. Les entités étant les plus petites, puisqu'il s'agit simplement d'une liste de noms d'organisations ou de personnes, je leur attribue une pondération de 5%. Le réglage précis de ces valeurs doit être déterminé de manière empirique, au cas par cas.
Enfin, écrivons une fonction pour appliquer les pondérations et créer notre intégration composite. Pour gagner de la place, nous supprimerons également tous les composants intégrés.
from tqdm import tqdm
def combine_embeddings(objects, embedding_cols, combination_weights, primary_embedding='primary_embedding'):
# Ensure the number of weights matches the number of embedding columns
assert len(embedding_cols) == len(combination_weights), "Number of embedding columns must match number of weights"
# Normalize weights to sum to 1
weights = np.array(combination_weights) / np.sum(combination_weights)
for obj in tqdm(objects, desc="Combining embeddings"):
# Initialize the combined embedding
combined = np.zeros_like(obj[embedding_cols[0]])
# Compute the weighted sum
for col, weight in zip(embedding_cols, weights):
combined += weight * np.array(obj[col])
# Add the new combined embedding to the object
obj.update({primary_embedding:combined.tolist()})
# Remove the original embedding columns
for col in embedding_cols:
obj.pop(col, None)
combine_embeddings(chunked_documents, embedding_cols, combination_weights)Nous avons ainsi terminé le traitement des documents. Nous disposons à présent d'une liste d'objets documents qui se présente comme suit :
{ 'id_': '7fe71686-5cd0-4831-9e79-998c6dbeae0c', 'chunk': [2312, 14613, ...], 'original_text': 'if an emerging growth company, indicate by check mark if the registrant has elected not to use the extended ...', 'chunk_index': 3, 'chunk_token_count': 399, 'metadata': {'page_label': '3', 'file_name': 'Elastic_NV_Annual-Report-Fiscal-Year-2023.pdf', ... 'keyphrases': 'sep cl unk\ncheck mark registrant\ncl unk indicate\nunk indicate check\nindicate check mark\nprincipal executive office\naccelerate filer unk\ncompany unk emerge\nunk emerge growth\nemerge growth company', 'potential_questions': '1. What are the different types of registrant statuses mentioned in the document?\n2. Under what section of the Sarbanes-Oxley Act must registrants file a report on the effectiveness of their internal ...', 'entities': 'the effe ctiveness of\nsection 13\nSEP\nUNK\nsection 21e\n1934\n1933\nu. s. c.\nsection 404\nsection 12\nal', 'primary_embedding': [-0.3946287803351879, -0.17586839850991964, ...] }Indexation vers Elastic
Chargeons nos documents en vrac dans Elastic Search. À cette fin, j'ai défini il y a longtemps un ensemble de fonctions Elastic Helper dans elastic_helpers.py. Il s'agit d'un code très long, nous allons donc nous contenter d'examiner les appels de fonction.
es_bulk_indexer.bulk_upload_documents fonctionne avec n'importe quelle liste d'objets dictionnaires, en tirant parti des mappages dynamiques pratiques d'Elasticsearch.
# Initialize Elasticsearch
ELASTIC_CLOUD_ID = os.environ.get('ELASTIC_CLOUD_ID')
ELASTIC_USERNAME = os.environ.get('ELASTIC_USERNAME')
ELASTIC_PASSWORD = os.environ.get('ELASTIC_PASSWORD')
ELASTIC_CLOUD_AUTH = (ELASTIC_USERNAME, ELASTIC_PASSWORD)
es_bulk_indexer = ESBulkIndexer(cloud_id=ELASTIC_CLOUD_ID, credentials=ELASTIC_CLOUD_AUTH)
es_query_maker = ESQueryMaker(cloud_id=ELASTIC_CLOUD_ID, credentials=ELASTIC_CLOUD_AUTH)
# Define Index Name
index_name=os.environ.get('ELASTIC_INDEX_NAME')
# Create index and bulk upload
index_exists = es_bulk_indexer.check_index_existence(index_name=index_name)
if not index_exists:
logger.info(f"Creating new index: {index_name}")
es_bulk_indexer.create_es_index(es_configuration=BASIC_CONFIG, index_name=index_name)
success_count = es_bulk_indexer.bulk_upload_documents(
index_name=index_name,
documents=chunked_documents,
id_col='id_',
batch_size=32
)Rendez-vous sur Kibana et vérifiez que tous les documents ont été indexés. Il devrait y en avoir 224. Pas mal pour un document aussi volumineux !

Documents du rapport annuel indexés dans Kibana
Pause-catalogues
Faisons une pause, l'article est un peu lourd, je sais. Jetez un coup d'œil à mon chat :

Regardez comme elle est furieuse
Adorable. Le chapeau a disparu et je soupçonne à moitié qu'elle l'a volé et caché quelque part :(
Félicitations pour avoir réussi à aller aussi loin :)
Rejoignez-moi dans la deuxième partie pour tester et évaluer notre pipeline RAG !
Annexe
Définitions
1. Découpage des phrases
Technique de prétraitement utilisée dans les systèmes RAG pour diviser le texte en unités plus petites et significatives.
Processus :
Entrée : Grand bloc de texte (par exemple, document, paragraphe)
Sortie : Segments de texte plus petits (généralement des phrases ou des petits groupes de phrases)
Objet :
Création de segments de texte granulaires et spécifiques au contexte
Permet une indexation et une recherche plus précises
Améliore la pertinence des informations recherchées dans les systèmes RAG
Caractéristiques :
Les segments sont sémantiquement significatifs
Peuvent être indexés et récupérés de manière indépendante
Souvent, le contexte est préservé afin de garantir la compréhensibilité autonome.
Avantages :
Améliore la précision de la recherche
Permet une augmentation plus ciblée des pipelines RAG
2. HyDE (Hypothetical Document Embedding)
Une technique qui utilise un LLM pour générer un document hypothétique pour l'expansion des requêtes dans les systèmes RAG.
Processus :
Requête d'entrée à un LLM
LLM génère un document hypothétique répondant à la requête
Intégrer le document généré
Utiliser l'intégration pour la recherche vectorielle
Différence essentielle :
RAG traditionnel : Correspondance entre la requête et les documents
HyDE : fait correspondre des documents à d'autres documents
Objet :
Améliorer les performances de recherche, en particulier pour les requêtes complexes ou ambiguës
Saisir un contexte sémantique plus riche qu'une requête courte
Avantages :
Exploite les connaissances du LLM pour élargir les requêtes
Peut potentiellement améliorer la pertinence des documents retrouvés
Défis :
Nécessite une inférence LLM supplémentaire, ce qui augmente le temps de latence et le coût.
La performance dépend de la qualité du document hypothétique généré
3. Emballage inversé
Technique utilisée dans les systèmes RAG pour réorganiser les résultats de la recherche avant de les transmettre au LLM.
Processus :
Le moteur de recherche (par exemple, Elasticsearch) renvoie les documents par ordre décroissant de pertinence.
L'ordre est inversé, le document le plus pertinent étant placé en dernier.
Objet :
Exploite le biais de récence des LLM, qui ont tendance à se concentrer sur les informations les plus récentes dans leur contexte.
Veille à ce que les informations les plus pertinentes soient "les plus récentes" dans la fenêtre contextuelle du LLM.
Exemple : Ordre original : [Plus pertinent, Deuxième plus important, Troisième plus important, ...] Ordre inversé : [..., Troisième plus important, Deuxième plus important, Plus important]
4. Classification des requêtes
Technique permettant d'optimiser l'efficacité du système RAG en déterminant si une requête nécessite un RAG ou si elle peut être traitée directement par le LLM.
Processus :
Développer un ensemble de données personnalisé spécifique au programme d'éducation et de formation tout au long de la vie utilisé
Former un modèle de classification spécialisé
Utiliser le modèle pour catégoriser les requêtes entrantes
Objet :
Améliorer l'efficacité du système en évitant le traitement inutile des RAG
Diriger les demandes vers le mécanisme de réponse le plus approprié
Exigences :
Ensemble de données et modèle spécifiques au LLM
Amélioration continue pour maintenir la précision
Avantages :
Réduction de la charge de calcul pour les requêtes simples
Amélioration potentielle du temps de réponse pour les requêtes non RAG
5. Résumé
Une technique pour condenser les documents récupérés dans les systèmes RAG.
Processus :
Récupérer les documents pertinents
Générer des résumés concis de chaque document
Utiliser des résumés plutôt que des documents complets dans le pipeline RAG
Objet :
Améliorer la performance du RAG en se concentrant sur les informations essentielles
Réduire le bruit et les interférences provenant de contenus moins pertinents
Avantages :
Amélioration potentielle de la pertinence des réponses au programme d'éducation et de formation tout au long de la vie
Permet d'inclure un plus grand nombre de documents dans les limites du contexte
Défis :
Risque de perdre des détails importants dans le résumé
Frais de calcul supplémentaires pour la génération du résumé
6. Inclusion de métadonnées
Une technique pour enrichir les documents avec des informations contextuelles supplémentaires.
Types de métadonnées :
Mots clés
Titres
Dates
Coordonnées de l'auteur
Les commentaires
Objet :
Augmenter les informations contextuelles disponibles pour le système RAG
Fournir aux gestionnaires du droit d'auteur une meilleure compréhension du contenu et de la pertinence des documents
Avantages :
Amélioration potentielle de la précision de la recherche
Améliore la capacité du LLM à évaluer l'utilité des documents
Mise en œuvre :
Peut être effectué lors du prétraitement des documents
Peut nécessiter des étapes supplémentaires d'extraction ou de génération de données
7. Intégrations composites multi-champs
Une technique d'intégration avancée pour les systèmes RAG qui crée des intégrations distinctes pour les différents composants du document.
Processus :
Identifier les champs pertinents (par exemple, le titre, les phrases clés, le résumé, le contenu principal)
Générer des embeddings distincts pour chaque champ
Combiner ou stocker ces encastrements pour les utiliser lors de la recherche.
Différence par rapport à l'approche standard :
Traditionnel : Intégration unique pour l'ensemble du document
Composite : Plusieurs encastrements pour différents aspects du document
Objet :
Créer des représentations de documents plus nuancées et tenant compte du contexte
Saisir des informations provenant d'une plus grande variété de sources dans un document
Avantages :
Amélioration potentielle des performances sur les requêtes ambiguës ou à multiples facettes
Permet une pondération plus souple des différents aspects du document dans la recherche.
Défis :
Complexité accrue de l'intégration des processus de stockage et d'extraction
Peut nécessiter des algorithmes d'appariement plus sophistiqués
8. Enrichissement des requêtes
Une technique qui consiste à ajouter des termes connexes à la requête initiale afin d'améliorer la couverture de la recherche.
Processus :
Analyser la requête originale
Générer des synonymes et des phrases sémantiquement proches
Complétez la requête avec ces termes supplémentaires
Objet :
Augmenter l'éventail des correspondances potentielles dans le corpus de documents
Améliorer les performances de recherche pour les requêtes formulées dans un langage spécifique ou technique
Avantages :
Possibilité de retrouver des documents pertinents qui ne correspondent pas exactement aux termes de la requête initiale.
Peut aider à surmonter l'inadéquation du vocabulaire entre les requêtes et les documents
Défis :
Risque de dérive des requêtes en l'absence d'une mise en œuvre rigoureuse
Peut augmenter la charge de calcul dans le processus de recherche.




