Como melhor lidar com requisições HTTP de longa duração e grandes payloads JSON do ScholarAPI.net em um fluxo RAG?

Oi comunidade n8n,

Atualmente estou construindo um pipeline automatizado de ingestão de pesquisa usando n8n para alimentar um sistema RAG (Retrieval-Augmented Generation) acadêmico.

Objetivo do Workflow:

O workflow de automação é acionado quando um novo tópico de pesquisa é registrado. Ele chama um mecanismo de infraestrutura de dados acadêmicos chamado ScholarAPI.net para extrair dados acadêmicos em texto completo e metadados de citação altamente detalhados. Uma vez que o payload JSON é recuperado, n8n passa os dados para um nó de embedding e os envia para um Vector Store.

O Desafio:

Ao fazer a chamada do nó HTTP Request para ScholarAPI.net, a resposta JSON contendo o texto completo de múltiplos artigos científicos pode ser bastante grande (às vezes vários megabytes de texto limpo e estruturado por lote).

Estou enfrentando duas questões arquiteturais específicas para manter o workflow otimizado:

  1. Tratamento de Timeouts / Limites de Execução: Para grandes lotes de dados em texto completo, o processamento da API upstream pode levar alguns momentos. Qual é a melhor prática em n8n para configurar perfis de retry resilientes ou estender timeouts no nó HTTP Request para que o workflow não falhe prematuramente?

  2. Memória/Divisão de Dados: Processar grandes payloads JSON aninhados diretamente em uma única thread de execução causa uso pesado de memória. Devo usar o nó “Item Lists” para dividir os arrays de texto recebidos imediatamente após recebê-los do ScholarAPI.net, ou um Code Node customizado (JavaScript/Python) é mais eficiente para chunking de strings de texto antes de enviá-los para embeddings vetoriais?

Agradeceria qualquer conselho ou templates de workflow de quem já construiu pipelines de ingestão/scraping de texto em larga escala dentro de n8n!

Obrigado antecipadamente.

@Asgef_Sha para timeouts, o nó HTTP Request tem um campo Timeout em Options, aumenta para as chamadas lentas, e ativa Retry On Fail em Settings com Max Tries e Wait Between Tries. Ó, retry só dispara se On Error for Stop Workflow, coloca para uma opção Continue e n8n ignora os contadores de retry.

para os payloads, não chunka na mão com Item Lists ou um nó Code, n8n tem um nó Recursive Character Text Splitter exatamente pra isso (Chunk Size + Chunk Overlap) alimentando o Default Data Loader dentro da tua vector store. Split Out o array papers primeiro pra cada um fluir por conta em vez de segurar o blob inteiro de vários MB numa só execução.

Bem-vindo @Asgef_Sha! O conselho do achamm sobre o splitter de texto está absolutamente correto. Um padrão extra para lotes de múltiplos artigos: após obter a resposta HTTP, use um nó SplitInBatches para processar artigos em grupos de 5-10 por vez, depois alimentar cada lote através do splitter de texto e inserção no vector store. Isso evita que um único payload grande fique na memória durante a incorporação, o que pode causar travamento na execução mesmo com o timeout estendido. Também vale a pena definir o timeout do HTTP Request para pelo menos 120 segundos para as chamadas de texto completo do ScholarAPI, já que a agregação no servidor deles pode ser lenta em consultas grandes.

Para esse tipo de ingestão RAG, eu não manteria tudo em uma única execução síncrona e longa. Armazene a resposta bruta do ScholarAPI primeiro, divida o payload em pedaços gerenciáveis e depois processe/embuta em etapas menores com retries e checkpoints. JSON grande mais chamadas HTTP longas é onde confiabilidade comum vence um workflow inteligente all-in-one. Você consegue salvar a resposta bruta em algum lugar antes da etapa de embedding começar?

Boas respostas acima já. O text splitter plus Split Out plus SplitInBatches cobre o chunking, e OMGItsDerek está certo que você quer persistir a resposta bruta antes de fazer embedding. Eu construiria sobre esse último ponto, porque para esse tipo de ingestão a arquitetura importa mais do que qualquer configuração de nó individual.

Algumas coisas que me salvaram em pipelines grandes de ingestão de texto:

  1. Divida em dois workflows, não um. Workflow A apenas chama ScholarAPI e escreve cada paper em uma tabela ou object store com status “fetched”. Workflow B pega linhas que estão “fetched”, faz chunking, embedding, e muda o status para “embedded”. O pull de API caro e o embedding lento então falham independentemente. Se embedding falhar no paper 40 de 50, você nunca refaz o pull do batch, B apenas retoma as linhas inacabadas. Essa coluna de status é seu checkpoint.

  2. Torne idempotente. Indexe cada paper por um id estável (DOI ou id ScholarAPI) e verifique o store antes de fazer embedding. Retries e reruns são inevitáveis em jobs longos, e sem uma chave de dedupe você paga para fazer embedding do mesmo paper duas vezes e acaba com vetores duplicados que poluem a retrieval. A vitória de confiabilidade mais barata que existe.

  3. Corrija o tamanho na fonte se conseguir. Se ScholarAPI suporta paging ou fetch por paper, puxe páginas menores em vez de um batch de vários megabytes. A maneira mais confiável de não ficar sem memória em um JSON gigante é nunca mantê-lo como um único item em primeiro lugar. Fazer Split Out cedo ajuda, chamadas upstream menores ajudam mais.

  4. Um pequeno esclarecimento sobre o ponto de retry acima: Retry On Fail vai reexecutar o nó independentemente. A configuração On Error decide o que acontece depois que as retries se esgotam, Stop Workflow para, Continue passa o item com falha para downstream. Para um job de ingestão mantenho retries ligadas, On Error configurado para continue (usando error output), e roteio falhas para uma dead-letter table para que um paper ruim não afunde a execução inteira.

  5. Se você está auto-hospedado e os payloads são genuinamente grandes, duas alavancas de env ajudam: aumente o heap do Node com NODE_OPTIONS=–max-old-space-size, e reduza data retention de execução para que execuções de vários megabytes não inchemm seu banco de dados.

Em resumo, a divisão chata producer-consumer com uma coluna de status e uma chave de dedupe vai levar você mais longe do que ajustar timeouts em uma execução grande. Fico feliz em elaborar qualquer uma dessas.

Oi :waving_hand:
Acho que entendi o que você quer dizer — o problema aqui não é apenas timeout ou batching, mas o fato de que o n8n está lidando com um payload JSON muito grande dentro de um único contexto de execução.

Para casos como ScholarAPI retornando texto estruturado enorme, o gargalo real geralmente é memória de execução + encadeamento de nós, não apenas limites HTTP.

Já vi comportamentos semelhantes onde dividir ou “async-ificar” o fluxo sozinho não resolve completamente porque os dados ainda são mantidos na memória durante o ciclo de vida da execução.

Ficaria curioso para saber se você já tentou isolar a etapa de ingestão completamente da etapa de transformação (não apenas dividindo dentro do mesmo workflow)?

Duas configurações concretas do n8n para corrigir isso: primeiro, no nó HTTP Request > Options > Timeout, defina para 300000 (5 min) para que a chamada não seja interrompida no meio da resposta em payloads grandes. Segundo, se o ScholarAPI retornar um array de papers, direcione a saída através de um nó Split In Batches configurado com tamanho de batch 1 antes da etapa de embedding - isso mantém apenas um paper no contexto de execução por vez em vez de todos eles. Para isolar totalmente o escopo de memória como @Bella123 sugeriu, chame um sub-workflow separado via Execute Workflow para a etapa embed + store. Dessa forma, o texto de cada paper é coletado como lixo depois que o sub-workflow retorna em vez de se acumular na execução pai.

Eu dividiria isso em ingestão, normalização e embedding em vez de tentar fazer um único fluxo de trabalho grande lidar com tudo de uma vez.

Para esse tipo de caminho ScholarAPI → RAG, a parte arriscada geralmente não é apenas a longa requisição HTTP. É que um payload enorme pode falhar em vários limites diferentes:

  1. limite de fetch
    A chamada HTTP pode expirar ou retornar muitos dados para uma execução manter confortavelmente.

  2. limite de normalização
    Você precisa decidir o que um “documento” significa antes de fazer chunking: paper, abstract, seção, bloco de citação ou metadados do autor.

  3. limite de chunking
    A etapa de embedding deve receber unidades previsíveis, não payloads brutos da API.

  4. limite de retry
    Se um registro falhar, você não quer refazer o fetch e re-embed de todo o conjunto de resultados.

O padrão que eu usaria:

  • requisitar uma página/lote de registros;
  • imediatamente escrever metadados de resposta bruta em algum lugar durável;
  • dividir cada paper em um item normalizado;
  • armazenar um id de item + estado de processamento;
  • executar chunking/embedding como um segundo fluxo de trabalho sobre itens pendentes;
  • marcar cada item como fetched, normalizado, chunked, embedded, failed ou skipped.

Isso te dá restartability. Também torna a qualidade do RAG mais fácil de debugar porque você pode inspecionar qual etapa produziu chunks ruins.

Uma pergunta não sensível: ScholarAPI permite paginar ou filtrar resultados por data/query, ou você está recebendo uma resposta grande que deve ser dividida após a requisição?