Plugin Discourse RAG (grain post, rerank cross-encoder, citations whitelistées, gate déterministe, réécriture de requête multi-tour) + documentation du chantier (design, éval, sécurité, pipeline). Export sanitisé depuis le monorepo privé via scripts/export_rag_public.py (aucun endpoint interne, IP, compte démo ou chemin d'infrastructure). WIP : agent en test sur groupe restreint, pas encore public sur le forum.
123 lines
6.1 KiB
Markdown
123 lines
6.1 KiB
Markdown
# Références — techniques RAG éprouvées (notes de lecture)
|
||
|
||
> Objectif : qu'est-ce que l'industrie fait, et qu'est-ce qui s'applique à
|
||
> notre cas (forum francophone, ~425k posts, megathreads, LLM local 30B).
|
||
|
||
## 1. Contextual Retrieval — Anthropic (sept. 2024)
|
||
|
||
**Source** : anthropic.com/engineering/contextual-retrieval · cookbook :
|
||
`claude-cookbooks/capabilities/contextual-embeddings`
|
||
|
||
- **Problème** : un chunk sorti de son document perd son contexte →
|
||
le retriever ne peut pas juger sa pertinence.
|
||
- **Méthode** : avant d'embedder chaque chunk, un LLM génère 1-2 phrases
|
||
qui le situent (« ce chunk est issu de X et traite de Y »), préfixées
|
||
au texte. Idem pour l'index BM25.
|
||
- **Résultats rapportés** : −35 % d'échecs de retrieval top-20 (embeddings
|
||
contextualisés seuls) → **−49 %** avec BM25 contextuel → **−67 %** en
|
||
ajoutant un reranker cross-encoder.
|
||
- **Coût** : ~1,02 $ / Mtok de contexte généré (avec prompt caching).
|
||
|
||
**Chez nous** : la version LLM (C4) coûte 1 appel × ~350k posts = cher pour
|
||
un lab. La version **gratuite** (C1-C3 : titre + OP + parent) capture la
|
||
même idée — *situuer le chunk*. À mesurer si le blurb LLM ajoute encore
|
||
quelque chose au-delà.
|
||
|
||
## 2. « Retrieve small, synthesize big » — sentence-window / parent-document
|
||
|
||
**Sources** : LlamaIndex SentenceWindowRetriever · LangChain
|
||
ParentDocumentRetriever · survey small-to-big
|
||
|
||
- **Principe** : *désolidariser l'unité de recherche de l'unité de
|
||
génération*. On embedde du petit (phrase/message → précision) ; quand ça
|
||
matche, on donne au LLM du plus grand (fenêtre de voisinage / parent).
|
||
- **Sentence-window** : embedde 1 phrase, lit phrase ± N voisines
|
||
(`window_size=3` par défaut).
|
||
- **Parent-document** : embedde les chunks enfants, retourne le parent
|
||
(document/section) via `parent_id` stocké en métadonnée.
|
||
- **Auto-merging** : variante hiérarchique — promeut au parent quand un
|
||
ratio de frères est atteint.
|
||
|
||
**Chez nous** : notre structure naturelle post→topic est exactement
|
||
parent/enfant. Retrieval au post (petit), evidence = post + voisinage ±N
|
||
+ titre/OP (grand). C'est notre config `D`.
|
||
|
||
## 3. Hybrid search + Reciprocal Rank Fusion (RRF)
|
||
|
||
**Sources** : Cormack, Clarke & Buettcher, *SIGIR 2009* (« RRF outperforms
|
||
Condorcet and individual rank learning methods ») · guides Elastic/etc.
|
||
|
||
- **Pourquoi hybride** : BM25 excelle sur l'exact (noms propres, marques,
|
||
termes rares) ; le dense excelle sur la paraphrase/le concept. Aucun ne
|
||
gagne partout — benchmark WANDS : hybride +7,4 % NDCG vs le meilleur seul.
|
||
- **RRF** : `score(d) = Σ 1/(k + rank_i(d))` sur chaque liste, `k=60`
|
||
standard. Ignore les scores bruts (BM25 non borné vs cosine [-1,1]
|
||
incommensurables) — fusionne par **rang**, pas par score.
|
||
- Pas de tuning nécessaire pour battre la moyenne pondérée.
|
||
|
||
**Chez nous** : la fusion actuelle est un scoring custom (base rank +
|
||
bonus). RRF est le standard — config à comparer en A/B. Notre Search
|
||
Discourse joue le rôle de BM25 (Postgres full-text).
|
||
|
||
## 4. Reranking cross-encoder
|
||
|
||
- Un bi-encoder (bge-m3) compare q et d **séparément** (rapide, indexable).
|
||
- Un cross-encoder prend `(query, doc)` **ensemble** → score de pertinence
|
||
fin, mais coûteux → on ne l'applique qu'au top ~50-150 fusionné.
|
||
- Modèles : `bge-reranker-v2-m3` (famille BGE, multilingue, ~2 Go),
|
||
Cohere Rerank (API). Chez Anthropic : le rerank passe de −49 % à −67 %.
|
||
|
||
**Chez nous** : étape optionnelle `E`. Un bge-reranker-v2-m3 tourne sur
|
||
CPU/iGPU mini PC ou laptop. À tester seulement après D — c'est un
|
||
multiplicateur, pas le fondement.
|
||
|
||
## 5. Évaluation — RAGAS et métriques par couche
|
||
|
||
**Source** : RAGAS (EACL 2024 demo) — ragas.io / explodinggradients
|
||
|
||
Le principe structurant : **séparer les métriques retrieval des métriques
|
||
de génération** — une réponse fidèle sur un mauvais contexte reste un échec.
|
||
|
||
| Métrique | Couche | Mesure |
|
||
|---|---|---|
|
||
| Context recall | retrieval | les docs attendus sont-ils dans le top-k ? |
|
||
| Context precision | retrieval | les docs remontés sont-ils pertinents ? |
|
||
| Faithfulness | génération | les claims de la réponse sont-elles supportées par le contexte ? |
|
||
| Answer relevance | génération | la réponse adresse-t-elle la question ? |
|
||
|
||
- LLM-as-judge = standard pour faithfulness/relevance ; context recall
|
||
peut être non-LLM si on a les golden docs.
|
||
- Taille typique d'un eval set : 50-200 Q pour du suivi continu ;
|
||
15-20 questions bien choisies suffisent pour itérer vite.
|
||
|
||
**Chez nous** : jeu custom `EVAL.md` — golden = fils/messages attendus
|
||
connus du forum. Faithfulness partiellement garantie par le sanitizer
|
||
(URLs whitelist) ; ce qu'on mesure surtout = **context recall**
|
||
(le bon fil/message remonte-t-il ?) et **pertinence des citations**.
|
||
|
||
## 6. Ce qu'on fait déjà — et que la littérature valide
|
||
|
||
| Pratique maison | Statut littérature |
|
||
|---|---|
|
||
| Retrieval serveur, tools LLM `[]` | Équivalent « evidence injection » ; limite les tool-call failures |
|
||
| `[[n]]` → URLs whitelist serveur | Anti-hallucination : le LLM ne génère jamais d'identifiant |
|
||
| HyDE off | Choix défendable : HyDE coûte 1 appel LLM et peut dériver ; à réévaluer éventuellement |
|
||
| Abstention si 0 preuve | Standard — le bot ne doit pas répondre sans contexte |
|
||
| temp 0 | Standard pour la fidélité |
|
||
|
||
## 7. Techniques connues, non retenues d'office
|
||
|
||
| Technique | Pourquoi pas maintenant |
|
||
|---|---|
|
||
| HyDE / multi-query expansion | Coût LLM par requête ; réévaluer si recall insuffisant |
|
||
| Matryoshka (dims réduites) | bge-m3 n'est pas Matryoshka — dims fixes 1024 |
|
||
| Chunking sémantique (split par sens) | Notre « chunk » = le post, frontière naturelle |
|
||
| GraphRAG / knowledge graph | Surdimensionné pour un forum |
|
||
| Fine-tuning embeddings | Étape possible un jour (MTEB/custom), pas avant la baseline |
|
||
|
||
## Liens
|
||
|
||
- Anthropic Contextual Retrieval : https://www.anthropic.com/engineering/contextual-retrieval
|
||
- Cormack et al. 2009 (RRF) : SIGIR — « Reciprocal Rank Fusion outperforms Condorcet… »
|
||
- RAGAS : https://arxiv.org/abs/2309.15217
|
||
- LlamaIndex sentence-window : docs.llamaindex.ai (pack SentenceWindowRetriever)
|