---
title: "Un RAG minimal en Python"
description: "Découper, ranger par sens, chercher, répondre en citant : le code, étape par étape."
url: https://meridal.fr/apprendre/rag-minimal-python/
language: fr
written: 2026-10-07
verified: 2026-10-07
license: CC BY 4.0
---

[Apprendre](https://meridal.fr/apprendre/) › [Vos documents](https://meridal.fr/apprendre/dossier/documents/)

S'exercer · Niveau 3, Construire · 25 minutes

# Un RAG minimal en Python

Le mécanisme du RAG écrit en Python, étape par étape : découper trois documents en passages, ranger chaque passage par son sens, retrouver les plus proches d'une question, puis faire répondre le modèle en citant ses passages.

Écrit le 7 octobre 2026 · Vérifié le 7 octobre 2026

## Vous saurez

- Découper des documents en passages qui gardent leur titre
- Calculer et comparer des vecteurs de sens
- Retrouver les passages d'une question, et faire citer la réponse
- Repérer ce qui fait rater un RAG, et où l'améliorer

## Dans le parcours

[L'IA sur vos documents](https://meridal.fr/apprendre/parcours/documents/)

Pour finir le parcours

Aussi dans : [Construction](https://meridal.fr/apprendre/rag-minimal-python/), [Premiers pas en développement](https://meridal.fr/apprendre/rag-minimal-python/)

- [← Avant Le RAG : une IA qui répond avec les documents de l'entreprise](https://meridal.fr/apprendre/rag/)
- [↑ Plus général La recherche par le sens](https://meridal.fr/apprendre/recherche-par-le-sens/)
- [↓ Plus concret Atelier : interroger vos documents sans programmer](https://meridal.fr/apprendre/atelier-documents/)
- [→ Le parcours suivant Automatisation d'une tâche](https://meridal.fr/apprendre/parcours/automatiser/)

Rappel de la page précédente

Répondez de tête, puis ouvrez. [Le RAG : une IA qui répond avec les documents de l'entreprise](https://meridal.fr/apprendre/rag/)

**1 Un 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.

**2 Votre é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.

L'essentiel

1. Un RAG tient en quatre étapes : découper, ranger par le sens, chercher, répondre en citant.
2. Ranger par le sens, c'est transformer chaque passage en une liste de nombres, un vecteur ; deux textes proches ont des vecteurs proches.
3. La recherche ne lit pas : elle compare des vecteurs, et rapporte les passages les plus proches de la question.
4. 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.
5. 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](https://meridal.fr/apprendre/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.

Avant de commencer : un poste prêt, avec uv et une clé d'API de Mistral rangée dans un fichier .env, comme dans [la page du poste de développement](https://meridal.fr/apprendre/poste-de-developpement/).

## 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 vente Texte Markdown, 2 Ko · huit articles, dont un tableau [Télécharger](https://meridal.fr/assets/apprendre/fichiers/atelier-documents/conditions-generales-de-vente.md)

  **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.

  | 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 client Texte Markdown, 1 Ko · cinq étapes [Télécharger](https://meridal.fr/assets/apprendre/fichiers/atelier-documents/procedure-ouverture-de-compte.md)

  **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 2026 Texte Markdown, 1 Ko · une règle qui déroge aux conditions générales [Télécharger](https://meridal.fr/assets/apprendre/fichiers/atelier-documents/note-direction-financiere-mars-2026.md)

  **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

![Une fois : les trois documents, découpés en 14 passages par decouper.py, puis rangés par le sens, chaque passage en un vecteur de 1 024 nombres, par ranger.py. À chaque question : la question devient un vecteur ; on garde les trois passages au plus grand produit scalaire ; le modèle répond à partir d'eux seuls, en citant leurs numéros, ou dit que la réponse n'y est pas.](https://meridal.fr/assets/apprendre/medias/apprendre-rag-minimal.svg)

*Le programme de l'exercice, étape par étape, avec ses fichiers.*

### Le projet

`Terminal`

```
uv 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.py`

```
import 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])
```

La sortie`uv run decouper.py`

```
conditions-generales-de-vente.md : 8 passages
note-direction-financiere-mars-2026.md : 1 passage
procedure-ouverture-de-compte.md : 5 passages
En tout : 14 passages
---
Conditions générales de vente, 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é.
```

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.py`

```
import 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)
```

La sortie`uv run ranger.py`

**Pas 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, suite`

```
def 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])
```

La sortie`uv run ranger.py`

**Pas 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, fin`

```
CONSIGNE = (
    "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")
```

La sortie`uv run ranger.py`

**Pas 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

- L'étape 1 affiche 14 passages, dont un pour la note
- Pour les questions a à d, le passage attendu (correction commentée) est parmi les trois trouvés
- La réponse b donne 30 jours pendant six mois, et cite la note une réponse à 45 jours a reçu l'article 6 sans la note
- La réponse e dit que les extraits ne donnent pas de délai chiffré tout nombre de jours est inventé
- Chaque réponse cite le numéro de ses extraits

## Indications

**« KeyError: 'MISTRAL_API_KEY' »**

**Cause**La clé n'est pas dans l'environnement : pas de fichier .env, ou `load_dotenv()` appelé trop tard.

**À faire**Vé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**

**Cause**Avec 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 »**

**Cause**L'appel des embeddings de Mistral attend `inputs`, au pluriel.

**À faire**Passez une liste à `inputs=`, même pour une seule question.

**La question d ne trouve pas l'article 7**

**Cause**Le passage est un tableau : son vecteur rend mal ce que disent ses cases.

**À faire**Ajoutez au document une phrase qui dit ce que contient le tableau, et relancez.

**La réponse ne cite aucun numéro**

**Cause**Le modèle n'a pas suivi la consigne.

**À faire**Placez 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écoupage**Une 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.ai` le 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](https://meridal.fr/apprendre/embeddings-et-bases-vectorielles/).
- **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](https://meridal.fr/apprendre/evaluer-un-outil-d-ia/).

## Lectures suivantes

↑ Plus général [La recherche par le sens Comprendre · Niveau 3 · 12 minutes](https://meridal.fr/apprendre/recherche-par-le-sens/)

← Avant [Le RAG : une IA qui répond avec les documents de l'entreprise Comprendre · Niveau 1 · 12 minutes](https://meridal.fr/apprendre/rag/)

Vous êtes ici

Un RAG minimal en Python

→ Le parcours suivant [Automatisation d'une tâche Niveaux 2 et 3](https://meridal.fr/apprendre/parcours/automatiser/)

↓ Plus concret [Atelier : interroger vos documents sans programmer S'exercer · Niveau 2 · 20 minutes](https://meridal.fr/apprendre/atelier-documents/) [Une base de savoir que l'assistant consulte avant de répondre Réalisation](https://meridal.fr/realisations/base-de-savoir/)

[Tout le dossier « Vos documents »](https://meridal.fr/apprendre/dossier/documents/)

Les pages qui renvoient ici

- [Atelier : interroger vos documents sans programmer](https://meridal.fr/apprendre/atelier-documents/)
- [Liste de contrôle : un assistant sur vos documents](https://meridal.fr/apprendre/avant-de-brancher-un-assistant/)
- [Embeddings et bases vectorielles](https://meridal.fr/apprendre/embeddings-et-bases-vectorielles/)
- [L'appel d'outils](https://meridal.fr/apprendre/appel-d-outils/)
- [La recherche par le sens](https://meridal.fr/apprendre/recherche-par-le-sens/)
- [Le RAG avancé](https://meridal.fr/apprendre/le-rag-avance/)

**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.

1. [Mistral, Text Embeddings](https://docs.mistral.ai/studio/knowledge-rag/embeddings/text_embeddings) ; [RAG Quickstart](https://docs.mistral.ai/studio/knowledge-rag/rag_quickstart) ; [Send your first API request](https://docs.mistral.ai/getting-started/quickstarts/developer/first-api-request) ; [Regional inference](https://docs.mistral.ai/inference/regional-inference).
2. 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](https://creativecommons.org/licenses/by/4.0/deed.fr) : reprenez-les en citant Meridal. Le code sous licence MIT.

Service correspondant

Un assistant qui connaît votre entreprise

3 300 € à 10 200 €, puis sur devis

[Voir le service](https://meridal.fr/offre/#assistant)

## Un premier échange de 30 minutes

En visio et sans frais : vous décrivez votre situation, nous vous indiquons ce qui est réalisable, avec quels outils et pour quel ordre de prix. Vous pouvez aussi nous écrire ; chaque message reçoit une réponse écrite.

[Réserver 30 minutes](https://meridal.fr/contact/#reserver) [Écrire un message](https://meridal.fr/contact/)
