FlowKit

Garder un index RAG à jour avec n8n : upsert, suppressions et resynchronisation

Publié le 1 août 2026 · 6 min de lecture

Tous les tutoriels RAG s'arrêtent au même endroit : les documents sont découpés, vectorisés, insérés dans Supabase pgvector, le chatbot répond — fin de l'histoire. Sauf que vos documents ne sont pas figés. La grille tarifaire change, la procédure interne est réécrite, une page Notion est supprimée. Trois mois plus tard, votre assistant cite avec assurance un prix qui n'existe plus, ou mélange deux versions du même document dont les chunks coexistent dans l'index. Ce guide traite le problème que les tutoriels ignorent : détecter les modifications, remplacer les chunks obsolètes, gérer les suppressions et resynchroniser sans réembedder tout le corpus.

L'intérêt même du RAG, tel que formulé par Patrick Lewis et ses co-auteurs dans l'article fondateur Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (NeurIPS 2020), est que la mémoire non paramétrique — l'index documentaire — peut être remplacée ou mise à jour sans réentraîner le modèle. Un index qu'on ne met jamais à jour renonce à cet avantage. Et une étude de Tu Vu et ses collègues, FreshLLMs: Refreshing Large Language Models with Search Engine Augmentation (Findings of ACL 2024), a mesuré le phénomène avec leur benchmark FreshQA : dès que les questions portent sur des connaissances qui évoluent, la justesse des modèles s'effondre — seul l'accès à des informations à jour la restaure. Un RAG branché sur des documents périmés reproduit le défaut qu'il devait corriger.

Pourquoi un index RAG se dégrade silencieusement

Trois mécanismes distincts abîment un index laissé sans maintenance :

  • Les doublons de versions : le node Vector Store en mode insertion ajoute des lignes, il n'écrase rien. Réingérer un document modifié sans supprimer l'ancien crée deux jeux de chunks concurrents, et la recherche peut renvoyer un chunk de chaque version dans le même contexte.
  • Les documents fantômes : un fichier supprimé de Google Drive ou une page archivée dans Notion reste indéfiniment dans pgvector. L'assistant continue de le citer.
  • La dérive de découpage : si vous changez de stratégie de chunking ou de modèle d'embeddings, anciens et nouveaux documents ne sont plus comparables : les distances vectorielles perdent leur cohérence.

Si vous partez de zéro, commencez par notre guide RAG complet avec n8n et Supabase ; la suite suppose un index pgvector déjà en place.

Détecter ce qui a changé : trois niveaux de précision

1. Schedule Trigger + date de modification

Le pattern le plus simple : un Schedule Trigger périodique liste les documents de la source et filtre sur la date de modification. Google Drive expose modifiedTime, Notion last_edited_time, un CMS ou une base SQL ont presque toujours un champ updated_at. Le workflow ne retient que les documents modifiés depuis la dernière exécution (stockez ce timestamp dans une Data Table ou votre table de suivi — voir plus bas). C'est robuste, mais avec une latence égale à l'intervalle du déclencheur ; notre guide du Schedule Trigger détaille la configuration cron et les pièges de fuseaux horaires.

2. Webhooks de la source

Google Drive et Notion peuvent notifier les changements plutôt qu'attendre le prochain polling — le trigger Google Drive de n8n surveille les créations et mises à jour de fichiers, comme décrit dans notre guide RAG sur Google Drive. La latence tombe à quelques secondes, mais un webhook peut se perdre (instance n8n arrêtée, erreur en cours de workflow) : gardez toujours une resynchronisation planifiée en filet de sécurité.

3. Hash de contenu : la source de vérité

La date de modification ment parfois : un fichier resauvegardé à l'identique, une propriété Notion cosmétique modifiée, et vous réembeddez pour rien. Le hash du contenu extrait tranche définitivement :

// Node Code — après extraction du texte du document
const crypto = require('crypto');
const hash = crypto.createHash('sha256')
  .update($json.content)
  .digest('hex');
return [{ json: { ...$json, content_hash: hash } }];

Si le hash calculé est identique à celui stocké lors de la dernière ingestion, on saute l'embedding : c'est ce test qui rend la synchronisation économiquement raisonnable.

La stratégie delete-then-insert par document

Pgvector n'a pas de notion native d'« upsert de document » : l'unité d'insertion est le chunk, et un document modifié ne produit pas le même nombre de chunks qu'avant. Faire correspondre les anciens chunks aux nouveaux un par un est le piège classique : une phrase ajoutée en tête de document décale toutes les frontières, et vos « IDs de chunks » (doc-42-chunk-3…) ne désignent plus le même contenu. La seule stratégie fiable est atomique : supprimer tous les chunks du document, puis réinsérer la nouvelle version en entier.

Condition préalable : chaque chunk doit porter un identifiant stable du document parent dans ses métadonnées, posé dès l'ingestion initiale (champ Metadata du Default Data Loader) :

{
  "doc_id": "notion-1a2b3c4d",
  "source": "notion",
  "title": "Politique de remboursement"
}

Même mécanisme que pour filtrer par métadonnées côté recherche — il sert ici à cibler la suppression. Le workflow de mise à jour enchaîne :

  1. Détection : le document notion-1a2b3c4d a un hash différent de celui stocké.
  2. Suppression ciblée : un node Postgres (connecté à Supabase, voir notre guide de connexion n8n–Supabase) exécute le delete sur le champ JSONB de métadonnées :
DELETE FROM documents
WHERE metadata->>'doc_id' = 'notion-1a2b3c4d';
  1. Réinsertion : le node Supabase Vector Store en mode Insert reçoit le texte complet, le redécoupe (mêmes réglages de chunking que l'ingestion initiale) et insère les nouveaux chunks avec les mêmes métadonnées doc_id.
  2. Mise à jour du suivi : le nouveau hash remplace l'ancien dans la table de suivi.

L'ordre delete-puis-insert laisse une fenêtre de quelques secondes où le document est absent de l'index — acceptable dans la quasi-totalité des cas, et bien préférable à la fenêtre inverse où deux versions coexistent.

La table de suivi : hash, timestamps et suppressions

Une petite table SQL dans le même projet Supabase centralise l'état de synchronisation :

CREATE TABLE rag_sync (
  doc_id text PRIMARY KEY,
  content_hash text NOT NULL,
  last_synced_at timestamptz DEFAULT now()
);

Elle rend trois services. D'abord le test de hash avant embedding (un simple SELECT par document). Ensuite la gestion des suppressions à la source, angle mort de l'incrémental : un document supprimé de Drive ou archivé dans Notion ne remonte plus dans les listings, donc aucun événement « modifié » ne le signale. La parade : lors de la resynchronisation complète, comparer la liste des doc_id présents dans la source avec ceux de rag_sync — tout identifiant orphelin déclenche un DELETE dans documents et dans rag_sync. Enfin, last_synced_at sert de tableau de bord pour repérer les documents jamais resynchronisés depuis des mois.

Incrémental fréquent, resynchronisation complète périodique

Les deux modes se complètent plutôt qu'ils ne s'opposent :

  • La synchronisation incrémentale (webhook ou Schedule Trigger horaire/quotidien, documents modifiés uniquement) porte la fraîcheur au quotidien pour un coût marginal quasi nul.
  • La resynchronisation complète (hebdomadaire ou mensuelle) reliste toute la source, repasse chaque document au test de hash — donc ne réembedde toujours que ce qui a changé — et purge les orphelins. Elle rattrape les webhooks perdus et les exécutions échouées.

Côté coût, le levier est presque entièrement dans le test de hash : sur un corpus de plusieurs milliers de documents où quelques dizaines changent par semaine, réembedder l'intégralité à chaque passage multiplierait la facture d'embeddings par cent ou plus, sans gain de qualité. Après chaque évolution notable du corpus, pensez aussi à évaluer la qualité des réponses de votre RAG pour vérifier que la synchronisation produit l'effet attendu côté utilisateur.

Notre workflow gratuit de synchronisation Notion vers base vectorielle implémente ce pattern de bout en bout ; et le Pack Assistant RAG (119 €) livre l'ensemble ingestion + synchronisation + assistant prêt à adapter à votre source documentaire.

En résumé

Un index RAG n'est pas un livrable, c'est un système à maintenir. Les points qui font la différence : un doc_id stable dans les métadonnées de chaque chunk dès l'ingestion initiale, la stratégie delete-then-insert au niveau du document (jamais de correspondance chunk à chunk), un hash de contenu stocké dans une table de suivi pour ne réembedder que ce qui a réellement changé, et la combinaison incrémental fréquent + resynchronisation complète périodique pour traiter aussi les suppressions à la source. Sans cela, votre assistant répond avec la documentation d'il y a six mois — une dérive qu'aucun utilisateur ne signale, parce que les réponses restent fluides et assurées.

FAQ

Questions fréquentes

Pourquoi ne pas simplement réinsérer un document modifié dans le vector store ?

Parce que le node Vector Store en mode insertion ajoute des lignes, il ne remplace rien. Réinsérer un document déjà indexé crée des doublons : l'ancienne version et la nouvelle coexistent, et la recherche peut renvoyer des chunks contradictoires. Il faut d'abord supprimer les chunks existants du document (via son doc_id en métadonnées), puis insérer la nouvelle version.

Faut-il recalculer les embeddings de tout le document si une seule section a changé ?

En pratique, oui, au niveau du document : le découpage en chunks dépend du texte complet, et une modification peut décaler toutes les frontières de chunks. L'optimisation rentable se joue au niveau des documents, pas des chunks : un hash du contenu permet de ne réembedder que les documents réellement modifiés et d'ignorer tous les autres.

À quelle fréquence lancer une resynchronisation complète de l'index RAG ?

La synchronisation incrémentale (documents modifiés depuis le dernier passage) peut tourner toutes les heures ou tous les jours selon la fraîcheur attendue. Une resynchronisation complète hebdomadaire ou mensuelle sert de filet de sécurité : elle rattrape les webhooks manqués, les documents supprimés à la source et les dérives accumulées, au prix d'un parcours complet de la source.

Comment gérer un document supprimé dans Google Drive ou Notion ?

L'incrémental par date de modification ne le voit pas : un document supprimé ne remonte plus dans les listings. Deux approches : comparer périodiquement la liste des doc_id présents dans la source avec ceux de la table de suivi et supprimer les orphelins du vector store, ou s'appuyer sur un webhook de suppression quand la source en propose un.

Bundle FlowKit Complet

269 €