PARTIE II. Développements autour des LLMs (pour les data scientists)
III. Focus sur le RAG (Retrieval Augmented Generation)
Le Retrieval Augmented Generation (RAG) est une technique courante utilisée pour améliorer les performances d’un LLM et de pallier ces déficiences. En effet les LLMs sont très performants pour de la génération de textes mais ils peuvent commettre des hallucinations, c’est-à-dire des affirmations qui semblent plausibles mais qui n’ont aucun fondement. Leur connaissance est aussi limitée par les données qui ont été utilisées pour l’entrainement, par exemple, un llm n’a pas accès aux informations contenues dans une base de connaissance privée car ces données ne sont pas contenues dans le corpus d’entrainement du llm.
Pour remédier à ces limitations le RAG propose de permettre à un LLM de s’appuyer sur une base de connaissance, généralement sous la forme de document contenant du texte pour répondre de manière pertinente à des questions, en utilisant de manière adéquate les informations contenues dans la base de connaissance.
Le LLM sera ainsi en mesure de répondre à des questions portant sur des points précis et sur des données sur lequel il n’a jamais été entrainé. En exploitant la base de connaissance il aura aussi moins tendance à inventer de fausses informations et donc à halluciner.
1. Principe de fonctionnement général
Un système de RAG va combiner la capacité de génération de textes d’un LLM avec de la recherche d’information dans une base de connaissance interne. Le RAG se compose principalement de deux parties, une première partie de retrieval dont le rôle est d’analyser une question de l’utilisateur et de trouver des éléments qui sont pertinents pour répondre à la question dans la base, et une seconde partie de génération qui contient le LLM et qui va incorporer le contexte récupérés par la partie de retrieval dans un prompt pour permettre au LLM de générer une réponse basée sur des éléments pertinents.
2. Recherche d’information
La partie de retrieval qui s’occupe de la recherche d’informations pertinentes dans la base joue un rôle essentiel pour le bon fonctionnement du RAG. En effet si des informations non pertinentes sont retournées au LLM il devient très difficile pour lui de formuler une réponse adéquate.
Il existe de nombreux algorithmes permettant d’effectuer cette recherche d’information, cependant l’une des approches les plus populaires se base sur l’utilisation de vecteurs denses. Dans cette méthode on utilise un encodeur pour transformer le texte en vecteurs de grandes dimensions que l’on stocke dans une base de données vectorielle. Cet encodeur a été entrainé a projeter des textes sémantiquement proches sur des vecteurs similaires. Lorsqu’une requête utilisateur est reçue en entrée, elle est elle aussi encodée dans un vecteur de même dimension. On peut alors comparer ce vecteur à l’ensemble des vecteurs présents en base ce qui permet de récupérer les vecteurs les plus proches qui correspondent à ceux qui sont sémantiquement proches. On peut ainsi trouver les morceaux de texte à envoyer au LLM pour la génération.
3. Génération
La phase de génération dans un système de RAG intervient après la récupération des documents pertinents. Une fois les documents récupérés, ils sont insérés dans un prompt que le LLM utilise pour produire des réponses contextuellement appropriées et précises. Plus le LLM est performant et correctement aligné sur les préférences humaines plus il est capable de prendre une quantité importante de document en contexte et ainsi de mieux répondre à la question.
4. Comparatif détaillé des solutions de stockages de données pour la recherche vectorielle approximative
Toutes les solutions testées sont open-source ou disposant d’une licence permissive, qui donne la possibilité d’héberger localement les données.
Weaviate | Milvus | Qdrant | ElasticSearch | FAISS | |
---|---|---|---|---|---|
Open source | ✅ | ✅ | ✅ | Partiellement | ✅ |
Dev-friendly | +++ | + | +++ | ++ | +++ |
Déploiement | ✅ | ✅ mais difficile à mettre en place, constellation de micro-services | ✅ | ✅ | ❌ mais possibilité de construire une image Docker custom par exemple |
Spécifique à la recherche vectorielle | ✅ | ✅ | ✅ | ❌ | ✅ |
Qualité de la documentation | +++ [-] | ++ [-] | +++ [-] | ++ [-] | + [-] |
Dernière mise à jour | mai 2024 | mai 2024 | mai 2024 | mai 2024 | mars 2024 |
Latence (ms)** | 438.18 | 322.63 | 118.25 | 338.53 | - |
Requêtes/seconde (RPS)** |
217.98 | 281.52 | 710.23 | 275.11 | - |
P99 latence (ms)** | 1723.62 | 436.87 | 144.78 | 589.61 | - |
Temps d’upload (minutes)** | 71.61 | 1.41 | 2.074 | 14.33 | - |
Temps d’upload + indexation (minutes)** |
71.61 | 9.53 | 17.49 |
122.79 ❌ |
- |
Place en mémoire |
num_vectors * vector_dimension * 4 bytes * 2 [-]
|
Conséquente d’après les avis d’utilisateurs, pas de formules approximative [-] |
num_vectors * vector_dimension * 4 bytes * 1.5 [-]
|
num_vectors * 4 * (vector_dimension + 12) [-]
|
? |
Type d’index | HNSW | FLAT, IVF_FLAT, IVF_SQ8, IVF_PQ, HNSW, BIN_FLAT, BIN_IVF_FLAT, DiskANN, GPU_IVF_FLAT, GPU_IVF_PQ, and CAGRA | HNSW | HNSW | FLAT, IVS_FLAT, IVF_SQ8, IVF_PQ, HNSW, BIN_FLAT and BIN_IVF_FLAT |
Recherche hybride | ✅ | ✅ | ✅ | ✅ | ❌ |
Ajout d’éléments à la volée, scalabilité | Partitionnement statique |
Segmentation dynamique |
Partitionnement statique | Partitionnement statique |
❌ (index immutable -> vector library) |
Accès contrôlé par rôles | ❌ sur le backlog, mais n’avance beaucoup [-] | ✅ [-] | ✅ [-] | ✅ [-] | ❌ |
Partions et étanchéité des bases de données (multi-tenancy) |
❌ pas très clair, mais il semble que ce ne soit pas encore possible [-] | ✅ Plusieurs systèmes de partitions, très flexible [-] | ✅ Plusieurs systèmes de partitions, assez flexible [-] | ✅ Possible mais pas très intuitif [-] | ❌ |
Autres avantages |
|
|
|||
Autres inconvénients |
|
|
|
** Qdrant benchmark (janvier 2024), dataset = gist-960-euclidean (1M de vecteurs en dimension 960), précision à 0.95
Les solutions présentées recouvrent en fait plusieurs cas d’usage :
- Les bibliothèques vectorielles (vector library) de type FAISS sont adaptées à de la rechercher sémantique à la volée, avec constitution de la base et recherche immédiate. Ici il s’agira d’un cas d’usage où l’utilisateur apporte son propre document avec un téléchargement en temps réel, et pose des questions dessus ou demande une synthèse.
- Les bases de données vectorielles (vector database) sont des dispositifs plus lourds et généralement un peu plus lents, mais avec un stockage permanent et beaucoup plus de flexibilité dans la recherche. Ils sont plus adaptés à un cas d’usage où la base de connaissance est constituée en amont et doit être mise à jour de temps en temps.
Pour une mise en production rapide et efficace Qdrant semble être la meilleure solution, combiné à une base de données plus traditionnelle comme ElasticSearch pour l’historique des conversations. Pour avoir une approche tout-en-en, et plus de flexibilité dans la gestion des collections, c’est ElasticSearch qui se détache des autres, malgré des temps d’indexation assez conséquents.
Aparté sur les intégrations Langchain : à manipuler avec précaution, les fonctions ne sont pas toujours explicites (par exemple la méthode
from_documents
supprime et recrée en général une collection). De plus certaines fonctionnalités comme l’utilisation de partitions ne sont pas toujours accessibles via Langchain. Il peut être utile de recréer des wrapper qui utilisent en partie Langchain et en partie les fonctions natives de la base de données.
Annexes
Définitions
Dev-friendly -> Note qualitative après installation de chaque solution (sauf FAISS) dans une image Docker, et utilisation avec Python (avec et sans l’intégration Langchain)
Déploiement -> Existence d’un écosystème de déploiement
Qualité de la documentation -> Note qualitative après installation de chaque solution (sauf FAISS) dans une image Docker, et utilisation avec Python (avec et sans l’intégration Langchain)
Ajout d’éléments à la volée, scalabilité -> Comment l’indexation se fait si la base de données est modifiée. Avec le partitionnement statique (static sharding), si la capacité du serveur est augmentée toutes les données doivent être de nouveau partitionnées, ce qui peut être long.
Recherche hybride -> Possibilité d’effectuer des recherches dans les métadonnées, avec des nombres ou des chaînes de caractères
Accès contrôlé par rôles (RBAC)-> Autorisations prédéfinies pour chaque utilisateur, avec un accès différencié aux documents
Ressources
https://weaviate.io/blog/vector-library-vs-vector-database
ANN Benchmark (avril 2023)