Sur cette page
Répondez de tête, puis ouvrez. Le RAG : une IA qui répond avec les documents de l'entreprise
1Un RAG garantit-il qu'une réponse est juste ?
Non. Il la rend vérifiable, parce qu'elle cite ses passages. Si un document est faux ou périmé, la réponse le sera aussi.
2Votre équipe a dix procédures de quelques pages. Faut-il un RAG sur mesure ?
Probablement pas. Un projet dans votre assistant, avec ces dix documents, suffit souvent. Le sur mesure se justifie avec beaucoup de documents, des droits d'accès par personne ou du confidentiel à tenir à part.
- Un RAG tient en quatre étapes : découper, ranger par le sens, chercher, répondre en citant.
- Ranger par le sens, c'est transformer chaque passage en une liste de nombres, un vecteur ; deux textes proches ont des vecteurs proches.
- La recherche ne lit pas : elle compare des vecteurs, et rapporte les passages les plus proches de la question.
- Le modèle ne répond qu'à partir des passages qu'on lui donne, et doit dire quand la réponse n'y est pas.
- Le programme entier tient en 73 lignes ; ce qui le rend bon tient surtout aux documents et au découpage.
Objectif
Écrire le mécanisme du RAG en Python, sur les trois documents de l'atelier, et le faire répondre aux cinq questions dont vous connaissez la réponse. Le programme utilise l'API de Mistral pour le sens et pour la réponse.
Le code des étapes 2 à 4 appelle l'API de Mistral : il est vérifié contre la documentation de l'éditeur, mais pas encore exécuté par Meridal, et sa sortie n'est pas montrée. L'étape 1 ne fait aucun appel ; sa sortie est réelle.
Données fournies
Les trois documents fabriqués de l'atelier, en texte Markdown : rangez-les dans un dossier documents, à la racine du projet.
- Conditions générales de venteTélécharger
Lire le document ici
Document fabriqué pour l'atelier de Meridal : l'entreprise, ses règles et ses chiffres sont inventés. Version du 1er janvier 2026.
Article 1. Objet
Les présentes conditions s'appliquent à toute commande passée auprès de l'entreprise par un client professionnel. Toute commande vaut acceptation des présentes conditions.
Article 2. Commandes
Une commande se passe par écrit, par courriel ou depuis l'espace client. Le montant minimum d'une commande est de 150 euros hors taxes. Une commande n'est ferme qu'après l'envoi de l'accusé de réception de commande.
Article 3. Prix
Les prix sont ceux du tarif en vigueur au jour de la commande, en euros hors taxes. Les frais de port sont offerts au-delà de 800 euros hors taxes par commande.
Article 4. Livraison
Le délai de livraison est indiqué, à titre indicatif, sur l'accusé de réception de commande. Un retard de livraison ne permet pas d'annuler la commande, sauf accord écrit de l'entreprise.
Article 5. Réserve de propriété
Les marchandises restent la propriété de l'entreprise jusqu'au paiement complet de leur prix.
Article 6. Paiement
Le délai de paiement est de 45 jours fin de mois à compter de la date de facture. Aucun escompte n'est accordé pour un paiement anticipé.
Article 7. Retard de paiement
Tout retard de paiement entraîne, de plein droit, les conséquences suivantes.
Données fournies Conséquence Montant ou délai Pénalités de retard Trois fois le taux d'intérêt légal, calculées par jour de retard Indemnité forfaitaire pour frais de recouvrement 40 euros par facture Suspension des livraisons en cours Après 15 jours de retard Article 8. Litiges
Tout litige relève du tribunal de commerce du siège de l'entreprise.
- Procédure d'ouverture de compte clientTélécharger
Lire le document ici
Document fabriqué pour l'atelier de Meridal : l'entreprise, ses règles et ses chiffres sont inventés. Version 3, mai 2025. Responsable : le service comptable.
Étape 1. Les informations du client
Le commercial recueille le numéro SIREN du client, l'adresse de facturation et le nom de la personne à contacter pour les factures.
Étape 2. La fiche d'ouverture de compte
Avant toute première commande, le nouveau client remplit la fiche d'ouverture de compte. Le commercial la transmet au service comptable.
Étape 3. Les vérifications
Le service comptable vérifie le numéro SIREN dans l'annuaire des entreprises, puis l'absence de procédure collective en cours.
Étape 4. L'encours autorisé
L'encours autorisé d'un nouveau client est de 5 000 euros hors taxes. Au-delà, toute commande demande l'accord de la direction financière.
Étape 5. La création du compte
Le service comptable crée le compte dans le logiciel de gestion sous deux jours ouvrés, puis prévient le commercial.
- Note de la direction financière, 12 mars 2026Télécharger
Lire le document ici
Document fabriqué pour l'atelier de Meridal : l'entreprise, ses règles et ses chiffres sont inventés. Le 12 mars 2026. Destinataires : les commerciaux et le service comptable.
Objet : délai de paiement des nouveaux clients
À compter de ce jour, pour les nouveaux clients, le délai de paiement est ramené à 30 jours à compter de la date de facture, pendant les six premiers mois de la relation. Le délai des conditions générales de vente s'applique ensuite.
Les conditions générales de vente seront mises à jour au prochain semestre. D'ici là, cette note prévaut sur elles pour les nouveaux clients.
Consignes
Le projet
Terminaluv init rag-minimal cd rag-minimal uv add mistralai numpy python-dotenv
La bibliothèque de Mistral, en version 3.1.0, s'importe par from mistralai.client import Mistral.
Étape 1. Découper
Un passage par section du document, précédé du titre du document : coupé du reste, le passage garde ainsi d'où il vient.
decouper.pyimport re
from pathlib import Path
def decouper(chemin):
"""Un passage par section ##, précédé du titre du document."""
texte = chemin.read_text(encoding="utf-8")
titre = texte.splitlines()[0].lstrip("# ").strip()
passages = []
for bloc in re.split(r"\n(?=## )", texte)[1:]:
intitule, _, corps = bloc.partition("\n")
passages.append(f"{titre}, {intitule.lstrip('# ').strip()}\n{corps.strip()}")
return passages
fichiers = sorted(Path("documents").glob("*.md"))
passages = [p for f in fichiers for p in decouper(f)]
if __name__ == "__main__":
for f in fichiers:
n = len(decouper(f))
print(f"{f.name} : {n} passage" + "s" * (n > 1))
print(f"En tout : {len(passages)} passages")
print("---")
print(passages[5])uv run decouper.pyconditions-generales-de-vente.md : 8 passagesnote-direction-financiere-mars-2026.md : 1 passageprocedure-ouverture-de-compte.md : 5 passagesEn tout : 14 passages---Conditions générales de vente, Article 6. PaiementLe délai de paiement est de 45 jours fin de mois à compter de la date de facture. Aucunescompte n'est accordé pour un paiement anticipé.
Essayé le 7 octobre 2026 avec Python 3.12.7, sur les trois documents de l'atelier.
Étape 2. Ranger par le sens
Chaque passage devient un vecteur. La documentation de Mistral donne 1 024 nombres par vecteur, de norme 1 : le produit scalaire de deux vecteurs suffit pour mesurer leur proximité.
ranger.pyimport os import numpy as np from dotenv import load_dotenv from mistralai.client import Mistral from decouper import passages load_dotenv() client = Mistral(api_key=os.environ["MISTRAL_API_KEY"]) # un vecteur de sens par passage, en un seul appel reponse = client.embeddings.create(model="mistral-embed", inputs=passages) vecteurs = np.array([d.embedding for d in reponse.data]) print(vecteurs.shape)
uv run ranger.pyPas encore exécuté par Meridal. Ce qu'on attend : (14, 1024), quatorze passages de 1 024 nombres chacun.
Étape 3. Chercher
La question devient un vecteur à son tour ; les passages les plus proches sont ceux dont le produit scalaire est le plus grand. À ajouter à la fin de ranger.py.
ranger.py, suitedef chercher(question, k=3):
"""Les k passages les plus proches de la question, par le sens."""
q = client.embeddings.create(model="mistral-embed", inputs=[question]).data[0].embedding
scores = vecteurs @ np.array(q) # vecteurs de norme 1 : le produit scalaire mesure la proximité
meilleurs = np.argsort(scores)[::-1][:k]
return [(round(float(scores[i]), 3), passages[i]) for i in meilleurs]
for score, passage in chercher("Quel délai de paiement accorde-t-on à un nouveau client ?"):
print(score, passage.splitlines()[0])uv run ranger.pyPas encore exécuté par Meridal. Ce qu'on attend, sous la ligne de l'étape 2 : trois lignes, chacune un score et le titre d'un passage, la note de la direction financière parmi les deux premières.
Étape 4. Répondre en citant
Les trois passages trouvés, numérotés, et la question partent au modèle avec une consigne : répondre à partir d'eux seuls, citer leurs numéros, dire quand la réponse n'y est pas.
ranger.py, finCONSIGNE = (
"Réponds seulement à partir des extraits ci-dessous. Cite entre crochets le numéro "
"de chaque extrait utilisé. Si la réponse n'y est pas, dis-le."
)
def repondre(question):
extraits = [p for _, p in chercher(question)]
contexte = "\n\n".join(f"[{n}] {p}" for n, p in enumerate(extraits, 1))
message = f"{CONSIGNE}\n\n{contexte}\n\nQuestion : {question}"
r = client.chat.complete(model="mistral-large-latest",
messages=[{"role": "user", "content": message}])
return r.choices[0].message.content
for question in [
"Quel délai de paiement accorde-t-on à un client existant ?",
"Quel délai de paiement accorde-t-on à un nouveau client ?",
"Que doit faire un nouveau client avant sa première commande ?",
"En plus des pénalités, combien facture-t-on à un client qui paie en retard ?",
"Quel est le délai de livraison d'une commande ?",
]:
print("•", question)
print(repondre(question), "\n")uv run ranger.pyPas encore exécuté par Meridal. Ce qu'on attend : les cinq réponses de la correction commentée, chacune avec le numéro de ses extraits.
Critères de réussite
Indications
« KeyError: 'MISTRAL_API_KEY' »
CauseLa clé n'est pas dans l'environnement : pas de fichier .env, ou load_dotenv() appelé trop tard.
À faireVérifiez le fichier .env à la racine du projet et l'appel à load_dotenv() avant la création du client.
« ImportError » sur l'import de Mistral
CauseAvec la version 3.1.0, l'ancien from mistralai import Mistral ne fonctionne plus.
À faireÉcrivez from mistralai.client import Mistral.
Une erreur sur le paramètre « input »
CauseL'appel des embeddings de Mistral attend inputs, au pluriel.
À fairePassez une liste à inputs=, même pour une seule question.
La question d ne trouve pas l'article 7
CauseLe passage est un tableau : son vecteur rend mal ce que disent ses cases.
À faireAjoutez au document une phrase qui dit ce que contient le tableau, et relancez.
La réponse ne cite aucun numéro
CauseLe modèle n'a pas suivi la consigne.
À fairePlacez la consigne aussi après les extraits, juste avant la question, et vérifiez que chaque extrait porte bien son numéro.
Correction commentée
Ouvrir la correction
| Question | Passage attendu | Réponse attendue |
|---|---|---|
| a. Client existant | Conditions générales, article 6 | 45 jours fin de mois à compter de la date de facture |
| b. Nouveau client | La note ; l'article 6 juste après | 30 jours à compter de la date de facture pendant six mois, puis 45 jours fin de mois |
| c. Première commande | Procédure, étape 2 | Remplir la fiche d'ouverture de compte |
| d. Retard de paiement | Conditions générales, article 7 | 40 euros par facture, l'indemnité forfaitaire pour frais de recouvrement |
| e. Livraison | Conditions générales, article 4 | Aucun délai chiffré : il figure sur l'accusé de réception de commande |
Pourquoi ce découpageUne section par passage garde chaque règle entière avec son titre. Couper tous les 2 048 caractères, comme le fait le démarrage rapide de Mistral sur un long essai, couperait ici l'article 7 de son tableau.
Extensions
- La date dans chaque passage : ajoutez au titre la date du document, lue dans sa première ligne, pour que la réponse puisse dire laquelle des deux règles est la plus récente.
- Le sens et les mots : une recherche par mots, comme BM25, retrouve les termes exacts que le sens rate ; les deux se combinent.
- Le calcul en Europe : le point d'accès par défaut de Mistral ne s'engage pas sur le lieu du calcul ;
api.eu.mistral.aile garde en Europe, facturé 1,1 fois le tarif. - Garder les vecteurs : le programme les recalcule à chaque lancement ; une base de vecteurs les garde, et c'est l'objet de la page des embeddings.
- Mesurer : vingt questions dont vous connaissez le passage attendu, et le nombre de fois où il arrive parmi les trois premiers ; voir l'évaluation d'un outil d'IA.
Lectures suivantes
Un RAG minimal en Python
Limites et sources
Le code des étapes 2 à 4 est vérifié contre la documentation de Mistral du 7 octobre 2026 et la version 3.1.0 de sa bibliothèque ; il n'a pas encore été exécuté par Meridal, et sa sortie s'ajoutera après le premier essai.
Ce programme garde tout en mémoire et recalcule les vecteurs à chaque lancement : il sert à comprendre, pas à servir une équipe.
- Mistral, Text Embeddings ; RAG Quickstart ; Send your first API request ; Regional inference.
- Le relevé complet :
apprendre/recherches/2026-10-07-rag-technique.json.
Écrit par Meridal, avec l'aide de l'IA ; chaque fait vérifié à sa source et relu avant publication. Texte et schémas sous licence CC BY 4.0 : reprenez-les en citant Meridal. Le code sous licence MIT.
Un assistant qui connaît votre entreprise
3 300 € à 10 200 €, puis sur devis