Bonjour à la communauté n8n,
Je construis actuellement un pipeline automatisé d’ingestion de recherche avec n8n pour alimenter un système RAG (Retrieval-Augmented Generation) académique.
Objectif du workflow :
Le workflow d’automatisation se déclenche lorsqu’un nouveau sujet de recherche est enregistré. Il appelle un moteur d’infrastructure de données académiques appelé ScholarAPI.net pour extraire des données académiques en texte intégral et des métadonnées de citations très détaillées. Une fois la charge JSON récupérée, n8n transmet les données à un nœud d’embedding et les pousse dans un Vector Store.
Le défi :
Lorsqu’on effectue un appel de nœud HTTP Request à ScholarAPI.net, la réponse JSON contenant le texte intégral de plusieurs articles scientifiques peut être très volumineuse (parfois plusieurs mégaoctets de texte propre et structuré par lot).
J’ai deux questions architecturales spécifiques pour garder le workflow optimisé :
-
Gestion des délais d’expiration / Limites d’exécution : Pour de grands lots de données textuelles intégrales, le traitement de l’API en amont peut prendre quelques moments. Quelle est la meilleure pratique dans n8n pour configurer des profils de retry résilients ou prolonger les délais d’expiration sur le nœud HTTP Request afin que le workflow ne échoue pas prématurément ?
-
Mémoire/Fractionnement des données : Le traitement de charges JSON imbriquées énormes directement dans un seul thread d’exécution provoque une utilisation importante de la mémoire. Dois-je utiliser le nœud « Item Lists » pour fractionner immédiatement les tableaux de texte entrants lors de la réception de ScholarAPI.net, ou un nœud Code personnalisé (JavaScript/Python) est-il plus efficace pour fragmenter les chaînes de texte avant de les envoyer aux embeddings vectoriels ?
J’apprécierais tout conseil ou modèle de workflow de la part de quiconque a construit des pipelines d’ingestion/scraping de texte à grande échelle dans n8n !
Merci d’avance.
@Asgef_Sha pour les timeouts, le nœud HTTP Request a un champ Timeout sous Options, augmente-le pour les appels lents, et active Retry On Fail dans Settings avec Max Tries et Wait Between Tries. Attention, la tentative ne se déclenche que si On Error est défini sur Stop Workflow, mets-le sur une option Continue et n8n ignore les compteurs de tentatives.
pour les payloads, ne découpe pas manuellement avec Item Lists ou un nœud Code, n8n a un nœud Recursive Character Text Splitter pour exactement ça (Chunk Size + Chunk Overlap) alimentant le Default Data Loader dans ton vector store. Divise d’abord le tableau papers pour que chacun s’exécute individuellement au lieu de garder tout le blob multi-mb en une seule exécution.
Bienvenue @Asgef_Sha ! Les conseils d’achamm sur le text splitter sont tout à fait justes. Un motif supplémentaire pour les lots multi-papiers : après avoir reçu la réponse HTTP, utilisez un nœud SplitInBatches pour traiter les articles par groupes de 5 à 10 à la fois, puis passez chaque lot par le text splitter et l’insertion dans le vector store. Cela empêche une charge utile unique de grande taille de rester en mémoire lors de l’embedding, ce qui peut bloquer l’exécution même si le timeout est augmenté. Il est aussi recommandé de définir le timeout de HTTP Request à au moins 120 secondes pour les appels full-text de ScholarAPI, car l’agrégation côté serveur peut être lente sur les grandes requêtes.
Pour ce type d’ingestion RAG, je ne garderais pas tout ça dans une seule exécution synchrone longue. Stockez d’abord la réponse brute de ScholarAPI, divisez la charge utile en segments gérables, puis traitez/intégrez par étapes plus petites avec des tentatives et des points de contrôle. Du JSON volumineux plus des appels HTTP longs, c’est là que la fiabilité banale bat un workflow intelligent tout-en-un. Êtes-vous capable de sauvegarder la réponse brute quelque part avant que l’étape d’intégration ne commence ?
Les bonnes réponses sont déjà là. Le Text Splitter plus Split Out plus SplitInBatches couvre la segmentation, et OMGItsDerek a raison de dire qu’on veut persister la réponse brute avant l’embedding. Je développerais ce dernier point, car pour ce type d’ingestion, l’architecture importe plus que n’importe quel paramètre de nœud unique.
Quelques points qui m’ont sauvé sur les grands pipelines d’ingestion de texte :
-
Divisez-le en deux workflows, pas un. Le Workflow A appelle simplement ScholarAPI et écrit chaque article dans une table ou un object store avec le statut « fetched ». Le Workflow B prend les lignes qui sont « fetched », les segmente, les embed, et les bascule à « embedded ». L’appel API coûteux et l’embedding lent échouent indépendamment. Si l’embedding échoue sur l’article 40 sur 50, vous ne re-tirez jamais le lot, B reprend simplement les lignes inachevées. Cette colonne de statut est votre point de contrôle.
-
Rendez-le idempotent. Identifiez chaque article par un identifiant stable (DOI ou identifiant ScholarAPI) et vérifiez le store avant l’embedding. Les retries et les reruns sont inévitables sur les longs jobs, et sans clé de déduplica vous payez pour embed le même article deux fois et vous finissez avec des vecteurs dupliqués qui polluent la récupération. C’est la plus grande victoire en fiabilité au meilleur prix.
-
Fixez la taille à la source si vous pouvez. Si ScholarAPI supporte la pagination ou une récupération par article, tirez des pages plus petites plutôt qu’un lot multi-MB. La façon la plus fiable de ne pas manquer de mémoire sur un énorme JSON est de ne jamais le tenir comme un élément unique en premier lieu. Utiliser Split Out tôt aide, les appels en amont plus petits aident davantage.
-
Une petite clarification sur le point de retry ci-dessus : Retry On Fail réessayera le nœud de toute façon. Le paramètre On Error décide ce qui se passe après l’épuisement des retries, Stop Workflow arrête, Continue passe l’élément échoué en aval. Pour un job d’ingestion je garde les retries activés, On Error défini sur continue (en utilisant la sortie d’erreur), et j’achemine les défaillances vers une table de dead-letter afin qu’un mauvais article ne coule pas toute l’exécution.
-
Si vous êtes auto-hébergé et les payloads sont vraiment volumineux, deux leviers env aident : augmentez le heap de Node avec NODE_OPTIONS=–max-old-space-size, et réduisez la rétention des données d’exécution pour que les exécutions multi-MB ne gonflent pas votre base de données.
En résumé, le banal split producteur-consommateur avec une colonne de statut et une clé de déduplica vous mènera plus loin que l’ajustement des timeouts sur une grande exécution. Heureux d’en développer n’importe lequel.
Salut 
Je crois que je comprends ce que tu veux dire — le problème ici n’est pas seulement un timeout ou du batching, mais le fait que n8n gère une très grande charge utile JSON dans un seul contexte d’exécution.
Pour des cas comme ScholarAPI retournant d’énormes textes structurés, le vrai goulot d’étranglement est généralement la mémoire d’exécution + le chaînage de nœuds, et pas seulement les limites HTTP.
J’ai observé un comportement similaire où le fait de diviser ou d’« asynchroniser » le flux seul ne le résout pas complètement, car les données sont toujours conservées en mémoire pendant le cycle de vie de l’exécution.
Je serais curieux de savoir si tu as déjà essayé d’isoler complètement l’étape d’ingestion de l’étape de transformation (pas seulement une division dans le même flux de travail) ?
Deux paramètres n8n concrets pour résoudre ce problème : d’abord, dans le nœud HTTP Request > Options > Timeout, définissez-le sur 300000 (5 min) pour que l’appel ne soit pas interrompu au milieu de la réponse sur les grandes charges utiles. Ensuite, si ScholarAPI retourne un tableau de papers, canalisez la sortie via un nœud Split In Batches défini sur une taille de lot 1 avant l’étape d’embedding - cela garde un seul paper dans le contexte d’exécution à la fois au lieu de tous les conserver. Pour isoler complètement la portée de la mémoire comme @Bella123 l’a suggéré, appelez un sous-flux de travail séparé via Execute Workflow pour l’étape embed + store. De cette façon, le texte de chaque paper est nettoyé par le garbage collector après le retour du sous-flux de travail plutôt que de s’accumuler dans l’exécution parent.
Je diviserais cela en ingestion, normalisation et intégration plutôt que d’essayer de faire gérer tout par un seul grand workflow.
Pour ce type de chemin ScholarAPI → RAG, la partie risquée n’est généralement pas seulement la longue requête HTTP. C’est qu’une énorme charge utile peut échouer à plusieurs frontières différentes :
-
frontière de récupération
L’appel HTTP peut expirer ou retourner trop de données pour qu’une seule exécution puisse les conserver confortablement.
-
frontière de normalisation
Vous devez décider ce qu’un « document » signifie avant le chunking : article, résumé, section, bloc de citation ou métadonnées d’auteur.
-
frontière de chunking
L’étape d’intégration doit recevoir des unités prévisibles, pas des charges utiles API brutes.
-
frontière de relance
Si un enregistrement échoue, vous ne voulez pas re-récupérer et re-intégrer tout l’ensemble de résultats.
Le modèle que j’utiliserais :
- demander une page/lot d’enregistrements ;
- écrire immédiatement les métadonnées de réponse brutes quelque part de manière durable ;
- diviser chaque article en un élément normalisé ;
- stocker un identifiant d’élément + état de traitement ;
- exécuter le chunking/intégration en tant que second workflow sur les éléments en attente ;
- marquer chaque élément comme récupéré, normalisé, chunké, intégré, échoué ou ignoré.
Cela vous donne la possibilité de redémarrer. Cela rend aussi la qualité du RAG plus facile à déboguer car vous pouvez inspecter quelle étape a produit de mauvais chunks.
Une question non sensible : ScholarAPI vous permet-il de paginer ou de filtrer les résultats par date/requête, ou recevez-vous une réponse volumineuse unique qui doit être divisée après la requête ?