Retrievers Avancés
Améliorez la qualité de récupération avec l'expansion multi-requêtes, la compression contextuelle et les méthodes d'ensemble.
Pourquoi des Retrievers Avancés ?
La recherche vectorielle basique peut manquer des documents pertinents en raison de la formulation de la requête ou des écarts sémantiques. Les retrievers avancés améliorent le rappel et la précision grâce à l'expansion de requêtes, la compression de résultats et les techniques de fusion.
# MultiQueryRetriever
Génère plusieurs requêtes alternatives en utilisant un LLM, récupère les résultats pour chacune et déduplique pour améliorer le rappel.
import { MultiQueryRetriever } from '@orka-js/tools';import { createOrka } from '@orka-js/core';import { OpenAIAdapter } from '@orka-js/openai';import { PineconeAdapter } from '@orka-js/pinecone'; const orka = createOrka({ llm: new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }), vectorDB: new PineconeAdapter({ /* config */ })}); const retriever = new MultiQueryRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], queryCount: 3, // Génère 3 requêtes alternatives topK: 5, // Retourne les 5 meilleurs résultats par requête deduplicateByContent: true // Supprime les résultats en double}); const results = await retriever.retrieve( 'How do I configure Orka JS?', 'my-knowledge-base'); // Returns deduplicated results from all query variationsLogique d'Augmentation du Rappel
Solving Semantic Mismatch via LLM Diversification
Requête d'Origine
Moteur de Variation LLM
Fusion & Classement
# ContextualCompressionRetriever
Récupère plus de documents que nécessaire, puis utilise un LLM pour extraire uniquement les parties pertinentes, améliorant la précision et réduisant la taille du contexte.
import { ContextualCompressionRetriever } from '@orka-js/tools'; const retriever = new ContextualCompressionRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], topK: 10, // Récupère 10 documents maxCompressedLength: 500 // Compresse chaque document à ~500 caractères}); const results = await retriever.retrieve( 'What are the benefits of RAG?', 'my-knowledge-base'); // Chaque résultat contient uniquement l'extrait pertinent, pas le document completRécupération Standard
Surcharge Documentaire
Gaspille 70-80% de la fenêtre de contexte avec du 'bruit' (headers, paragraphes inutiles).
Sortie Compressée
Haute Densité de Signal
Ne retourne que les pépites d'info. Réduit les coûts et améliore drastiquement la précision.
# EnsembleRetriever
Combine plusieurs retrievers en utilisant Reciprocal Rank Fusion (RRF) pour de meilleurs résultats. Utile pour combiner différentes stratégies de récupération.
import { EnsembleRetriever } from '@orka-js/tools';import { VectorRetriever } from '@orka-js/tools';import { MultiQueryRetriever } from '@orka-js/tools'; // Créez des retrievers individuelsconst vectorRetriever = new VectorRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], topK: 10}); const multiQueryRetriever = new MultiQueryRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], queryCount: 3, topK: 10}); // Combine avec fusion pondéréeconst ensemble = new EnsembleRetriever({ retrievers: [vectorRetriever, multiQueryRetriever], weights: [0.4, 0.6], // 40% vector, 60% multi-query topK: 5 // Retourne les 5 meilleurs résultats fusionnés}); const results = await ensemble.retrieve( 'Expliquez l'architecture RAG', 'ma-base-de-connaissances');🔬 Reciprocal Rank Fusion (RRF)
RRF combine les classements de plusieurs sources en donnant des scores plus élevés aux documents qui apparaissent en haut de plusieurs retrievers.
// Formule: score = weight * (1 / (rank + 60)// Document à la position 1 dans Retriever A: 0.4 * (1/61) = 0.0066// Même document à la position 3 dans Retriever B: 0.6 * (1/63) = 0.0095// Score de fusion final: 0.0066 + 0.0095 = 0.0161# VectorRetriever
Wrapper de recherche vectorielle basique qui implémente l'interface Retriever. Utile comme bloc de construction pour les retrievers d'ensemble.
import { VectorRetriever } from '@orka-js/tools'; const retriever = new VectorRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], topK: 5, minScore: 0.7 // Filtre les résultats avec une similarité inférieure à 0.7}); const results = await retriever.retrieve( 'What is RAG?', 'my-knowledge-base');# ParentDocumentRetriever
Recherche sur de petits chunks enfants pour la précision, puis retourne le document parent complet pour le contexte. Cela résout le compromis classique : les petits chunks sont meilleurs pour la précision de recherche, mais les grands chunks fournissent plus de contexte au LLM.
import { ParentDocumentRetriever } from '@orka-js/tools'; const retriever = new ParentDocumentRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], childTopK: 10, // Recherche des 10 chunks enfants les plus pertinents parentTopK: 3, // Retourne les 3 documents parents les plus pertinents minScore: 0.6});const results = await retriever.retrieve( 'How does authentication work?', 'documentation'); // Retourne les documents parents complets, classés par score de chunk enfant le plus pertinent// Chaque résultat inclut les métadonnées: { childCount, parentContent, ... }Indexation Granulaire
Découpage en petits snippets. Chaque fragment stocke l'ID du document Parent pour reconstruction future.
Step 1: IndexSmall ChunksRecherche Vectorielle
Recherche sémantique sur les petits chunks pour trouver la correspondance exacte sans bruit.
Step 2: SearchChild SearchAssociation Parentale
Consolide les chunks enfants trouvés par leur ID Parent. Regroupe les fragments en unités logiques.
Step 3: GroupMetadata JoinExpansion de Contexte
Retourne le contenu parent complet du meilleur enfant, offrant au LLM un contexte exhaustif.
Step 4: ExpandFull Retrieval# SelfQueryRetriever
Utilise un LLM pour extraire automatiquement des filtres de métadonnées à partir de requêtes en langage naturel. Au lieu d'une simple recherche sémantique, il combine la recherche basée sur le sens avec le filtrage structuré de métadonnées pour des résultats plus précis.
import { SelfQueryRetriever } from '@orka-js/tools'; const retriever = new SelfQueryRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], topK: 5, metadataFields: [ { name: 'category', type: 'string', description: 'La catégorie du document', enumValues: ['tutorial', 'api-reference', 'guide', 'changelog'] }, { name: 'language', type: 'string', description: 'Langage de programmation', enumValues: ['typescript', 'python', 'javascript'] }, { name: 'version', type: 'number', description: 'Le numéro de version de la documentation' } ]}); // Requête en langage naturel avec filtres implicitesconst results = await retriever.retrieve( 'Montre-moi les tutoriels TypeScript sur l'authentification dans la version 3', 'documentation'); // Le LLM extrait :// semanticQuery: "authentication"// filter: { language: "typescript", category: "tutorial", version: 3 }Exemple de Décomposition de Requête
Le LLM sépare automatiquement le sens sémantique des filtres structurés :
// User query: "Find Python guides about deployment from 2024"// Le LLM extrait :{ "semanticQuery": "deployment", "filter": { "language": "python", "category": "guide" }}# BM25Retriever
Un retriever basé sur les mots-clés utilisant l'algorithme BM25 (Best Matching 25). Contrairement à la recherche vectorielle qui repose sur la similarité sémantique, BM25 utilise la fréquence des termes et la fréquence inverse des documents pour la correspondance exacte de mots-clés. Parfait pour combiner avec la recherche vectorielle dans un EnsembleRetriever.
import { BM25Retriever } from '@orka-js/tools'; const bm25 = new BM25Retriever({ documents: [ { id: '1', content: 'TypeScript est un sur-ensemble typé de JavaScript...', metadata: { source: 'docs' } }, { id: '2', content: 'Les hooks React vous permettent d'utiliser l'état dans les composants fonctionnels...', metadata: { source: 'blog' } }, { id: '3', content: 'Node.js est un runtime JavaScript construit sur Chrome V8...', metadata: { source: 'docs' } }, ], topK: 5, k1: 1.5, // Saturation de la fréquence des termes (par défaut: 1.5) b: 0.75 // Normalisation de la longueur des documents (par défaut: 0.75)}); const results = await bm25.retrieve('runtime JavaScript', 'any');// Trouve les documents avec correspondance exacte pour "JavaScript" et "runtime" // Ajoute plus de documents dynamiquementbm25.addDocuments([ { id: '4', content: 'Deno est un runtime JavaScript/TypeScript moderne...' }]);# BM25 + Recherche Vectorielle (Hybride)
La stratégie de récupération la plus puissante combine BM25 (correspondance de mots-clés) avec la recherche vectorielle (compréhension sémantique) via l'EnsembleRetriever :
import { EnsembleRetriever } from '@orka-js/tools';import { VectorRetriever } from '@orka-js/tools';import { BM25Retriever } from '@orka-js/tools'; // Récupération basée sur les mots-clésconst bm25 = new BM25Retriever({ documents: myDocuments, topK: 10}); // Récupération sémantiqueconst vector = new VectorRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], topK: 10}); // Hybride : combine les deux avec Fusion du Rang Réciproqueconst hybrid = new EnsembleRetriever({ retrievers: [bm25, vector], weights: [0.3, 0.7], // 30% keyword, 70% semantic topK: 5}); const results = await hybrid.retrieve('middleware d'authentification', 'docs');// Trouve les documents correspondant aux mots-clés ET sémantiquement similairesComparaison
| Stratégie de Retrieval | Force Principale | Compromis Architecture |
|---|---|---|
MultiQueryCreative | Rappel Max | Latence / Tokens ++ |
CompressionClean | Ultra-Précision | Overhead LLM |
EnsembleRobust | Puissance Hybride | Traitement Multi-passes |
VectorBaseline | Latence < 50ms | Dérive Sémantique |
ParentDocContext | Contexte Riche | Complexité Stockage |
SelfQueryLogic | Filtrage Intelligent | Dépendance au Schéma |
BM25Classic | Match Exact | Zéro Sémantique |
Exemple Complet
import { createOrka } from '@orka-js/core';import { OpenAIAdapter } from '@orka-js/adapters';import { PineconeAdapter } from '@orka-js/adapters';import { MultiQueryRetriever, ContextualCompressionRetriever, EnsembleRetriever } from '@orka-js/tools'; const orka = createOrka({ llm: new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }), vectorDB: new PineconeAdapter({ /* config */ })}); // Stratégie 1: Multi-query pour un meilleur recallconst multiQuery = new MultiQueryRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], queryCount: 3, topK: 10}); // Stratégie 2: Compression pour une meilleure précisionconst compression = new ContextualCompressionRetriever({ llm: orka.getLLM(), vectorDB: orka.knowledge['vectorDB'], topK: 15, maxCompressedLength: 400}); // Combine les deux stratégiesconst ensemble = new EnsembleRetriever({ retrievers: [multiQuery, compression], weights: [0.5, 0.5], topK: 5}); // Récupère avec le meilleur des deux mondesconst results = await ensemble.retrieve( 'How does RAG improve LLM responses?', 'documentation'); console.log(`Found ${results.length} highly relevant results`);results.forEach(r => { console.log(`Score: ${r.score.toFixed(3)}`); console.log(`Content: ${r.content?.slice(0, 100)}...`);});Bonnes Pratiques
1. Commencez Simple
Commencez avec VectorRetriever. Ajoutez MultiQuery si le rappel est faible. Ajoutez Compression si la précision est faible.
2. Surveillez les Coûts
MultiQuery et Compression font des appels LLM supplémentaires. Utilisez le cache ou limitez le nombre de requêtes en production.
3. Ajustez les Poids
Expérimentez avec les poids d'ensemble selon votre cas d'usage. Poids plus élevé = plus d'influence sur le classement final.
Imports Tree-shakeable
// ✅ Importez uniquement ce dont vous avez besoinimport { MultiQueryRetriever } from '@orka-js/tools';import { EnsembleRetriever } from '@orka-js/tools'; // ✅ Ou importez depuis l'indeximport { MultiQueryRetriever, ContextualCompressionRetriever } from '@orka-js/tools';