RAG : Connecter un LLM à Vos Documents Internes en Pratique
Votre équipe pose chaque semaine les mêmes questions au service RH, à la comptabilité ou au support technique. Et si un assistant IA pouvait répondre instantanément en s’appuyant sur vos propres procédures internes, vos contrats, vos fiches produit ? Selon une étude McKinsey de 2024, les entreprises qui déploient des assistants IA connectés à leur base documentaire réduisent de 40 % le temps consacré à la recherche d’information. La technologie qui rend cela possible s’appelle le RAG — Retrieval-Augmented Generation.
Qu’est-ce que le RAG et pourquoi dépasse-t-il le LLM seul ?
Un LLM comme GPT-4 ou Claude possède une connaissance générale impressionnante, mais il ignore tout de votre entreprise. Il ne connaît pas votre catalogue produit mis à jour le mois dernier, vos procédures RH spécifiques, ni les clauses de vos contrats fournisseurs.
Face à ce problème, deux approches naïves existent : envoyer tous vos documents dans le prompt (limité par la fenêtre de contexte et coûteux), ou fine-tuner le modèle sur vos données (coûteux, lent, et le modèle “oublie” les mises à jour). Le RAG offre une troisième voie, bien plus élégante.
Le principe : avant de générer une réponse, le système récupère les passages les plus pertinents de votre base documentaire, puis les injecte dans le contexte du LLM. Le modèle répond en s’appuyant sur des faits réels tirés de vos documents — et non sur des suppositions.
Comparaison des approches :
| Critère | LLM seul | Fine-tuning | RAG |
|---|---|---|---|
| Coût initial | Faible | Élevé | Moyen |
| Mise à jour docs | Impossible | Long | Immédiat |
| Précision métier | Faible | Bonne | Très bonne |
| Traçabilité sources | Non | Non | Oui |
Le pipeline RAG étape par étape
1. Ingestion et découpage (Chunking)
La première étape consiste à transformer vos documents en fragments exploitables. Un PDF de 50 pages doit être découpé en morceaux cohérents — ni trop petits (perte de contexte), ni trop grands (dilution de la pertinence).
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # ~500 caractères par chunk
chunk_overlap=50, # chevauchement pour ne pas couper les idées
separators=["\n\n", "\n", ". ", " "]
)
chunks = splitter.split_documents(documents) Stratégies de découpage selon le type de document :
- Documents structurés (PDF avec titres) : découpage par section
- Emails ou messages courts : par conversation
- Textes longs et denses : chevauchement de 10-15 % recommandé
- Tableaux ou données tabulaires : conserver la ligne d’en-tête dans chaque chunk
2. Embedding : transformer le texte en vecteurs
Chaque chunk est ensuite converti en un vecteur numérique (embedding) qui capture sa signification sémantique. Deux phrases qui veulent dire la même chose, même avec des mots différents, auront des vecteurs proches.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
# Modèle multilingue — idéal pour du français
embeddings = model.encode(chunks, batch_size=32) Pour le français, le modèle camembert-base ou paraphrase-multilingual-mpnet-base-v2 donne d’excellents résultats. Les services cloud (OpenAI Embeddings, Cohere) offrent des embeddings de haute qualité si vous n’avez pas de contrainte de souveraineté des données.
3. Stockage dans une base vectorielle
Les vecteurs sont stockés dans une base de données spécialisée qui permet une recherche par similarité ultra-rapide parmi des millions de documents.
import chromadb
client = chromadb.PersistentClient(path="./ma_base_docs")
collection = client.get_or_create_collection("documents_internes")
collection.add(
embeddings=embeddings.tolist(),
documents=chunks,
ids=[f"chunk_{i}" for i in range(len(chunks))],
metadatas=[{"source": doc.metadata["source"]} for doc in chunks]
) Choix de la base vectorielle selon vos besoins :
| Solution | Type | Idéal pour |
|---|---|---|
| ChromaDB | Local/Open-source | Prototypage, PME < 100k docs |
| Qdrant | Self-hosted/Cloud | Production, filtres complexes |
| Pinecone | SaaS | Scalabilité sans ops |
| pgvector | Extension PostgreSQL | Si vous avez déjà PostgreSQL |
| Weaviate | Self-hosted/Cloud | Multimodal (texte + images) |
4. Retrieval : trouver les passages pertinents
Quand un utilisateur pose une question, celle-ci est aussi convertie en vecteur, puis on cherche les chunks les plus proches dans la base.
def retrieve(question: str, n_results: int = 5):
query_embedding = model.encode([question])
results = collection.query(
query_embeddings=query_embedding.tolist(),
n_results=n_results,
include=["documents", "metadatas", "distances"]
)
return results Astuce : combinez la recherche vectorielle (sémantique) avec une recherche par mots-clés (BM25) pour les termes techniques ou les références exactes. LangChain propose un EnsembleRetriever à cet effet.
5. Génération : le LLM répond avec contexte
Les chunks récupérés sont injectés dans le prompt avant la question de l’utilisateur :
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
prompt_template = ChatPromptTemplate.from_template("""
Tu es un assistant interne de l'entreprise. Réponds uniquement en te basant
sur les documents fournis. Si l'information n'est pas dans les documents,
dis-le clairement.
Documents pertinents :
{context}
Question : {question}
Réponse :
""")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
def generate_answer(question: str):
results = retrieve(question)
context = "\n\n---\n\n".join(results["documents"][0])
chain = prompt_template | llm
response = chain.invoke({"context": context, "question": question})
return response.content Cas pratique : la base de connaissances RH d’une PME
Prenons une PME de 80 employés avec des procédures RH dispersées dans 200 documents Word et PDF. Voici comment le RAG transforme l’expérience :
Avant le RAG : un employé qui demande “Combien de jours de congé puis-je poser en une seule fois ?” doit appeler les RH ou chercher dans une arborescence de dossiers.
Avec le RAG : il interroge l’assistant qui retrouve instantanément la clause correspondante dans la convention collective et dans le règlement intérieur, en citant les sources.
L’implémentation avec LlamaIndex, alternative à LangChain plus orientée recherche documentaire :
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.node_parser import SentenceSplitter
# Charger tous les documents RH
documents = SimpleDirectoryReader("./docs_rh").load_data()
# Créer l'index
index = VectorStoreIndex.from_documents(
documents,
transformations=[SentenceSplitter(chunk_size=512)]
)
# Interroger
query_engine = index.as_query_engine(similarity_top_k=4)
response = query_engine.query("Quelle est la politique de télétravail ?")
print(response)
# Sources citées automatiquement Optimiser la qualité de votre RAG
Le problème des mauvaises réponses vient souvent du retrieval, pas du LLM. Voici les leviers d’optimisation :
Enrichir les métadonnées : ajoutez au moment de l’indexation la date du document, le département, le type (procédure/contrat/FAQ). Cela permet des filtres précis (“cherche uniquement dans les documents RH mis à jour après janvier 2024”).
HyDE (Hypothetical Document Embeddings) : au lieu d’embedder directement la question, demandez au LLM de générer d’abord un document hypothétique qui répondrait à cette question, puis embedder ce document. Améliore la précision de 15-25 % sur les questions courtes.
Reranking : après le retrieval initial, utilisez un modèle de reranking (Cohere Rerank, cross-encoder) pour reclasser les résultats par pertinence réelle.
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
def rerank(question, chunks, top_k=3):
pairs = [(question, chunk) for chunk in chunks]
scores = reranker.predict(pairs)
ranked = sorted(zip(scores, chunks), reverse=True)
return [chunk for _, chunk in ranked[:top_k]] Considérations pour une PME française
Souveraineté des données : si vos documents contiennent des données sensibles (RH, financières, clients), privilégiez une solution on-premise. ChromaDB + Ollama (LLM local) permet un RAG entièrement hébergé chez vous, sans envoyer de données vers des serveurs américains.
Coût : pour 10 000 pages de documents, l’indexation initiale avec OpenAI Embeddings coûte environ 0,50 €. Les requêtes quotidiennes restent négligeables (< 10 € / mois pour 100 utilisateurs).
Maintenance : prévoyez une stratégie de mise à jour. Quand un document est modifié, les anciens chunks doivent être supprimés et remplacés. LangChain propose des DocumentLoader avec détection de changements pour automatiser cela.
Ce que le RAG ne peut pas faire
Il faut être honnête sur les limites : le RAG ne raisonne pas sur plusieurs documents simultanément (ex : “compare ces trois contrats”), ne gère pas bien les questions nécessitant des calculs complexes, et peut citer des sources contradictoires sans les réconcilier. Pour ces cas, des architectures plus avancées (agents multi-outils, GraphRAG) sont nécessaires.
Conclusion
Le RAG est aujourd’hui la technique la plus pragmatique pour connecter l’intelligence des LLM à la connaissance de votre entreprise. Il ne nécessite pas de GPU, se met en place en quelques jours, et donne des résultats immédiatement utilisables. La clé du succès réside dans la qualité du découpage documentaire et d’une stratégie de retrieval adaptée à vos types de documents.
Votre entreprise possède une richesse documentaire inexploitée — procédures, historiques, expertises métier. Le RAG est le pont entre cette connaissance et l’efficacité opérationnelle que l’IA peut apporter.
Prêt à connecter vos documents à un LLM ? L’équipe Brio Novia accompagne les PME françaises dans la conception et le déploiement de solutions RAG sur mesure. Contactez-nous à contact@brio-novia.eu pour un audit gratuit de votre base documentaire.