Aller au contenu
Développement medium

FAISS : recherche vectorielle en mémoire

9 min de lecture

logo python

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.

  • 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.

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.

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 faiss
import 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.

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...

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.

# Sauvegarde
faiss.write_index(index, "corpus.faiss")
# Rechargement
index = 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.

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.

BesoinFAISS convientPréférer une base dédiée
Prototype, corpus en mémoireOui
Filtrage par métadonnéesLimitéChroma, Qdrant
Service partagé, multi-clientsNonQdrant
Persistance géréeManuelleChroma, 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.

SymptômeCause probableSolution
AssertionError à l'ajoutDimension du vecteur ≠ dimension de l'indexCréer l'index avec la bonne dimension
Scores supérieurs à 1 ou incohérentsVecteurs non normalisésAppliquer faiss.normalize_L2
search renvoie des indices -1Moins de k vecteurs dans l'indexFiltrer les -1, réduire k
Résultats sans texteListe des textes non tenue à jourAligner la liste sur l'ordre d'insertion
Index vide au redémarrageIndex non persistéwrite_index puis read_index
  • 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.
  • IndexFlatIP sur 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.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn