Bonjour,
Je suis en phase d’apprentissage sur un projet d’agent documentaire IA, donc je cherche à comprendre la bonne logique et les bonnes pratiques, pas seulement une correction rapide.
Je travaille sur un agent documentaire basé sur FastAPI, LangChain et PGVector.
Le système indexe des documents PDF dans PGVector, puis l’agent doit répondre aux questions à partir des chunks retrouvés.
J’ai constaté le problème suivant :
- Pour un document Power BI, la recherche fonctionne bien si j’ajoute des mots-clés spécifiques comme “Gateway”, “Power BI”,
- Pour un document LIASE, la recherche échoue parfois si la question utilisateur n’utilise pas les mêmes mots que le document.
- Par exemple, la question “profils et rôles des techniciens” ne retrouve pas toujours le bon chunk, alors que le contenu existe bien en base avec d’autres termes comme “statut”, “attribué”, “technicien”, “ticket”.
Aujourd’hui, j’ai testé une logique avec des conditions du type :
if “LIASE” in question:
enrichissement LIASE
elif “power bi” in question:
enrichissement Power BI
Mais cette solution n’est pas maintenable, car il faudrait ajouter une règle pour chaque nouveau document.
Ma question est donc :
quelle est la meilleure approche pour rendre le retrieval dynamique, quel que soit le document ?
Je cherche notamment à savoir s’il vaut mieux utiliser :
- une recherche vectorielle large avec top-k plus élevé ;
- une recherche hybride vectorielle + mots-clés SQL ;
- un reranking des chunks ;
- une extraction automatique des mots-clés de la question ;
- un filtrage par métadonnées source/document ;
- ou une autre architecture recommandée avec LangChain et PGVector.
Stack utilisée :
- FastAPI
- LangChain / LangGraph
- PGVector
- PostgreSQL
- PDF parsés puis indexés
- LLM via endpoint compatible OpenAI
Merci d’avance pour vos conseils. Je suis preneuse d’explications pédagogiques, car je suis encore en apprentissage sur les architectures RAG.
Good instinct: the problem isn’t your rules — it’s your retrieval pipeline. The if/elif conditions are a band-aid over a recall problem. Here’s how to make retrieval dynamic, in priority order.
First thing I’d look into: which embedding model are you using? Is it one that handles French well? An English-centric model can sometimes miss semantic matching in other languages — so this is worth checking before anything else, because it’s free and fast to test.
A few French-appropriate options to consider:
- BGE-M3 — multilingual, and natively outputs dense + sparse vectors, so it’s ideal for hybrid search. Self-hostable.
- Solon-embeddings-large — French-specialized, tops the French MTEB leaderboard.
- multilingual-e5-large — a solid, easy-to-deploy baseline.
- OpenAI text-embedding-3-large — easiest drop-in since you already have an OpenAI-compatible endpoint (good on French, not the best).
- Worth comparing them yourself on the MTEB French leaderboard.
Then stack these 4 layers — don’t pick one:
- Hybrid search (vector + keyword). Your failing case shares the word “technicien” between question and doc: a lexical retriever (BM25 / Postgres full-text) catches that for free, while the vector side handles rephrasing. This is your biggest win. →
EnsembleRetriever.
- LLM query rewriting. This replaces your
if/elif. Two forms: multi-query (generate 3–5 rephrasings of the question) or HyDE (generate a hypothetical answer, then embed that). → MultiQueryRetriever.
- Reranking. A cross-encoder re-scores the retrieved chunks for final precision (e.g. bge-reranker, Cohere Rerank).
- Higher top-k upstream. Retrieve broadly (20–40 chunks), let the reranker decide.
How they fit together at query time (numbers map to the priority list — they run in a different order than they rank):
User question
|
v
+-----------------------------+
| 2. Query rewriting (LLM) | multi-query / HyDE -> 3-5 variants
+-----------------------------+
|
v
+-----------------------------+
| 1. Hybrid retrieval | 4. retrieve top-k 20-40
| Vector -> PGVector |
| Keyword -> BM25 / FTS |
+-----------------------------+
| merged candidates
v
+-----------------------------+
| 3. Reranking (cross-encoder)| -> keep top 4-6
+-----------------------------+
|
v
LLM answer
What I’d skip for now: filtering by source/document metadata. It’s useful for targeting a specific doc, but it won’t fix your vocabulary problem.
Bottom line: confirm a French-capable embedding model → hybrid → rewriting → reranking. Test layer by layer to see what actually moves recall.
Good luck — you’re asking exactly the right questions. 
Merci beaucoup pour votre retour détaillé et pour les pistes d’amélioration proposées.
Pour précision, le modèle d’embedding actuellement utilisé dans le projet est llamacpp-mxbai-embed-large-1. Je vais donc commencer par évaluer son comportement sur notre corpus en français, puis comparer ses résultats avec des modèles davantage orientés français ou multilingues.
Votre analyse sur le rappel, la recherche hybride, la réécriture de requêtes et le reranking clarifie bien les axes d’amélioration à prioriser. Merci encore pour votre aide et pour ces recommandations très concrètes.