Un système de génération augmentée par recherche (RAG) digne de confiance ne répond qu’à partir de sources qu’il peut citer, et s’abstient quand il n’en trouve aucune. Ce contrat est simple à énoncer et difficile à tenir, car il doit valoir pour la qualité de la recherche, la conception des prompts, le multi-tenant et les tests. Ce guide montre comment le construire sur PostgreSQL avec pgvector : index vectoriels HNSW, recherche hybride avec reranking, et isolation des tenants assurée dans la base par Row-Level Security.

Le contrat : citer ou s’abstenir

Énoncez la règle précisément. Chaque réponse doit porter des citations vers les passages utilisés, et si la recherche ne renvoie rien qui étaye une réponse, le système le dit au lieu d’en générer une.

Imposez-le structurellement, pas seulement par le prompt. La couche de recherche renvoie des passages avec des identifiants stables. L’étape de génération doit répondre uniquement à partir de ces passages et les référencer. Un contrôle après génération rejette toute réponse dont les citations ne correspondent pas aux passages retrouvés. Une réponse sans citation valide devient un refus.

Stocker et chercher : pgvector avec HNSW

pgvector ajoute à PostgreSQL un type vectoriel et la recherche par similarité. Garder les embeddings à côté des données relationnelles (documents, tenants, droits) revient à n’avoir qu’un système à sauvegarder, sécuriser et interroger.

Pour la vitesse de recherche, les index HNSW (Hierarchical Navigable Small World) offrent une recherche approximative des plus proches voisins avec un bon rappel et une faible latence. Leurs paramètres arbitrent entre rappel, temps de construction, mémoire et coût de requête : réglez-les sur vos propres requêtes d’évaluation plutôt que de garder les valeurs par défaut.

Recherche hybride et reranking

La recherche vectorielle trouve des passages dont le sens est proche. La recherche par mots-clés trouve les passages qui contiennent exactement les termes recherchés, comme des noms de produits, des identifiants et des codes d’erreur, que les embeddings peuvent brouiller. La recherche hybride exécute les deux et fusionne les résultats.

Un reranker réévalue ensuite les candidats fusionnés avec un modèle qui lit ensemble la requête et le passage, ce qui améliore en général le haut de la liste, celui que le générateur voit réellement. Le reranking coûte de la latence : reclassez un petit ensemble de candidats, quelques dizaines de passages plutôt que des centaines.

Isolation des tenants avec Row-Level Security

Dans un système multi-tenant, la pire défaillance est qu’un tenant voie les passages d’un autre. Row-Level Security (RLS) dans PostgreSQL applique les règles d’accès dans la base : des politiques s’attachent aux tables, et chaque requête, y compris la recherche vectorielle, ne voit que les lignes que le tenant de la session peut lire.

Comme la règle vit dans la base, le code applicatif ne peut pas l’ignorer, à condition que l’application se connecte avec un rôle qui ne possède pas les tables et n’échappe pas à RLS (les propriétaires de table sont exemptés des politiques, sauf si la table utilise FORCE ROW LEVEL SECURITY). La garantie est aussi testable au niveau des données : exécutez la même requête sous deux identités de tenant et vérifiez que les résultats ne se recoupent pas.

Une API de recherche maîtrisée

Placez la recherche derrière une API que la plateforme maîtrise, plutôt que de laisser chaque produit interroger la base. L’API est l’endroit où le contrat est appliqué : elle fixe le tenant de la session, exécute la recherche hybride et le reranking, renvoie les passages avec leurs identifiants et applique la politique de citations. Les produits disposent d’un seul contrat de recherche, et les améliorations de la recherche profitent à tous en même temps.

En pratique

Sur la plateforme d’ENSO, j’ai construit l’architecture RAG sur Aurora PostgreSQL avec pgvector (HNSW, recherche hybride et reranking), derrière une API de recherche maîtrisée avec une politique de citations stricte : chaque réponse cite ses sources ou s’abstient, et l’isolation des tenants est assurée dans la base par Row-Level Security. L’architecture qui entoure ce RAG est décrite dans l’étude de cas ENSO.

Compromis et limites

Placer l’isolation et la recherche dans PostgreSQL lie la conception à un seul moteur et à ses limites de montée en charge ; un corpus très volumineux peut demander un magasin vectoriel dédié.

Une citation stricte augmente les refus. Les utilisateurs verront plus souvent « Je ne peux pas répondre à partir des sources disponibles », ce qui est le comportement voulu mais demande un message clair et un moyen d’ajouter des sources.

Le reranking et la recherche hybride ajoutent de la latence et des pièces mobiles, et chaque paramètre (taille des chunks, réglages d’index, nombre de candidats) doit être évalué sur des requêtes réelles. Un jeu de référence de paires question et source attendue, exécuté en CI, est le moyen d’éviter que des améliorations ne cassent silencieusement le contrat de citations.