
Comparer une question à chaque vecteur du corpus, un par un, fonctionne sur quelques phrases — pas sur des milliers de chunks. FAISS, la bibliothèque de recherche de similarité de Meta, résout ce problème : elle construit un index qui retrouve les vecteurs les plus proches sans tout parcourir. Tout se passe en mémoire, sans serveur à déployer — ce qui en fait l'outil idéal pour prototyper un RAG. Ce guide montre comment créer un index, y ajouter des vecteurs, rechercher les plus proches, et persister l'index sur disque. Public visé : développeur qui a généré des embeddings et veut les rendre interrogeables.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Pourquoi une recherche naïve ne tient pas à l'échelle.
- Créer un index FAISS et y ajouter des vecteurs.
- Obtenir une similarité cosinus avec un index à produit scalaire.
- Rechercher les k plus proches voisins d'une question.
- Sauvegarder et recharger un index.
Prérequis
Section intitulée « Prérequis »- Python 3.10+.
- Une instance Ollama avec le modèle d'embedding
nomic-embed-text. - Comprendre les embeddings et la similarité.
Pourquoi un index, et pas une simple boucle
Section intitulée « Pourquoi un index, et pas une simple boucle »Le guide sur les embeddings cherchait en comparant la question à tous les vecteurs, un par un. C'est correct, et c'est limpide — mais le coût croît linéairement avec la taille du corpus. À dix mille chunks, chaque question recalcule dix mille similarités. À un million, c'est inutilisable.
Un index vectoriel change l'échelle. Au lieu de tout parcourir, il organise les vecteurs de sorte à retrouver les plus proches voisins en n'en examinant qu'une fraction. C'est ce que fait FAISS : il prend en charge cette structure de données, et la recherche reste rapide même quand le corpus grossit.
FAISS travaille en mémoire et sans serveur : on l'importe comme une bibliothèque, on construit l'index dans le processus Python. C'est sa force pour prototyper — et aussi sa limite, on y revient.
Créer un index et y ajouter des vecteurs
Section intitulée « Créer un index et y ajouter des vecteurs »FAISS propose plusieurs types d'index. Le plus simple, IndexFlatIP, calcule un produit scalaire (Inner Product) entre la requête et chaque vecteur. Combiné à des vecteurs normalisés, ce produit scalaire est la similarité cosinus.
import faissimport numpy as np
DIMENSION = 768 # taille des vecteurs de nomic-embed-text
def vectoriser(textes: list[str]) -> np.ndarray: """Vectorise des textes ; vecteurs normalisés pour une similarité cosinus.""" reponse = CLIENT.embeddings.create(model="nomic-embed-text", input=textes) vecteurs = np.array([d.embedding for d in reponse.data], dtype="float32") faiss.normalize_L2(vecteurs) return vecteurs
index = faiss.IndexFlatIP(DIMENSION)index.add(vectoriser(corpus))Trois points méritent attention. L'index est créé avec la dimension exacte des vecteurs — 768 pour nomic-embed-text ; un vecteur d'une autre taille sera refusé. Les vecteurs sont fournis en float32 — le type que FAISS attend. Et faiss.normalize_L2 ramène chaque vecteur à une longueur de 1, condition pour que le produit scalaire vaille le cosinus.
Rechercher les plus proches voisins
Section intitulée « Rechercher les plus proches voisins »Une fois l'index peuplé, la recherche se fait avec search : on lui passe le vecteur de la question et le nombre k de voisins voulus.
def rechercher(index, textes, question, k=3): """Renvoie les k textes les plus proches de la question, avec score.""" scores, indices = index.search(vectoriser([question]), k) return [ (textes[i], float(score)) for score, i in zip(scores[0], indices[0]) if i != -1 ]search renvoie deux tableaux : les scores de similarité et les indices des vecteurs trouvés. On relie chaque indice au texte correspondant grâce à la liste tenue à côté. Le filtre i != -1 écarte les positions vides — FAISS renvoie -1 quand l'index contient moins de k vecteurs que demandé.
Sur un corpus de quelques phrases, la recherche se comporte comme attendu :
Question : Comment garder les données d'un conteneur ? [0.687] Pour sauvegarder un volume, on lance un conteneur temporaire. [0.630] Un volume Docker conserve les données après la suppression...Sauvegarder et recharger l'index
Section intitulée « Sauvegarder et recharger l'index »Un index vit en mémoire : il disparaît à l'arrêt du processus. Reconstruire l'index à chaque démarrage, c'est revectoriser tout le corpus — long et coûteux. FAISS sait donc écrire un index sur disque et le relire.
# Sauvegardefaiss.write_index(index, "corpus.faiss")
# Rechargementindex = faiss.read_index("corpus.faiss")Une nuance importante : write_index ne sauvegarde que les vecteurs. La liste des textes, elle, se sauvegarde séparément — un simple fichier texte suffit. Recharger un index complet, c'est donc relire deux fichiers : l'index FAISS et les textes alignés.
Place de FAISS dans un pipeline RAG
Section intitulée « Place de FAISS dans un pipeline RAG »FAISS est excellent pour ce qu'il est : un moteur de recherche vectorielle en mémoire, rapide, sans serveur. C'est l'outil parfait pour prototyper un RAG, mesurer une idée, travailler sur un corpus de taille raisonnable.
Ses limites apparaissent quand le projet mûrit. FAISS ne gère pas nativement les métadonnées riches ni le filtrage — « cherche, mais seulement dans les documents de 2026 ». Il ne se partage pas entre plusieurs processus ou machines. Et la persistance, on l'a vu, se bricole à la main.
| Besoin | FAISS convient | Préférer une base dédiée |
|---|---|---|
| Prototype, corpus en mémoire | Oui | — |
| Filtrage par métadonnées | Limité | Chroma, Qdrant |
| Service partagé, multi-clients | Non | Qdrant |
| Persistance gérée | Manuelle | Chroma, Qdrant |
Le bon réflexe : prototyper avec FAISS, puis basculer vers une base vectorielle comme Chroma en développement ou Qdrant en production quand les besoins de filtrage et de service apparaissent.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
AssertionError à l'ajout | Dimension du vecteur ≠ dimension de l'index | Créer l'index avec la bonne dimension |
| Scores supérieurs à 1 ou incohérents | Vecteurs non normalisés | Appliquer faiss.normalize_L2 |
search renvoie des indices -1 | Moins de k vecteurs dans l'index | Filtrer les -1, réduire k |
| Résultats sans texte | Liste des textes non tenue à jour | Aligner la liste sur l'ordre d'insertion |
| Index vide au redémarrage | Index non persisté | write_index puis read_index |
À retenir
Section intitulée « À retenir »- Une recherche naïve coûte linéairement ; un index garde la recherche rapide à l'échelle.
- FAISS est un moteur de recherche vectorielle en mémoire, sans serveur.
IndexFlatIPsur des vecteurs normalisés donne une similarité cosinus.- FAISS ne stocke que des vecteurs — la liste des textes se tient à côté.
- La persistance s'écrit à la main : l'index d'un côté, les textes de l'autre.
- FAISS excelle pour prototyper ; le filtrage et le service appellent une base dédiée.
Prochaines étapes
Section intitulée « Prochaines étapes »Pour aller plus loin
Section intitulée « Pour aller plus loin »- Documentation FAISS — la référence de la bibliothèque et de ses types d'index.