Construire un RAG avec n8n et Supabase pgvector, pas à pas
Publié le 14 avril 2026 · 6 min de lecture
Un LLM ne connaît ni vos devis, ni vos procédures internes, ni votre documentation produit. Le RAG (Retrieval-Augmented Generation) corrige cela : avant de répondre, l'assistant recherche les passages pertinents dans vos documents et s'appuie dessus. Avec n8n pour l'orchestration et Supabase pour le stockage vectoriel, on construit un assistant documentaire complet sans écrire d'application — juste un peu de SQL et deux workflows. Suivez le guide.
Comment ça marche, en deux paragraphes
Chaque document est découpé en fragments (chunks) de quelques centaines de mots. Chaque fragment est transformé en embedding : un vecteur de nombres qui encode son sens. Ces vecteurs sont stockés dans Postgres grâce à l'extension pgvector, incluse dans Supabase.
Quand un utilisateur pose une question, celle-ci est vectorisée à son tour, et une recherche par similarité retrouve les fragments les plus proches sémantiquement. Ces fragments sont injectés dans le prompt du LLM, qui répond en s'appuyant dessus — et peut citer ses sources. Deux workflows n8n suffisent : un pour l'ingestion des documents, un pour la conversation.
Étape 1 — Préparer Supabase
Créez un projet sur supabase.com (le palier gratuit suffit pour tester), puis ouvrez le SQL Editor et exécutez le script standard attendu par l'intégration LangChain/n8n :
-- Activer pgvector
create extension if not exists vector;
-- Table de stockage des fragments
create table documents (
id bigserial primary key,
content text, -- le texte du fragment
metadata jsonb, -- source, titre, page...
embedding vector(1536) -- dimension du modèle d'embedding
);
-- Fonction de recherche par similarité
create function match_documents (
query_embedding vector(1536),
match_count int default null,
filter jsonb default '{}'
) returns table (
id bigint,
content text,
metadata jsonb,
similarity float
)
language plpgsql
as $$
begin
return query
select
documents.id,
documents.content,
documents.metadata,
1 - (documents.embedding <=> query_embedding) as similarity
from documents
where documents.metadata @> filter
order by documents.embedding <=> query_embedding
limit match_count;
end;
$$;
Deux points d'attention :
- La dimension
1536correspond au modèletext-embedding-3-smalld'OpenAI. Si vous utilisez un autre modèle d'embedding, adaptez la dimension partout — un décalage ici est la cause n° 1 d'erreurs d'insertion. - Row Level Security : si la RLS est activée sur la table, le node n8n sera silencieusement bloqué en lecture. Utilisez la clé
service_role(secrète, jamais côté client) dans le credential Supabase de n8n, ou définissez des policies adaptées.
Récupérez enfin l'URL du projet et la clé API (Settings → API) pour créer le credential Supabase dans n8n.
Étape 2 — Le workflow d'ingestion
Ce workflow lit vos documents, les découpe, les vectorise et les insère. Structure type :
- Déclencheur : manuel pour commencer ; plus tard, un trigger Google Drive ou un webhook pour ingérer automatiquement les nouveaux fichiers.
- Récupération du document : node Google Drive, HTTP Request ou Read Binary File. Pour un PDF, ajoutez une étape d'extraction de texte (Extract From File).
- Supabase Vector Store (
vectorStoreSupabase) en mode Insert Documents, pointant vers la tabledocuments.
Sur ce node racine se branchent trois sub-nodes :
- Embeddings OpenAI (connexion
ai_embedding) avectext-embedding-3-small— efficace et très bon marché : à la date de rédaction, de l'ordre de quelques centimes pour un million de tokens, soit des centaines de pages. - Default Data Loader (connexion
ai_document), qui transforme la donnée entrante en documents LangChain. C'est ici qu'on définit les metadata : ajoutez au minimumsource(nom du fichier) et si possible une URL — elles serviront aux citations. - Recursive Character Text Splitter (connexion
ai_textSplitter), branché sur le Data Loader. Réglage de départ raisonnable : chunk size 1000 caractères, overlap 200. Des chunks trop petits perdent le contexte ; trop grands, ils diluent la pertinence de la recherche.
Exécutez, puis vérifiez dans le Table Editor de Supabase que les lignes apparaissent avec content, metadata et embedding remplis. L'ingestion est idempotente à organiser vous-même : en cas de ré-ingestion d'un document, supprimez d'abord ses anciennes lignes (filtre sur metadata->>source), sinon vous cumulerez des doublons.
Étape 3 — Le workflow de conversation
- Chat Trigger (
chatTrigger) : il fournit une interface de chat intégrée à n8n, très pratique pour tester, et peut être exposé publiquement ou embarqué sur votre site. - AI Agent (
agent), avec trois branchements :- un modèle de chat (connexion
ai_languageModel) — Claude Sonnet ou GPT-4o donnent d'excellentes réponses sourcées ; un modèle « mini » suffit souvent pour de la FAQ interne (voir Connecter Claude ou GPT à n8n) ; - une Simple Memory (connexion
ai_memory) pour que l'assistant suive la conversation ; - le Supabase Vector Store en mode « Retrieve Documents (As Tool) » (connexion
ai_tool), avec son propre sub-node d'embeddings — impérativement le même modèle que celui de l'ingestion. Donnez au tool un nom et une description clairs (« Recherche dans la documentation interne de l'entreprise ») : c'est ce texte qui aide l'agent à décider quand chercher.
- un modèle de chat (connexion
Réglez le nombre de résultats (top K) entre 4 et 6 pour commencer.
Alternative plus simple : le node Question and Answer Chain (chainRetrievalQa) avec le vector store en mode Retrieve. Moins souple (pas d'outils multiples), mais plus déterministe et moins coûteux — la chaîne interroge systématiquement la base à chaque question, sans décision d'agent. Bon choix pour une FAQ pure ; l'agent s'impose dès que l'assistant doit aussi faire autre chose. Notre guide Débuter avec les nodes IA de n8n détaille ce choix.
Étape 4 — Obtenir des citations fiables
Un RAG sans sources est un RAG qu'on ne peut pas vérifier. Deux leviers :
- Les metadata injectées à l'ingestion : puisque chaque fragment retrouvé porte son
source, il suffit de l'exiger dans le message système de l'agent :
Tu réponds uniquement à partir des documents fournis par l'outil de recherche.
Termine chaque réponse par une ligne "Sources :" listant les valeurs
de metadata.source des passages utilisés.
Si les documents ne permettent pas de répondre, dis-le explicitement
au lieu d'inventer.
- La consigne anti-hallucination (« si tu ne trouves pas, dis-le ») est aussi importante que les citations elles-mêmes : c'est elle qui rend l'assistant digne de confiance au quotidien.
Testez avec des questions dont vous connaissez la réponse, puis — plus révélateur — avec des questions absentes de la base : un bon RAG doit savoir dire « je ne sais pas ».
Les erreurs qui font perdre une soirée
- Dimensions incohérentes : table en
vector(1536)mais embeddings d'une autre dimension → erreur d'insertion ou résultats vides. - Modèles d'embedding différents entre ingestion et interrogation → recherche silencieusement médiocre.
- RLS activée sans policy ni clé service_role → zéro résultat, sans message d'erreur clair.
- Fonction
match_documentsabsente ou signature modifiée → erreur du node au moment de la recherche. - Chunks énormes → le top K explose le contexte et la facture.
Gagner du temps
L'ensemble — SQL, ingestion multi-formats, agent avec citations, gestion des doublons — représente une bonne journée de travail quand on découvre les nodes. Le Pack Assistant RAG (79 €) livre ces workflows prêts à importer avec le script SQL fourni : vous créez le projet Supabase, collez vos clés, et votre assistant documentaire répond avec sources dans l'après-midi.
Une fois la mécanique en place, l'amélioration continue est simple : enrichir la base, affiner le découpage, ajuster le message système. Le RAG est rarement parfait au premier jet — mais avec n8n, chaque itération prend des minutes, pas des jours.