La conoscenza “sparsa” in documenti, Drive, wiki e pagine web frena risposte rapide e consistenti. Una pipeline RAG n8n (Retrieval‑Augmented Generation) risolve il problema: indicizza i contenuti in un database vettoriale, recupera passaggi pertinenti con similarity search e li usa per “groundare” il modello LLM, generando risposte accurate con citazioni. In questo articolo crei una pipeline RAG con n8n, scegliendo tra vector store persistente vs in‑memory, orchestrando l’intero ciclo (ingestione, chunking, embeddings semantici in n8n, top‑k retrieval, prompt grounding e citazioni delle fonti), ottimizzando costi e performance e mettendo in sicurezza dati e accessi. Troverai configurazioni nodo‑per‑nodo basate su nomi e parametri effettivi, esempi pronti e consigli per valutazione qualità del retrieval (precision/recall), caching dei risultati e re‑ranking. Al termine, potrai lanciare un chatbot documentale affidabile con orchestrazione chatbot su n8n che risponde “usando SOLO le tue fonti”, mantenendo governance e scalabilità.
[IMG: panoramica pipeline RAG: Ingest (Drive/Web) → Chunking → Embeddings → Vector DB → Retrieval → LLM (prompt grounding) → Risposta con citazioni]
Architettura RAG: componenti, scelte di stack e trade‑off
Una pipeline RAG con n8n unisce tre livelli:
- Ingestione: acquisisci contenuti da Google Drive/Docs e web scraping. Normalizza in testo, arricchisci metadati (titolo, URL, sezione) e applica chunking e text splitter per indicizzazione.
- Indicizzazione: generi embeddings semantici in n8n e li invii a un database vettoriale per RAG (Pinecone, Qdrant, pgvector). Versioni l’indice e gestisci namespace/collezioni.
- Retrieval + Generazione: per ogni domanda, esegui similarity search e top‑k retrieval, costruisci il prompt grounding con citazioni delle fonti e chiami l’LLM. Opzionale: caching e re‑ranking per qualità/costi.
Scelte di stack:
- Vector store persistente vs in‑memory: un archivio in‑memory (es. “Simple Vector Store”) accelera prototipi ma non persiste; per produzione usa Pinecone o soluzioni self‑host (Qdrant, pgvector su Postgres).
- Modelli: Gemini, OpenAI, Cohere, Groq, OpenRouter in n8n sono intercambiabili a livello di orchestrazione. Parti da OpenAI per ampia compatibilità e passa ad alternative per costo/latency.
- Orchestrazione: tieni l’ETL di indicizzazione come workflow batch (cron) separato dalla chat (on‑demand). Questo semplifica governance, rollback e osservabilità.
Insight poco discusso: versiona i tuoi indici (v1, v2, …) e mantieni un “alias” per lo switch atomico del chatbot da vecchia a nuova indicizzazione, evitando “mezzo indice vecchio/mezzo nuovo” durante re‑indicizzazioni lunghe.
[IMG: diagramma con due workflow: Indexing (cron) e Chat (on‑demand), collegati allo stesso vector store]
Ingestione da Drive e Web: normalizzare testi e metadati
Per indicizzare bene serve testo pulito e metadati utili:
- Drive/Docs: estrai testo dai documenti e conserva titolo, percorso/URL, ultimo aggiornamento. Se l’integrazione Drive nativa non è disponibile, puoi usare HTTP Request verso l’API ufficiale (OAuth2) o esportazioni in formati testo/HTML.
- Web scraping: prendi solo il contenuto “main”, ripulisci boilerplate (menu, footer), conserva URL e heading come metadati. Evita di indicizzare cookie banner e pagine rumorose.
Pipeline suggerita:
1) Scheduler (cron) per batch giornaliero/settimanale
2) Recupero lista file/URL
3) Download dei contenuti in testo
4) Normalizzazione (lowercase selettivo, rimozione markup, split per heading)
5) Arricchimento metadati: {source, title, url, section, updatedAt}
Chunking (senza dipendere da uno specifico nodo “splitter”):
// Code Node: chunking ricorsivo semplice
const text = $json.text || '';
const chunkSize = 1000; // ~token-aware (approssimato)
const chunkOverlap = 200;
const chunks = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + chunkSize, text.length);
const chunk = text.slice(start, end);
chunks.push({ chunk, meta: $json.meta });
start = end - chunkOverlap;
if (start < 0) start = 0;
}
return chunks.map(c => ({ json: c }));
Se possiedi già un array di paragrafi/sezioni, puoi usare l’Item Lists Node per “esplodere” in item:
{
"name": "Split Array",
"type": "n8n-nodes-base.itemLists",
"typeVersion": 1,
"parameters": {
"operation": "splitIntoItems",
"property": "results"
}
}
[IMG: canvas ingestione:
Scopri la consulenza →

