Pourquoi la vitesse de recherche est importante pour les agents IA et l'ingénierie du contexte
Sur un corpus de 20 millions de documents, nos benchmarks révèlent qu’Elasticsearch multiplie par 8 le débit d’OpenSearch en recherche vectorielle filtrée, avec un Recall@100 supérieur dans toutes les configurations évaluées. L’ingénierie de contexte va au-delà de la performance brute de la récupération vectorielle. Une pertinence maîtrisée (recherche hybride, filtrage), une exploitation simplifiée et des performances constantes sont tout aussi essentielles pour les équipes lors de l’évolution de leurs workflows. Comme les agents effectuent fréquemment des cycles itératifs de récupération et de raisonnement pour chaque demande, la latence de recherche agit comme un facteur multiplicatif. Toute optimisation ici améliore donc instantanément la réactivité de bout en bout et diminue les coûts d’exploitation.

Graphe 1 : Débit.
Pour l'ingénierie du contexte, la récupération n'est pas une étape unique. Les agents et les applications effectuent de manière répétée des exécutions de boucles, telles que récupérer → raisonner → récupérer, pour affiner les requêtes, vérifier les faits, assembler un contexte étayé et accomplir les tâches. Ce schéma est courant dans les workflows d'agents et la Retrieval-Augmented Generation (RAG) itérative. Comme la récupération peut être sollicitée de nombreuses fois pour une seule requête utilisateur, elle ajoute un délai à la réponse et/ou augmente les coûts d’infrastructure.

Figure 1: L’ingénierie de contexte transforme un vaste réservoir d’informations (documents, mémoire, outils, historique de discussion) en une fenêtre de contexte restreinte pour le modèle de langage (LLM) grâce à des cycles répétés de récupération et de sélection.
L’optimisation de l’ingénierie de contexte s’impose aujourd’hui comme une méthode de pointe en pleine expansion. Le nombre d'itérations varie considérablement selon le workflow. Le principe essentiel qui sous-tend ces résultats est que l’ingénierie de contexte suit une logique directionnelle ; dans un processus de récupération itérative, la latence devient un multiplicateur de temps de réponse.
Pourquoi la performance de la recherche vectorielle est-elle critique ?
Imaginez la réponse d’un assistant d’achat à cette requête : « Il me faut un sac à dos de type bagage à main à moins de 60 $, adapté à un ordinateur de 15 pouces, résistant à l’eau et disponible en livraison d’ici vendredi. »
Dans un environnement de production, il est rare que l’assistant lance une unique recherche vectorielle et en reste là. L’assistant lance une boucle de recherche afin d’élaborer le bon contexte, chaque phase étant soumise à des filtres précis : disponibilité, zone géographique, délais de livraison, image de marque ou encore conformité aux politiques internes.
Étape 1 : interpréter l'intention et traduire en contraintes.
L’agent transforme la requête en filtres structurés et en une recherche sémantique, comme suit :
- Filtres : en stock, livrable à l'utilisateur à son code postal, livraison avant vendredi, prix inférieur à 60 $, annonce valide
- Requête vectorielle : « Sac à dos cabine ordinateur 15 pouces résistant à l’eau »
Étape 2 : récupérer les candidats, puis affiner.
Elle répète souvent la récupération avec des variantes afin de ne pas manquer de bonnes correspondances :
- « sac à dos de voyage cabine compartiment ordinateur »
- « sac à dos de trajet quotidien, résistant à l’eau, ordinateur 15 pouces »
- « sac à dos de cabine léger »
Chaque requête utilise les mêmes filtres d’éligibilité, car récupérer des éléments non pertinents ou indisponibles constitue un gaspillage de contexte.
Étape 3 : Élargir la recherche pour confirmer les détails et réduire les risques.
L’agent effectue une récupération supplémentaire pour valider les attributs déterminants du résultat final :
- Formulation concernant les matériaux et la résistance à l’eau
- Dimensions et compatibilité du compartiment pour ordinateur portable
- Modalités de retour et clauses de garantie
- Options alternatives en cas de stock faible
Ceci est l'ingénierie contextuelle en plusieurs étapes : Récupérer, raisonner, récupérer, assembler.
L’importance de la latence et du rappel dans l’ingénierie de contexte
Ces interactions peuvent impliquer des dizaines d’appels de récupération filtrés par session utilisateur. La latence par appel est donc un multiplicateur direct du temps de réponse de bout en bout, et un faible taux de rappel oblige à des tentatives supplémentaires ou amène l'agent à manquer des éléments éligibles, ce qui dégrade la qualité de la réponse.
À retenir : Dans les systèmes d’ingénierie de contexte, la recherche filtrée des plus proches voisins (ANN) n’est pas une simple requête unique. C’est une suite d’opérations sous contraintes : la performance de la recherche vectorielle se traduit donc directement en termes de latence, de débit et de coûts, alors même que le LLM capte toute l’attention en surface.
Évaluation comparative
Résultats
Dans le graphe 2, chaque point représente une configuration de test. Les performances optimales apparaissent dans le coin supérieur gauche : c’est là que le rappel est le plus important et la latence la plus réduite. Les données d’Elasticsearch se rapprochent davantage du coin supérieur gauche que celles d’OpenSearch, signe d’une vitesse et d’une précision accrues pour une même charge de travail.

Graphe 2 : Rappel par rapport à la latence moyenne, avec un paramètre de rescore de 1.
Quelques informations clés
s_n_r_value: Abréviation poursize_numCandidates_rescoreOversample(k et numCandidates sont égaux à numCandidates dans ces tests) ; par exemple,100_500_1signifie taille=100, candidats=500 et k=500, rescore oversample=1- Rappel : Mesure du Rappel@100 pour cette configuration spécifique
- Latence moyenne (ms) : Temps de réponse moyen de bout en bout par requête
- Débit : requêtes par seconde (QPS)
- Pourcentage de rappel : Amélioration relative du rappel pour Elasticsearch comparativement à OpenSearch ((Elasticsearch - OpenSearch) / OpenSearch)
- Latence Xs : latence moyenne d'OpenSearch divisée par la latence moyenne d'Elasticsearch
- Débit Xs : débit Elasticsearch divisé par le débit OpenSearch
| Moteur | `s_n_r_value` | Rappel | Latence moyenne (ms) | Débit | Rappel % | Latence Xs | Débit Xs |
|---|---|---|---|---|---|---|---|
| Elasticsearch | 100_250_1 | 0,7704 | 25 | 534,75 | 9,70 % | 2,28 | 1,91 |
| OpenSearch | 100_250_1 | 0,7023 | 57,08 | 279,58 | |||
| Elasticsearch | 100_500_1 | 0,8577 | 25,42 | 524,14 | 7,20 % | 2.4 | 2 |
| OpenSearch | 100_500_1 | 0,8001 | 60,9 | 262,12 | |||
| Elasticsearch | 100_750_1 | 0,8947 | 29,67 | 528,09 | 5,72 % | 2,25 | 2,21 |
| OpenSearch | 100_750_1 | 0,8463 | 66,76 | 239,11 | |||
| Elasticsearch | 100_1000_1 | 0,9156 | 29,65 | 534,5 | 4,66 % | 2,46 | 2,44 |
| OpenSearch | 100_1000_1 | 0,8748 | 72,88 | 219,01 | |||
| Elasticsearch | 100_1500_1 | 0,9386 | 31,84 | 497,3 | 3,38 % | 2,71 | 2,68 |
| OpenSearch | 100_1500_1 | 0,9079 | 86,16 | 185,4 | |||
| Elasticsearch | 100_2000_1 | 0,9507 | 34,69 | 457,2 | 2,57 % | 2,98 | 2,96 |
| OpenSearch | 100_2000_1 | 0,9269 | 103,36 | 154,55 | |||
| Elasticsearch | 100_2500_1 | 0,9582 | 37,9 | 418,43 | 1,99 % | 3,28 | 3,26 |
| OpenSearch | 100_2500_1 | 0,9395 | 124,29 | 128,53 | |||
| Elasticsearch | 100_3000_1 | 0,9636 | 41,86 | 379,4 | 1,62 % | 3,46 | 3,44 |
| OpenSearch | 100_3000_1 | 0,9482 | 144,67 | 110,34 | |||
| Elasticsearch | 100_4000_1 | 0,9705 | 50,28 | 316,21 | 1,06 % | 3,87 | 3,85 |
| OpenSearch | 100_4000_1 | 0,9603 | 194,36 | 82,22 | |||
| Elasticsearch | 100_5000_1 | 0,9749 | 58,77 | 270,91 | 0,73 % | 4,43 | 4,41 |
| OpenSearch | 100_5000_1 | 0,9678 | 260,33 | 61,38 | |||
| Elasticsearch | 100_6000_1 | 0,9781 | 66,75 | 238,59 | 0,52 % | 4,91 | 4,89 |
| OpenSearch | 100_6000_1 | 0,973 | 327,44 | 48,81 | |||
| Elasticsearch | 100_7000_1 | 0,9804 | 74,64 | 213,49 | 0,38 % | 5,28 | 5,27 |
| OpenSearch | 100_7000_1 | 0,9767 | 394,24 | 40,53 | |||
| Elasticsearch | 100_8000_1 | 0,9823 | 82,28 | 193,59 | 0,27 % | 6,86 | 6,83 |
| OpenSearch | 100_8000_1 | 0,9797 | 564,14 | 28,33 | |||
| Elasticsearch | 100_9000_1 | 0,9837 | 90,08 | 176,96 | 0,16 % | 7,63 | 7,61 |
| OpenSearch | 100_9000_1 | 0,9821 | 687,25 | 23,25 | |||
| Elasticsearch | 100_10000_1 | 0,9848 | 97,64 | 163,31 | 0,08 % | 8,38 | 8,36 |
| OpenSearch | 100_10000_1 | 0,984 | 818,64 | 19,53 |
Par exemple, à 100_9000_1, OpenSearch enregistre en moyenne 687 millisecondes par extraction, contre 90 millisecondes pour Elasticsearch, et dans une boucle de récupération en 10 étapes, cela représente environ 10 × (687 - 90) = six secondes de temps d’attente supplémentaire.
Découvrez les résultats complets.
Méthodologie
À l’aide de Python pour l’envoi des requêtes et le suivi de la latence ainsi que des données statistiques, nous avons soumis les requêtes suivantes aux moteurs. N’oubliez pas que l’efficacité d’un moteur vectoriel repose sur l’ajustement de ses paramètres clés : le nombre de candidats analysés, le niveau d’agressivité du score de pertinence et la quantité de contexte fournie en retour. Ces configurations agissent directement sur le rappel (l’assurance de ne pas manquer la réponse adéquate) et sur la latence (la vélocité du traitement).
Pour nos tests, nous avons conservé les mêmes réglages de sélection de candidats, de nouveau calcul de score et de dimension de contexte que ceux d’un cycle de récupération itératif, puis nous avons mesuré l’efficacité d’Elasticsearch face à ce volume de données. Par la suite, nous avons testé OpenSearch avec une configuration identique afin d’établir un point de comparaison.
OpenSearch
"size": <RESULT_SIZE>: Nombre de résultats renvoyés au client. Pour ce benchmark, nous avons défini une taille de résultat de 100 pour l’évaluation du Rappel@100."k": <NUMBER_OF_CANDIDATES>: Le nombre de candidats voisins les plus proches."ef_search": <NUMBER_OF_CANDIDATES>: Lle nombre de vecteurs à examiner."oversample_factor": <OVERSAMPLE>: Combien de vecteurs candidats sont récupérés avant réévaluation.
Elasticsearch
"size": <RESULT_SIZE>: Nombre de résultats renvoyés au client. Pour ce benchmark, nous avons défini une taille de résultat de 100 pour l’évaluation du Rappel@100."k": <NUMBER_OF_CANDIDATES>: Nombre de voisins les plus proches à renvoyer de chaque partition."num_candidates": <NUMBER_OF_CANDIDATES>: Nombre de candidats au plus proche voisin à considérer par partition lors d'une opération de rechercheknn."oversample": <OVERSAMPLE>: Combien de vecteurs candidats sont récupérés avant réévaluation.
Exemple
Knn la requête, (100_500_1), serait la suivante :
OpenSearch
Elasticsearch
La configuration complète, ainsi que les scripts Terraform, les manifestes Kubernetes et le code de test de performance, sont disponibles dans ce dépôt dans le dossier es-9.3-vs-os-3.5-vector-search.
Configuration du clustering
Nous avons utilisé six instances cloud de type e2-standard-16 pour nos tests, chacune équipée de 16 vCPUs et de 64 Go de mémoire vive. Nous avons configuré chaque pod Kubernetes hébergeant un node du moteur avec 15 vCPUs et 56 Go de RAM, en réservant 28 Go pour la mémoire de la JVM.
Les tests ont été effectués sur les versions 9.3.0 d’Elasticsearch et 3.5.0 d’OpenSearch. (Lucene 10,3,2). Comme les deux solutions reposent sur la même version de Lucene pour ce test, les écarts de performance constatés au niveau du débit et de la latence ne s’expliquent pas par le moteur de base, mais par la façon dont chaque plateforme orchestre la recherche kNN filtrée et les étapes de calcul de score. Pour ce test, nous avons configuré un index unique comportant trois shards primaires et une réplique (ce qui donne 6 partitions au total, soit 1 par node).
Nous avons par ailleurs mobilisé un serveur séparé, situé dans la même région, afin de faire tourner le client de test et de compiler les données de performance.

Figure 2 : Schéma de la configuration du clustering.
L’ensemble de données
Pour ce test de performance, nous avons exploité un catalogue e-commerce de 20 millions de documents (embeddings), afin de simuler une recherche vectorielle avec filtres à l’échelle d’une application de production.
Chaque document représente un élément de catalogue et comprend :
- Un vecteur dense à 128 dimensions utilisé pour la recherche approximative par kNN.
- Champs de métadonnées structurés servant au filtrage (disponibilité, validité des produits, etc.), afin de simuler la récupération de vecteurs voisins restreinte à une sélection de données qualifiées, comme c’est souvent le cas en environnement réel.
Nous avons opté pour ces données car elles reflètent la problématique critique des systèmes de production actuels : le besoin de filtrage systématique qui vient s’ajouter à la recherche vectorielle, exigeant une efficacité maximale tant en termes de précision que de rapidité. Par rapport à des bases de données de petite taille, l’utilisation de 20 millions de documents permet de mieux simuler la charge de travail et la complexité de sélection des candidats rencontrées par les moteurs de recherche vectorielle filtrée dans un environnement réel.
Conclusion
Pour les systèmes d’IA de nouvelle génération, notamment ceux qui reposent sur la gestion dynamique du contexte, la performance brute de la recherche par vecteurs est un élément structurant de l’expérience utilisateur. C’est un facteur multiplicateur. Dans les architectures où les agents enchaînent les étapes de recherche et de réflexion, l’efficacité de la récupération détermine non seulement la rapidité de la réponse finale, mais aussi la pertinence des informations transmises au LLM.
Elasticsearch a fait preuve d’une supériorité constante lors de nos tests, affichant un meilleur rappel et une latence réduite par rapport à OpenSearch, particulièrement lorsque la précision de la recherche repose sur l’identification du document spécifique plutôt que sur une vague ressemblance vectorielle. Sur un ensemble de données contrôlé, la différence est nette, et en production, ces gains s’accumulent au fil de volumes massifs d’appels de récupération, améliorant la réactivité, augmentant la marge de capacité et réduisant les coûts d’infrastructure.




