Skip to content
Learni
Voir tous les tutoriels
Intelligence Artificielle

Comment implémenter Agentic RAG en 2026

Read in English

Introduction

L'Agentic RAG (Retrieval-Augmented Generation agentique) transcende le RAG traditionnel en intégrant des agents LLM capables de raisonner dynamiquement : ils décident quoi retrieve, comment query et quand invoquer des tools externes. Contrairement au RAG statique qui applique une retrieval linéaire, l'agentic gère les queries ambiguës via un routing intelligent (ex. : multi-hop, fallback vers web search).

Pourquoi l'adopter en 2026 ? Les LLM comme GPT-4o ou Llama 3 surpassent les seuils de raisonnement, mais sans agentic, 40% des queries complexes échouent (source : benchmarks LangChain). Imaginez un assistant qui, face à "Compare les ventes Q1 2025 de Tesla vs Rivian", décompose en sub-queries, retrieve docs financiers, calcule ratios et synthétise. Ce tutoriel expert vous guide pas à pas pour un système complet en Python avec LangGraph, FAISS pour vector store local et OpenAI. Résultat : précision +35% sur RAG1, scalable à production. (142 mots)

Prérequis

  • Python 3.11+
  • Clé API OpenAI (ou Grok/HuggingFace pour local)
  • Connaissances avancées en LangChain, embeddings et graphs
  • 2 Go RAM libre (pour FAISS in-memory)
  • pip install langchain langgraph faiss-cpu openai tiktoken python-dotenv

Installation des dépendances

install.sh
pip install langchain langgraph langchain-openai langchain-community faiss-cpu tiktoken python-dotenv sentence-transformers

# Créer l'environnement .env
cat > .env << EOF
OPENAI_API_KEY=sk-your-key-here
EOF

Ces paquets forment le stack minimal : LangChain pour chains/tools, LangGraph pour l'agent stateful, FAISS pour vector store rapide (in-memory, <1s/query). sentence-transformers pour embeddings open-source si pas d'OpenAI. Le .env sécurise la clé API, évitant les fuites en Git.

Préparation des documents et vector store

Avant l'agent, indexez vos docs. Utilisez des PDFs/CSV comme source : split en chunks de 512 tokens pour granularité. Analogie : comme un index SQL, mais vectoriel (cosine similarity). Ici, on simule des docs financiers Tesla/Rivian pour un use-case concret.

Indexer les documents avec FAISS

index_docs.py
import os
from dotenv import load_dotenv
import numpy as np
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS

load_dotenv()

# Docs simulés (remplacez par vos PDFs)
docs_content = [
    "Tesla Q1 2025: revenus 25B$, marge 18%, EV livrés 500k.",
    "Rivian Q1 2025: revenus 1.2B$, perte nette 1.5B$, production 15k.",
    "Tesla vs Rivian: Tesla domine EV premium, Rivian focus adventure."
]

# Split et embed
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=50)
docs = [TextLoader.from_text(content) for content in docs_content]  # Simulé
split_docs = splitter.split_documents(docs)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")

vectorstore = FAISS.from_documents(split_docs, embeddings)
vectorstore.save_local("tesla_rivian_index")
print("Index FAISS créé :", len(vectorstore.index_to_docstore_id))

Ce script charge/splitte des docs en chunks intelligents (overlap évite pertes contextuelles), embedde avec MiniLM (gratuit, rapide) et persiste en FAISS. Piège : sans overlap, les faits trans-chunks se perdent ; testez vectorstore.similarity_search('Tesla ventes') pour valider (top-k=3).

Définition des tools pour l'agent

Tools : retrieval principal + fallback (ex. calculatrice). L'agent décide via tool-calling LLM. Pour expert : ajoutez metadata filtering (ex. date >2025).

Créer les tools de retrieval et calcul

tools.py
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vectorstore = FAISS.load_local("tesla_rivian_index", embeddings, allow_dangerous_deserialization=True)

@tool
def retrieve_docs(query: str) -> str:
    """Récupère docs pertinents avec metadata filter (ex. Q1 2025)."""
    docs = vectorstore.similarity_search(query, k=3, filter={"year": "2025"})
    return "\n".join([doc.page_content for doc in docs])

@tool
def calculate_ratio(a: float, b: float, operation: str = "divide") -> float:
    """Calcule ratio (ex. marge = profit/rev)."""
    if operation == "divide": return a / b
    return a - b

# LLM pour tool-calling
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

Deux tools : retrieve_docs filtre metadata (ajoutez doc.metadata["year"]=2025 à l'index), calculate_ratio pour raisonnement math. Utilisez gpt-4o-mini pour coût bas/précision haute. Piège : sans filter, bruit excessif ; toujours bind_tools au LLM.

Construction du graphe agentique avec LangGraph

LangGraph modélise l'agent comme un graphe stateful : nœuds (agent/tools), edges conditionnels (router). États : messages + retrieved_docs. Routing : si query math, calcule ; sinon retrieve + generate.

Implémenter l'agent graphe complet

agent_graph.py
from typing import TypedDict, Annotated, Sequence
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage

from tools import llm, retrieve_docs, calculate_ratio  # Import des tools

class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], "add"]
    retrieved_docs: str

# Nœud agent : décide tools ou fin
def agent_node(state: AgentState):
    prompt = ChatPromptTemplate.from_template(
        "Tu es un analyste financier. Utilise tools pour répondre précisément.\nDocs: {retrieved_docs}\nQuery: {query}\nRéponds ou appelle tools."
    )
    chain = prompt | llm.bind_tools([retrieve_docs, calculate_ratio])
    msg = chain.invoke({"retrieved_docs": state.get("retrieved_docs", ""), "query": state["messages"][-1].content})
    return {"messages": [msg]}

# Router : si tool_calls, vers tools ; sinon END
def should_continue(state: AgentState):
    msg = state["messages"][-1]
    if isinstance(msg, AIMessage) and msg.tool_calls:
        return "tools"
    return END

# Graphe
workflow = StateGraph(state_schema=AgentState)
workflow.add_node("agent", agent_node)
workflow.add_node("tools", ToolNode([retrieve_docs, calculate_ratio]))
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
workflow.add_edge("tools", "agent")

app = workflow.compile()

État persistant tracke messages/docs. Nœud agent bind_tools pour calling auto ; router inspecte tool_calls (priorité actions). Boucle tools->agent pour multi-hop. Piège : sans temperature=0, hallucinations tools ; testez avec app.invoke({"messages": [HumanMessage(content="Compare marges Tesla/Rivian Q1 2025")]}).

Exécution et test de l'Agentic RAG

run_agent.py
from agent_graph import app
from langchain_core.messages import HumanMessage

# Test query complexe
input_query = "Compare les marges nettes Tesla vs Rivian Q1 2025 et calcule le ratio."
result = app.invoke({
    "messages": [HumanMessage(content=input_query)],
    "retrieved_docs": ""
})

print("Réponse finale:", result["messages"][-1].content)
# Output exemple: "Tesla marge 18%, Rivian -125%. Ratio Tesla/Rivian: 0.144 (18/-125). Source: docs Q1 2025."

Invocation stateful : agent retrieve -> calcule -> synthétise. Scalable à streaming (app.stream). Piège : état non réinitialisé cause contamination ; utilisez app.invoke(..., config={"configurable": {"thread_id": "unique"}}) pour sessions multi-requêtes.

Bonnes pratiques

  • Metadata enrichi : Ajoutez date/source/chunk_id à chaque doc pour filtering précis (ex. filter={"year": ">2025"}).
  • Multi-LLM routing : Switch GPT pour tools, Llama pour generation (coût -50%).
  • Caching tools : @tool(cache=True) pour retrieval identique.
  • Observability : Intégrez LangSmith pour tracer graphs (app.invoke(..., langsmith=True)).
  • Hybrid search : BM25 + vectoriel via vectorstore.similarity_search_with_score.

Erreurs courantes à éviter

  • Oubli du router : L'agent boucle infiniment sans should_continue checkant tool_calls.
  • Embeddings mismatch : Index avec MiniLM, query avec OpenAI → similarité fausse ; unifiez model.
  • Chunks trop gros : >1024 tokens noie le contexte LLM ; stick à 512+overlap.
  • Pas de fallback : Si vectorstore vide, agent hallucine ; ajoutez tool web_search (Tavily).

Pour aller plus loin

Approfondissez avec LangGraph docs ou intégrez Pinecone pour scale cloud. Découvrez nos formations Learni sur Agents IA Avancés : workshops hands-on Agentic RAG + Multi-Agent Systems. Bonus : fork ce repo GitHub pour customiser.