cursus
RAG agentique : Tutoriel étape par étape avec projet de démonstration
Combien de fois souhaitez-vous que votre IA fasse plus que répéter ce qu'elle sait déjà ? Ayant passé d'innombrables heures à affiner et à modifier des systèmes d'intelligence artificielle, je peux vous dire que les modèles traditionnels, bien qu'impressionnants, donnent souvent l'impression d'être coincés dans une bulle limitée à ce sur quoi ils ont été formés. C'est là que Agentic RAG entre en jeu.
Dans le cadre de la RAG agentique, les capacités de prise de décision de l'intelligence artificielle agentique sont prises en compte. l'IA agentique rencontrent la capacité d'adaptation de la génération augmentée par la recherche (RAG). Ensemble, ils forment un système capable d'accéder à des informations pertinentes, de raisonner avec elles et de les générer de manière indépendante.
J'ai déjà écrit un article sur le RAG agentique qui vous aidera à tout comprendre d'un point de vue théorique. Cet article sera plus pratique, alors concentrons-nous sur ce point.
Aperçu du projet Agentic RAG
Permettez-moi de vous expliquer, étape par étape, ce que nous construisons. Il s'agit de créer un pipeline RAG basé sur l'architecture présentée ici :
Étape 1 : Requête de l'utilisateur
Qu'il s'agisse d'une simple requête ou d'un problème complexe, tout commence par une question de l'utilisateur. C'est le Spark qui met notre pipeline en mouvement.
Étape 2 : Acheminement de la requête
Ensuite, le système effectue des vérifications : Puis-je répondre à cette question ?
Oui ? Il s'appuie sur les connaissances existantes et fournit une réponse immédiate.
Non ? Il est temps d'approfondir ! La demande est acheminée vers l'étape suivante.
Étape 3 : Récupération des données
Si la réponse n'est pas immédiatement disponible, le pipeline se tourne vers deux sources possibles :
- Documents locaux : Nous utiliserons un PDF prétraité comme base de connaissances, dans laquelle le système recherchera des éléments d'information pertinents.
- Recherche sur Internet : Si un contexte supplémentaire est nécessaire, le pipeline peut s'adresser à des sources externes pour obtenir des informations actualisées.
Étape 4 : Construire le contexte
Les données extraites, qu'elles proviennent du PDF ou du web, sont ensuite compilées dans un contexte cohérent. Pensez-y comme si vous rassembliez toutes les pièces du puzzle avant de les assembler.
Étape 5 : Génération de la réponse finale
Enfin, ce contexte est transmis à un modèle de langage étendu (LLM) afin d'élaborer une réponse claire et précise. Il ne s'agit pas seulement d'extraire des données, mais aussi de les comprendre et de les présenter de la meilleure façon possible.
À l'issue de ce projet, nous disposerons d'un pipeline RAG intelligent et efficace, capable de répondre de manière dynamique aux requêtes en tenant compte du contexte réel.
Source de données locales
Pour commencer, je vais utiliser un document du monde réel comme source de données locale. Le document sur lequel nous allons travailler n'est autre que le suivant Principes de l'IA générative. Il regorge d'informations précieuses et constituera donc un test parfait pour notre pipeline. Vous aurez également besoin d'un résumé du fichier que j'utilise à des fins de routage. Vous pouvez obtenir le fichier de synthèse ici.
Voici tout ce dont vous avez besoin pour commencer, étape par étape.
Conditions préalables
Avant d'entrer dans le vif du sujet, vous devez avoir mis en place un certain nombre d'éléments :
- Clé API Groq: Vous aurez besoin d'une clé API de Groq, que vous pouvez obtenir ici : Console API Groq
- Clé API Gemini: Gemini vous aidera lors de l'orchestration avec des agents, Groq donne des réponses super rapides mais peut être bloqué par les limites de taux actuelles qu'ils ont : Console API Gemini
- Clé API Serper.dev: Pour toute fonctionnalité de recherche sur Internet, nous utiliserons Serper.dev. Obtenez votre clé API ici : Clé API Serper.dev
Installation des paquets
Assurons-nous d'avoir installé les bons outils. Ouvrez votre terminal et exécutez les commandes suivantes pour installer les paquets Python nécessaires :
pip install langchain-groq faiss-cpu crewai serper pypdf2 python-dotenv setuptools sentence-transformers huggingface distutils`
Mise en place de l'environnement
Une fois les clés et les paquets prêts, vous pouvez partir ! Je vous recommande de sauvegarder vos clés d'API dans un fichier.env
ou en toute sécurité dans votre base de code. Voici un exemple de fichier .env
:
import os from dotenv
import load_dotenv from langchain.vectorstores
import FAISS from langchain.document_loaders
import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
from langchain_groq import ChatGroq
from crewai_tools import SerperDevTool
from crewai import Agent, Task, Crew, LLM
load_dotenv()
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
SERPER_API_KEY = os.getenv("SERPER_API_KEY")
GEMINI=os.getenv("GEMINI")
J'ai chargé des variables d'environnement afin de pouvoir gérer en toute sécurité les clés d'API et les données sensibles sans les coder en dur. Cela garantit que le script reste sécurisé et que je peux changer les clés en un seul endroit ( fichier.env
) si nécessaire.
En bref, voici ce que feront ces paquets et fonctions importés :
- os : Fournit des utilitaires d'interface avec le système d'exploitation.
- dotenv: Charge les variables d'environnement à partir des fichiers
.env
. - FAISS : Magasin de vecteurs pour la recherche et l'extraction de similarités.
- PyPDFLoader : Extrait le contenu textuel des documents PDF.
- RecursiveCharacterTextSplitter : Découpe le texte en morceaux gérables de manière récursive.
- Les mariages à visage découvert : Génère des enchâssements de texte à l'aide des modèles HuggingFace.
- ChatGroq : Interface de chat utilisant l'accélération matérielle Groq.
- SerperDevTool : Outil permettant d'effectuer des recherches sur le web.
- ScrapeWebsiteTool : Extraction de données à partir de pages web.
- Agent : Définit une entité IA avec des rôles et des objectifs.
- Tâche : Représente un objectif ou une action spécifique pour un agent.
- L'équipage : Orchestrer les agents et les tâches pour des flux de travail coordonnés.
- LLM : Interface d'un grand modèle de langage pour générer des réponses textuelles.
Initialisation des LLM
Nous commençons par initialiser deux modèles linguistiques :
llm
: Pour les tâches générales telles que le routage et la génération de réponses. Nous utiliserons le modèlellama-3.3-70b-specdec
.crew_llm
: Spécifiquement pour l'agent web-scraping, car il a besoin d'une configuration légèrement différente (comme la température pour des résultats plus créatifs). Nous utiliserons le modèlegemini/gemini-1.5-flash
.
# Initialize LLM
llm = ChatGroq(
model="llama-3.3-70b-specdec",
temperature=0,
max_tokens=500,
timeout=None,
max_retries=2,
)
crew_llm = LLM(
model="gemini/gemini-1.5-flash",
api_key=GEMINI,
max_tokens=500,
temperature=0.7
)
Ajouter le décideur
La fonction check_local_knowledge()
ci-dessous joue le rôle de décideur. J'ai créé une invite à laquelle j'ai transmis la requête de l'utilisateur et un certain contexte local (provenant du PDF). Le modèle répond par "Oui" ou "Non", en m'indiquant s'il dispose localement de suffisamment d'informations pour répondre à la demande. Si ce n'est pas le cas, nous aurons recours au "web scraping".
def check_local_knowledge(query, context):
"""Router function to determine if we can answer from local knowledge"""
prompt = '''Role: Question-Answering Assistant
Task: Determine whether the system can answer the user's question based on the provided text.
Instructions:
- Analyze the text and identify if it contains the necessary information to answer the user's question.
- Provide a clear and concise response indicating whether the system can answer the question or not.
- Your response should include only a single word. Nothing else, no other text, information, header/footer.
Output Format:
- Answer: Yes/No
Study the below examples and based on that, respond to the last question.
Examples:
Input:
Text: The capital of France is Paris.
User Question: What is the capital of France?
Expected Output:
Answer: Yes
Input:
Text: The population of the United States is over 330 million.
User Question: What is the population of China?
Expected Output:
Answer: No
Input:
User Question: {query}
Text: {text}
'''
formatted_prompt = prompt.format(text=context, query=query)
response = llm.invoke(formatted_prompt)
return response.content.strip().lower() == "yes"
Agent de recherche et d'extraction de données sur le Web
Ensuite, nous avons mis en place un agent de recherche et d'exploration du Web en utilisant la bibliothèque crewai
bibliothèque. Cet agent utilise un outil de recherche (SerperDevTool
) pour trouver des articles en rapport avec la requête de l'utilisateur. La description de la tâche permet à l'agent de savoir ce qu'il doit rechercher et résume le contenu Web pertinent. C'est comme si vous envoyiez un employé spécialisé chercher des données sur l'internet.
Ensuite, la fonction get_web_content()
exécute l'agent d'exploration du web. Il envoie la requête en entrée et récupère un résumé concis de l'article le plus pertinent. Il renvoie le résultat brut, qui devient notre contexte si le routeur décide que nous n'avons pas assez d'informations locales.
def setup_web_scraping_agent():
"""Setup the web scraping agent and related components"""
search_tool = SerperDevTool() # Tool for performing web searches
scrape_website = ScrapeWebsiteTool() # Tool for extracting data from websites
# Define the web search agent
web_search_agent = Agent(
role="Expert Web Search Agent",
goal="Identify and retrieve relevant web data for user queries",
backstory="An expert in identifying valuable web sources for the user's needs",
allow_delegation=False,
verbose=True,
llm=crew_llm
)
# Define the web scraping agent
web_scraper_agent = Agent(
role="Expert Web Scraper Agent",
goal="Extract and analyze content from specific web pages identified by the search agent",
backstory="A highly skilled web scraper, capable of analyzing and summarizing website content accurately",
allow_delegation=False,
verbose=True,
llm=crew_llm
)
# Define the web search task
search_task = Task(
description=(
"Identify the most relevant web page or article for the topic: '{topic}'. "
"Use all available tools to search for and provide a link to a web page "
"that contains valuable information about the topic. Keep your response concise."
),
expected_output=(
"A concise summary of the most relevant web page or article for '{topic}', "
"including the link to the source and key points from the content."
),
tools=[search_tool],
agent=web_search_agent,
)
# Define the web scraping task
scraping_task = Task(
description=(
"Extract and analyze data from the given web page or website. Focus on the key sections "
"that provide insights into the topic: '{topic}'. Use all available tools to retrieve the content, "
"and summarize the key findings in a concise manner."
),
expected_output=(
"A detailed summary of the content from the given web page or website, highlighting the key insights "
"and explaining their relevance to the topic: '{topic}'. Ensure clarity and conciseness."
),
tools=[scrape_website],
agent=web_scraper_agent,
)
# Define the crew to manage agents and tasks
crew = Crew(
agents=[web_search_agent, web_scraper_agent],
tasks=[search_task, scraping_task],
verbose=1,
memory=False,
)
return crew
def get_web_content(query):
"""Get content from web scraping"""
crew = setup_web_scraping_agent()
result = crew.kickoff(inputs={"topic": query})
return result.raw
Création de la base de données vectorielle
La fonction setup_vector_db()
crée la base de données vectorielles à partir d'un fichier PDF. Voici comment j'ai procédé, étape par étape :
- Chargez le PDF : J'ai utilisé
PyPDFLoader
pour extraire le contenu. - Découpez le texte: J'ai divisé le contenu du PDF en morceaux plus petits (1000 caractères avec 50 caractères de chevauchement) à l'aide de
RecursiveCharacterTextSplitter
. Les données peuvent ainsi être gérées et faire l'objet de recherches. - Créer une base de données vectorielle: J'ai intégré les morceaux à l'aide d'un modèle de transformateur de phrase et je les ai stockés dans un fichier FAISS et je les ai stockés dans une base de données vectorielles FAISS. Cela me permet de rechercher efficacement un texte pertinent.
Ensuite, la fonction get_local_content()
interroge la base de données vectorielles pour trouver les 5 morceaux les plus pertinents par rapport à la requête de l'utilisateur. Il combine ces morceaux en une seule chaîne de contexte.
def setup_vector_db(pdf_path):
"""Setup vector database from PDF"""
# Load and chunk PDF
loader = PyPDFLoader(pdf_path)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50
)
chunks = text_splitter.split_documents(documents)
# Create vector database
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-mpnet-base-v2"
)
vector_db = FAISS.from_documents(chunks, embeddings)
return vector_db
def get_local_content(vector_db, query):
"""Get content from vector database"""
docs = vector_db.similarity_search(query, k=5)
return " ".join([doc.page_content for doc in docs])
Générer la réponse finale
Une fois que j'ai le contexte (à partir de documents locaux ou d'une recherche sur le web), je le transmets au modèle linguistique avec la requête de l'utilisateur. Le LLM génère la réponse finale en combinant le contexte et la requête dans un format conversationnel.
Voici le déroulement du traitement de la requête principale :
- Routage : J'utilise
check_local_knowledge()
pour décider si le contenu PDF local contient suffisamment de données pour répondre à la requête. - Dans l'affirmative "Oui"je récupère les morceaux pertinents dans la base de données vectorielle.
- Dans l'affirmative "Non"je cherche sur le web des articles pertinents.
- Réponse finale: Une fois que j'ai le contexte, je le transmets au LLM pour qu'il génère la réponse finale.
def generate_final_answer(context, query):
"""Generate final answer using LLM"""
messages = [
(
"system",
"You are a helpful assistant. Use the provided context to answer the query accurately.",
),
("system", f"Context: {context}"),
("human", query),
]
response = llm.invoke(messages)
return response.content
def process_query(query, vector_db, local_context):
"""Main function to process user query"""
print(f"Processing query: {query}")
# Step 1: Check if we can answer from local knowledge
can_answer_locally = check_local_knowledge(query, local_context)
print(f"Can answer locally: {can_answer_locally}")
# Step 2: Get context either from local DB or web
if can_answer_locally:
context = get_local_content(vector_db, query)
print("Retrieved context from local documents")
else:
context = get_web_content(query)
print("Retrieved context from web scraping")
# Step 3: Generate final answer
answer = generate_final_answer(context, query)
return answer
Enfin, nous lions le tout avec la fonction main()
:
def main():
# Setup
pdf_path = "genai-principles.pdf"
# Initialize vector database
print("Setting up vector database...")
vector_db = setup_vector_db(pdf_path)
# Get initial context from PDF for routing
local_context = get_local_content(vector_db, "")
# Example usage
query = "What is Agentic RAG?"
result = process_query(query, vector_db, local_context)
print("\nFinal Answer:")
print(result)
if __name__ == "__main__":
main()
Ci-dessus, nous :
- Configurez la base de données vectorielle : Chargez et traitez le PDF.
- Initialisation du contexte local : Nous avons récupéré un contenu général du PDF pour le transmettre au routeur en tant que contexte.
- Lancez une requête à titre d'exemple : Nous avons exécuté un exemple de requête (
"What is Agentic RAG?"
) et imprimé la réponse finale.
Voici le résultat du programme :
Agentic RAG is a technique for building Large Language Model (LLM) powered applications that incorporates AI agents. It is an extension of the traditional Retrieval-Augmented Generation (RAG) approach, which uses an external knowledge source to provide the LLM with relevant context and reduce hallucinations.
In traditional RAG pipelines, the retrieval component is typically composed of an embedding model and a vector database, and the generative component is an LLM. At inference time, the user query is used to run a similarity search over the indexed documents to retrieve the most similar documents to the query and provide the LLM with additional context.
Agentic RAG, on the other hand, introduces AI agents that are designed to interact with the user query and provide additional context to the LLM. These agents can be thought of as "virtual assistants" that help the LLM to better understand the user's intent and retrieve relevant documents.
The key components of Agentic RAG include:
1. AI agents: These are the virtual assistants that interact with the user query and provide additional context to the LLM.
2. Retrieval component: This is the component that retrieves the most similar documents to the user query.
3. Generative component: This is the component that uses the retrieved documents to generate the final output.
Agentic RAG has several benefits, including:
1. Improved accuracy: By providing additional context to the LLM, Agentic RAG can improve the accuracy of the generated output.
2. Enhanced user experience: Agentic RAG can help to reduce the complexity of the user interface and provide a more natural and intuitive experience.
3. Increased flexibility: Agentic RAG can be easily extended to support new use cases and applications.
However, Agentic RAG also has some limitations, including:
1. Increased complexity: Agentic RAG requires additional components and infrastructure, which can increase the complexity of the system.
2. Higher computational requirements: Agentic RAG requires more computational resources to handle the additional complexity of the AI agents and the retrieval component.
3. Training requirements: Agentic RAG requires more data and training to learn the behaviour of the AI agents and the retrieval component.
Explication de la sortie
Lorsque j'ai posé la question "Qu'est-ce que le RAG Agentic ?" qui n'était pas explicitement disponible dans le document fourni, le système a démontré sa flexibilité et son intelligence. Les agents crewAI ont acheminé la requête correctement, en utilisant la compréhension du routeur selon laquelle un contexte externe était nécessaire. Les agents ont collaboré pour extraire l'article le plus pertinent du web, analyser son contenu et générer une réponse bien informée.
Le système fournissait une explication claire de la GCR agentique, de ses composantes (agents d'intelligence artificielle, recherche et éléments génératifs), de ses avantages (précision, expérience utilisateur et flexibilité) et de ses limites (complexité, besoins en matière de calcul et de formation).
Cela met en évidence la capacité du pipeline à récupérer le contexte de manière dynamique et à fournir des informations précises, concises et précieuses, même lorsqu'il est confronté à des requêtes dépassant le cadre de son ensemble de données initial.
Conclusion
Le pipeline que nous avons construit est un processus dynamique en plusieurs étapes qui traite efficacement les requêtes des utilisateurs en combinant les connaissances existantes et externes.
Le système peut s'adapter dynamiquement à diverses requêtes et fournir des réponses précises et conviviales. Grâce à l'intégration de données locales, de recherches en direct sur Internet et d'une interface utilisateur transparente, le pipeline RAG s'avère être une solution robuste et pratique pour des applications concrètes. Dans une prochaine étape, essayez de construire quelque chose de votre côté en utilisant le flux de travail que nous avons couvert.
Ingénieur GenAI senior et créateur de contenu qui a recueilli 20 millions de vues en partageant ses connaissances sur la GenAI et la science des données.
Apprenez l'IA avec ces cours !
cours
Retrieval Augmented Generation (RAG) avec LangChain
cours