n8n RAG Agent Tutorial

📝 Blog⏱ 7 min read

n8n RAG Agent Tutorial

Retrieval-Augmented Generation (RAG) lets your AI agent answer questions from your own documents instead of just its training data. n8n's AI Agent node combined with Vector Store nodes makes building RAG agents visual and code-free. This tutorial walks you through building a complete RAG agent in n8n.

What You'll Build

A RAG agent that: 1. Ingests documents (PDFs, web pages, Notion, etc.) 2. Chunks and embeds them into a vector store 3. Retrieves relevant chunks for user questions 4. Generates answers grounded in your documents 5. Cites sources so users can verify

Prerequisites

Architecture Overview

User Question
    ↓
Embed Query → Vector Store Search
    ↓
Top-K Chunks → AI Agent (with context)
    ↓
Generated Answer + Citations

Step 1: Set Up Vector Store

Option A: Pinecone (Managed, Easy)

1. Create Pinecone account 2. Create index: dimension: 1536 (for OpenAI embeddings), metric: cosine 2. Copy API Key and Environment

Option B: Qdrant (Self-Hosted or Cloud)

1. Deploy Qdrant (Docker, Railway, or Qdrant Cloud) 2. Create collection: vector_size: 1536, distance: Cosine 3. Copy URL and API Key

Option C: PostgreSQL + pgvector (Self-Hosted)

1. Enable pgvector extension: CREATE EXTENSION vector; 2. Create table: ``sql CREATE TABLE documents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), content TEXT, metadata JSONB, embedding VECTOR(1536) ); CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops); ``

Add Vector Store Credential in n8n

1. n8n → Credentials → New Credential 2. Search your vector store (Pinecone, Qdrant, PostgreSQL, etc.) 3. Enter credentials 4. Test → Save

Step 2: Document Ingestion Workflow

Create a workflow to ingest documents into the vector store.

Workflow Structure

Trigger (Webhook / Schedule / Manual)
    ↓
Get Documents (HTTP Request / Google Drive / Notion / Local File)
    ↓
Extract Text (Extract from PDF / HTML / Markdown)
    ↓
Split Text (Recursive Character Text Splitter)
    ↓
Generate Embeddings (OpenAI Embeddings)
    ↓
Store in Vector Store (Pinecone / Qdrant / PGVector)

Detailed Nodes

#### 1. Trigger - Webhook for on-demand ingestion - Schedule for periodic re-indexing (daily/weekly) - Manual for one-off runs

#### 2. Get Documents

SourceNode
**PDFs from URL**HTTP Request → Extract from File
**Google Drive**Google Drive (search files) → Download
**Notion**Notion (query database)
**Web pages**HTTP Request → Extract from HTML
**Local files**Read Binary File (self-hosted)

#### 3. Extract Text

#### 4. Split Text (Critical for RAG Quality)

Add Text Splitter node (or use Code node):

const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200, separators: ['\n\n', '\n', ' ', ''] });

const chunks = await splitter.splitText($json.content); return chunks.map((chunk, i) => ({ content: chunk, metadata: { ...$json.metadata, chunkIndex: i } }));; ```

Recommended settings: - chunkSize: 1000 (tokens) - chunkOverlap: 200 (tokens) - Separators: ['\n\n', '\n', ' ', '']

#### 5. Generate Embeddings

Add Embeddings node: - Provider: OpenAI (or Anthropic, Cohere, Ollama) - Model: text-embedding-3-small (1536 dim, cheap) or text-embedding-3-large (3072 dim) - Input: Connect to chunked text output

#### 6. Store in Vector Store

Add your Vector Store node: - Operation: Upsert (insert or update) - Documents: Connect embeddings output - Metadata: Include source, chunkIndex, sourceUrl, ingestedAt

Step 3: RAG Query Workflow

Create a separate workflow for answering questions.

Workflow Structure

User Question (Webhook / Chat Trigger)
    ↓
Embed Query (OpenAI Embeddings)
    ↓
Vector Store Search (Top-K Retrieval)
    ↓
Format Context (Combine chunks + citations)
    ↓
AI Agent (Answer with context)
    ↓
Format Response (Answer + Citations)
    ↓
Respond (Webhook Response / Chat)

Detailed Nodes

Advertisement
Ad Space

#### 1. Trigger - Webhook for API access - Chat Trigger for chat widget - Slack/Discord for bot integration

#### 2. Embed Query

#### 3. Vector Store Search

#### 4. Format Context

Add Code node to format retrieved chunks:

chunks.forEach((chunk, i) => { const citationNum = i + 1; context += [${citationNum}] ${chunk.metadata.source || 'Source'}: ${chunk.content}\n\n; citations.push({ num: citationNum, source: chunk.metadata.sourceUrl || chunk.metadata.source, snippet: chunk.content.substring(0, 200) + '...' }); });

return { context, citations }; ```

#### 5. AI Agent Node

Add AI Agent node: - System Prompt: ``` You are a helpful assistant that answers questions using ONLY the provided context.

Rules: 1. Answer ONLY from the provided context 2. If context doesn't contain the answer, say "I don't have enough information to answer that." 3. Cite sources using [1], [2], etc. format 4. Be concise but complete `` - User Prompt: Question: {{ $json.question }}\n\nContext:\n{{ $json.context }}` - Model: GPT-4o-mini (cheap) or GPT-4o (better reasoning) - Temperature: 0.1 (factual)

#### 6. Format Response

Add Code node: ``javascript return { answer: $json.output, citations: $json.citations, confidence: $json.confidence || 'high' }; ``

Step 4: Chat Interface (Optional)

n8n Chat Trigger

1. Add Chat Trigger node 2. Connect to RAG query workflow 3. Configure: welcome message, placeholder, theme 3. Embed in website via iframe or n8n Chat Cloud

Custom Frontend

// Simple fetch to n8n webhook
const response = await fetch('https://your-n8n.com/webhook/ask', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ question: userInput })
});
const { answer, citations } = await response.json();

Step 5: Test & Optimize

Test Ingestion 1. Run ingestion workflow with test documents 2. Check vector store: verify chunks stored with metadata 3. Verify chunk count and sizes

Test Query 1. Ask questions with known answers 2. Verify citations are correct 3. Check for hallucinations (answers not in context) 4. Adjust `Top K`, `Score Threshold`, `Chunk Size`

Common Tuning Parameters

ParameterDefaultTune If
`chunkSize`1000Answers too long/short
`chunkOverlap`200Context lost between chunks
`topK`4Missing context / too much noise
`scoreThreshold`0.7Irrelevant chunks retrieved
`temperature`0.1Hallucinations / too rigid

Advanced: Hybrid Search

Combine keyword + vector search for better recall:

1. Vector Search (semantic) 2. Keyword Search (BM25/PostgreSQL full-text) 3. Reciprocal Rank Fusion to combine

In n8n: Run both searches in parallel → Code node → RRF merge → Feed to agent.

Advanced: Metadata Filtering

Filter by metadata for multi-tenant or categorized search:

// In Vector Store Search node
Filter: {
  tenantId: '{{ $json.user.tenantId }}',
  category: '{{ $json.category }}',
  date: { $gte: '2024-01-01' }
}

Advanced: Conversational Memory

Add memory to your RAG agent for multi-turn conversations:

1. AI Agent Node → Memory section 2. Select: Window Buffer (last N turns) or Vector Store (semantic) 3. Configure session ID from trigger (user ID, session ID)

Cost Estimation

ComponentMonthly Cost (10K queries)
n8n Cloud Pro$50
OpenAI Embeddings (3-small)~$3
OpenAI GPT-4o-mini~$15
Pinecone (Starter)$70
**Total****~$138/mo**

Self-hosted n8n: ~$30-50/mo (infrastructure only)

Common Issues

IssueFix
`401 Unauthorized` on vector storeCheck API key, environment, URL
`400 Dimension mismatch`Embedding model dim ≠ index dim (1536 vs 3072)
Empty resultsLower score threshold, check ingestion
HallucinationsLower temperature, stricter system prompt
Slow queriesReduce topK, use smaller embeddings
Citations wrongCheck context formatting, metadata

Related Tutorials

Frequently Asked Questions

n8n supports Pinecone, Qdrant, Chroma, Weaviate, PostgreSQL+pgvector, Redis, Elasticsearch, and any vector store with a compatible node. Community nodes add more options.

Start with 1000 tokens and 200 overlap. For technical docs, try 500/100. For long-form content, 1500/300. Test with your specific documents.

Re-run the ingestion workflow with the same document IDs. The vector store Upsert operation will update existing vectors. For deletions, use the Delete operation with the document ID filter.

Yes. Enable memory in the AI Agent node (Window Buffer, Summary, or Vector Store memory) and pass a session ID from your chat trigger to maintain context across turns.

Advertisement

Related Articles