Document entier ou RAG : mesurer pour choisir
Deux stratégies
- Contexte long : on met le document entier dans la requête. Simple, aucun index à construire, le modèle voit tout (y compris les règles générales qui s'appliquent à tous les produits).
- RAG (Retrieval-Augmented Generation, génération augmentée par la recherche) : on découpe le document en passages, on cherche les plus pertinents pour la question, et on n'envoie qu'eux.
flowchart TB Q["Question sur AT-1137"] --> L["Contexte long : catalogue entier, 8 149 tokens"] Q --> R["RAG : BM25 sur 160 passages"] R --> P["3 passages + conditions générales"] L --> M1["Gemini"] P --> M2["Gemini"] M1 --> C["Comparer : exactitude, tokens, latence"] M2 --> C
Ici la recherche est lexicale (BM25, un classement par mots communs pondérés par leur rareté), pas sémantique : pour un identifiant exact comme « AT-1137 », la correspondance de mots est imbattable, et elle ne coûte aucun appel d'API.
def bm25_top(chunks, query, k=3):
tok = lambda s: s.lower().replace(":", " ").replace(".", " ").split()
scores = BM25Okapi([tok(c) for c in chunks]).get_scores(tok(query))
return [chunks[i] for i in sorted(range(len(chunks)), key=lambda i: -scores[i])[:k]]
head = doc.split("## Produits")[0] # les conditions générales, toujours utiles
passages = "\n".join(bm25_top(catalogue.chunks(), QUESTION))
show("RAG (BM25, 3 passages)", ask(c, f"{head}\n{passages}\n\nQuestion : {QUESTION}"))Pourquoi le RAG du lab ajoute-t-il l'en-tête du catalogue aux 3 passages trouvés ?
La question combine une donnée produit (prix, entrepôt) et une règle générale (express depuis Lyon uniquement). Sans la règle, le modèle ne peut pas répondre correctement à la seconde partie.
Résultat obtenu
Exécution réelle du 2026-10-15 (gemini-3.5-flash), question : « Quel est le prix et l'entrepôt d'expédition de la référence AT-1137 ? Et la livraison express est-elle possible ? »
Document : 23042 caractères, 8149 tokens
document entier 2.62 s | entrée 8184 (dont cache 0) | sortie 79 | "Pour la référence **AT-1137** :\n\n* **Prix :** 821 euros TTC\n* **Entrepôt d'expédition :** Nantes\n* **Livraison express :"
RAG (BM25, 3 passages) 3.9 s | entrée 234 (dont cache 0) | sortie 84 | "Voici les informations concernant la référence **AT-1137** :\n\n* **Prix :** 821 euros TTC.\n* **Entrepôt d'expédition :** "Les deux réponses sont exactes (821 euros, Nantes, et pas d'express puisque le produit ne part pas de Lyon). Le RAG a utilisé 35 fois moins de tokens d'entrée. Il n'a pas été plus rapide sur cet essai unique (3,9 s contre 2,62 s) : à ces tailles, la latence dépend surtout de la charge du service. Comme toujours, une mesure isolée n'est pas une moyenne.
Quand choisir quoi
| Situation | Plutôt | Pourquoi |
|---|---|---|
| Un document moyen, beaucoup de questions transverses (« résume », « compare ») | contexte long + cache | le modèle a besoin de tout voir |
| Une base qui grandit (des milliers de pages) | RAG | ne tient plus dans la fenêtre, ou coûte trop |
| Questions pointues sur des identifiants | RAG lexical ou hybride | correspondance exacte, coût minimal |
| Prototype, peu de questions | contexte long | zéro infrastructure |
| Exigence de citer la source | RAG | on sait quels passages ont servi |
Votre base documentaire fait 3 millions de tokens et grossit chaque semaine. Que choisissez-vous ?
3 millions de tokens dépassent la fenêtre, et le contenu change souvent. Le RAG sélectionne les passages utiles ; le cache peut servir pour un sous-ensemble stable (un règlement, une FAQ) interrogé en permanence.
Exercice : la question transverse
Posez au RAG la question « Quel est le produit le moins cher expédié depuis Lyon ? ». Que va-t-il se passer, et comment le corriger ?
Voir la solution
BM25 va remonter 3 passages qui contiennent « Lyon » (et « produit », « expédié »), choisis par score de mots et non par prix. Le modèle répondra avec le moins cher des 3, pas du catalogue : réponse fausse, mais plausible.
Corrections possibles :
- Reconnaître que c'est une question d'agrégation : c'est un filtre et un tri (
min(p for p in products() if p["entrepot"] == "Lyon")), à faire en code ou en SQL, exposé au modèle comme un outil. - Ou basculer vers le contexte long (8 000 tokens, avec cache) pour ce type de question.
Le RAG répond bien aux questions dont la réponse tient dans quelques passages ; il répond mal à celles qui demandent de parcourir tout le corpus.
Je sais faire
- Comparer document entier et RAG sur la même question, avec des mesures
- Accompagner les passages des règles transverses nécessaires
- Choisir une recherche lexicale pour des identifiants exacts
- Reconnaître une question d'agrégation que le RAG traitera mal