Accéder au contenu principal

RAG agentique : Tutoriel étape par étape avec projet de démonstration

Apprenez à construire un pipeline Agentic RAG à partir de zéro, en intégrant des sources de données locales et du web scraping pour générer des réponses contextuelles aux requêtes des utilisateurs.
Actualisé 27 févr. 2025  · 12 min de lecture

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 :

Vue d'ensemble du projet de démonstration du chiffon agentique

É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 :

  1. Documents locaux : Nous utiliserons un PDF prétraité comme base de connaissances, dans laquelle le système recherchera des éléments d'information pertinents.
  2. 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 :

  1. Clé API Groq: Vous aurez besoin d'une clé API de Groq, que vous pouvez obtenir ici : Console API Groq
  2. 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
  3. 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èle llama-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èle gemini/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 :

  1. Chargez le PDF : J'ai utilisé PyPDFLoader pour extraire le contenu.
  2. 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.
  3. 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 :

  1. 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.
  2. 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 :

  1. Configurez la base de données vectorielle : Chargez et traitez le PDF.
  2. 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.
  3. 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.


Bhavishya Pandit's photo
Author
Bhavishya Pandit
LinkedIn
Twitter

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.

Sujets

Apprenez l'IA avec ces cours !

cursus

Développer des applications d'IA

23 heures hr
Apprenez à créer des applications alimentées par l'IA avec les derniers outils de développement d'IA, notamment l'API OpenAI, Hugging Face et LangChain.
Afficher les détailsRight Arrow
Commencer le cours
Certification disponible

cours

Retrieval Augmented Generation (RAG) avec LangChain

3 hr
4.2K
Apprenez des méthodes de pointe pour intégrer des données externes aux LLM en utilisant Retrieval Augmented Generation (RAG) avec LangChain.
Voir plusRight Arrow