This workflow corresponds to n8n.io template #14782 — we link there as the canonical source.
This workflow follows the Agent → Chainllm recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "hiXXL4p3oGe1vagC",
"name": "RAG Chatbot with Small Local LLMs (Ollama) \u2014 No Tool Calling",
"tags": [],
"nodes": [
{
"id": "81fd20e5-7618-49c7-9e4e-d48209237e1b",
"name": "Sticky Note \u2014 Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2528,
560
],
"parameters": {
"width": 700,
"height": 852,
"content": "## RAG Chatbot with Small Local LLMs (Ollama)\n\nA full RAG chatbot that runs entirely on local hardware using Ollama \u2014 no cloud APIs, no tool calling required. A lightweight 7B model classifies intent and plans retrieval; a 14B model synthesizes sourced answers. This **Workflow RAG** approach moves all retrieval logic into deterministic n8n nodes, making it reliable and debuggable even on small models.\n\n## How it works\n\n1. **Webhook** receives a POST request with `chatInput` and `session_id`\n2. **Classify & Decompose** (Qwen2.5:7b) decides if the input is a question or small talk, and generates 1\u20135 focused sub-queries as structured JSON\n3. **Router** sends small talk to a conversational agent; questions enter the RAG pipeline\n4. **Retrieval Loop** runs each sub-query against pgvector using BGE-M3 embeddings, scores chunks, and discards anything below 0.4 relevance\n5. **Answer Generator** (Qwen3:14b) synthesizes a concise sourced answer with file citations and offers to elaborate\n6. **Think Tag Stripper** removes `<think>` reasoning blocks that Qwen3 outputs before the response is returned\n\n## Set up steps\n\n- [ ] Install Ollama and pull the required models: `ollama pull qwen2.5:7b`, `ollama pull qwen3:14b`, `ollama pull bge-m3:latest`\n- [ ] Set up PostgreSQL with the pgvector extension enabled\n- [ ] Create the `chat_histories` table (created automatically by n8n on first run)\n- [ ] Populate the `vector_store` table with your document embeddings using a separate ingestion workflow (chunks must include `title` and `file_path` in metadata)\n- [ ] Add your **Ollama** credentials to all Ollama nodes (host URL, e.g. `http://localhost:11434`)\n- [ ] Add your **Postgres** credentials to the PGVector and Chat Memory nodes\n- [ ] Activate the workflow and POST to the webhook: `{\"chatInput\": \"your question\", \"session_id\": \"unique-session-id\"}`"
},
"typeVersion": 1
},
{
"id": "1a2a3291-5eb5-454c-8219-7894cf791015",
"name": "Sticky Note \u2014 Classification",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1776,
688
],
"parameters": {
"color": 6,
"width": 1020,
"height": 520,
"content": "### 1. Classification & Routing\nA lightweight 7B model classifies the input as a question or small talk and decomposes questions into focused retrieval sub-queries."
},
"typeVersion": 1
},
{
"id": "6b94bfb2-1d74-46b0-aa72-9827a29f223a",
"name": "Sticky Note \u2014 Small Talk",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
-16
],
"parameters": {
"color": 6,
"width": 812,
"height": 540,
"content": "### 2a. Small Talk Path\nHandles greetings and casual conversation with a 14B conversational agent backed by persistent session memory."
},
"typeVersion": 1
},
{
"id": "432d4802-ebbb-4555-b188-72befc0ced83",
"name": "Sticky Note \u2014 Answer Generation",
"type": "n8n-nodes-base.stickyNote",
"position": [
-240,
576
],
"parameters": {
"color": 6,
"width": 1000,
"height": 424,
"content": "### 2b. Answer Generation\nAggregated retrieval results are passed to a 14B model that writes a concise sourced answer (1\u20133 sentences + source list) and offers to elaborate."
},
"typeVersion": 1
},
{
"id": "11e0d33c-93f4-4b14-af30-b7d96efbc561",
"name": "Sticky Note \u2014 RAG Retrieval",
"type": "n8n-nodes-base.stickyNote",
"position": [
-736,
1008
],
"parameters": {
"color": 6,
"width": 2240,
"height": 600,
"content": "### 3. RAG Retrieval Pipeline\nLoops over each sub-query \u2192 embeds with BGE-M3 \u2192 retrieves from pgvector \u2192 filters chunks below 0.4 relevance score \u2192 aggregates per-query results."
},
"typeVersion": 1
},
{
"id": "518a6ba7-40c4-43db-8e6b-2f850415ae94",
"name": "Sticky Note \u2014 Think Tags Warning",
"type": "n8n-nodes-base.stickyNote",
"position": [
416,
48
],
"parameters": {
"color": 4,
"width": 320,
"height": 344,
"content": "\u26a0\ufe0f **Qwen3 Think Tags**\nQwen3 outputs `<think>\u2026</think>` reasoning blocks before its answer. These Code nodes strip them. If you switch to a non-reasoning model (e.g. Qwen2.5, Llama 3), you can delete these two nodes."
},
"typeVersion": 1
},
{
"id": "bc890da2-28e9-452d-a5e5-77ca62cec7d9",
"name": "Split Sub-Queries",
"type": "n8n-nodes-base.splitOut",
"position": [
-672,
1184
],
"parameters": {
"options": {},
"fieldToSplitOut": "=queries"
},
"typeVersion": 1
},
{
"id": "3aa14308-a12d-4d64-bac3-c2ff86a8d5e1",
"name": "Aggregate Matching Chunks",
"type": "n8n-nodes-base.aggregate",
"position": [
928,
1088
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData",
"destinationFieldName": "All chunks for this question"
},
"typeVersion": 1
},
{
"id": "280b31a0-a342-44e1-a981-aa8addb7b1aa",
"name": "Aggregate All Retrieval Results",
"type": "n8n-nodes-base.aggregate",
"position": [
-160,
752
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData",
"destinationFieldName": "Knowledge base retrieval"
},
"typeVersion": 1
},
{
"id": "06899328-33b2-4d12-aa02-13a6115080bf",
"name": "Any chunk?",
"type": "n8n-nodes-base.if",
"position": [
704,
1184
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "66402fe0-918e-4268-8928-f4e83cbb3c4f",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json['Chunk content'] }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f1770405-ca5d-4b2d-b940-1b98dc7b94c6",
"name": "Clean RAG output",
"type": "n8n-nodes-base.set",
"position": [
192,
1184
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1eddb72f-9c99-465b-8f94-0ff0f686b542",
"name": "Chunk content",
"type": "string",
"value": "={{ $json.document.pageContent }}"
},
{
"id": "09fe6c91-2cce-40ff-9f8c-86a6857f0772",
"name": "=Chunk metadata",
"type": "object",
"value": "={\n \"Resource File name\": \"{{ $json.document.metadata.title }}\",\n \"Reference File Path\": \"{{ $json.document.metadata.file_path }}\",\n \"Retrieval relevance score\": {{ $json.score.round(2) }}\n}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "832d0a58-abc2-4df7-ae52-dba54baa8ed2",
"name": "Keep score over 0.4",
"type": "n8n-nodes-base.filter",
"position": [
480,
1184
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9a3f844e-7d19-4631-9876-140118e61b6b",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json['Chunk metadata']['Retrieval relevance score'] }}",
"rightValue": 0.4
}
]
}
},
"typeVersion": 2.2,
"alwaysOutputData": true
},
{
"id": "52ca59d4-6911-486f-ae3e-0263c00eb5a9",
"name": "Say no chunk match",
"type": "n8n-nodes-base.set",
"position": [
928,
1280
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "245fe8f8-b217-4626-bc4d-84f53e47fbbf",
"name": "Retrieval output",
"type": "string",
"value": "=No chunks reached the relevance threshold, the knowledge base was unable to provide information that would be helpful to answer this question."
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9b419289-7657-406f-b8ff-512d14d0e205",
"name": "Prepare loop output",
"type": "n8n-nodes-base.set",
"position": [
1152,
1280
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "838f21a4-f7bc-414e-83da-99fbaca4fcca",
"name": "Query to the knowledge base",
"type": "string",
"value": "={{ $('Loop Over Sub-Queries').first().json.query || $('Loop Over Sub-Queries').item.json.queries }}"
},
{
"id": "10a89085-1937-459f-9721-8715cd51ad39",
"name": "Chunks returned",
"type": "string",
"value": "={{ JSON.stringify($json, null, 2) }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "e29bc19a-329e-404e-a49a-2a878cfcaa62",
"name": "Postgres Chat Memory (Small Talk)",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"position": [
272,
352
],
"parameters": {
"tableName": "chat_histories",
"sessionKey": "={{ $('Webhook').item.json.body.session_id }}",
"sessionIdType": "customKey",
"contextWindowLength": 10
},
"typeVersion": 1.3
},
{
"id": "7b97d99a-7aaa-4188-927f-dfbdcc5322ea",
"name": "Remove Think Tags (RAG Path)",
"type": "n8n-nodes-base.code",
"position": [
528,
640
],
"parameters": {
"jsCode": "// Remove <think> tags and their content\nconst response = $json.output;\nconst cleaned = response.replace(/[\\s\\S]*?<\\/think>/gi, '').trim();\n\nreturn {\n json: {\n output: cleaned\n }\n};"
},
"typeVersion": 2
},
{
"id": "c7e303f8-280d-4459-9d60-eded7bbd1c26",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
-928,
848
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Discussion",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9af19156-d14e-4429-9a53-89efb0ba336f",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.is_question }}",
"rightValue": "false"
}
]
},
"renameOutput": true
},
{
"outputKey": "Question",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "6fc6a4e5-48e0-459a-abe3-69e5750ba2e9",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.is_question }}",
"rightValue": "true"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.3
},
{
"id": "20b2828a-f0aa-4266-9897-6089639656e9",
"name": "JSON Formatter",
"type": "n8n-nodes-base.code",
"position": [
-1136,
848
],
"parameters": {
"jsCode": "// Parse the escaped JSON string from LLM output\nconst rawOutput = $json.output || $json.text || $json.response || \"\";\n\ntry {\n // Remove escaped characters and parse\n const cleaned = rawOutput\n .replace(/\\\\n/g, '')\n .replace(/\\\\/g, '')\n .trim();\n \n const parsed = JSON.parse(cleaned);\n \n return {\n json: {\n is_question: parsed.is_question,\n question_type: parsed.question_type,\n queries: parsed.queries || [],\n notes: parsed.notes || \"\"\n }\n };\n} catch (error) {\n // Fallback if parsing fails\n return {\n json: {\n is_question: false,\n question_type: 0,\n queries: [],\n notes: \"Failed to parse LLM output\",\n raw_output: rawOutput,\n error: error.message\n }\n };\n}"
},
"typeVersion": 2
},
{
"id": "91311fcc-ceb9-48a7-b20f-0bd91969a7db",
"name": "Small Talk AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
128,
128
],
"parameters": {
"text": "={{ $('Webhook').item.json.body.chatInput }}",
"options": {
"systemMessage": "=ROLE\nYou are a friendly assistant for internal company information. You engage in natural conversations with users.\n\nBEHAVIOR\n- Greet users politely and professionally\n- Respond to small talk briefly and in a friendly manner\n- When needed, explain your capabilities: \"I can help you with questions about our internal documents, products, processes, and policies.\"\n- Encourage users to ask specific questions\n- Match the user's language\n- Keep responses short (2\u20134 sentences)\n\nBOUNDARIES\n- No speculation or fabrication\n- For factual questions: \"I'd be happy to look that up in the knowledge base. Please ask me a specific question.\"\n- No personal opinions or advice outside the company context\n\nEXAMPLES\nUser: \"Hello\"\nAssistant: \"Hello! I'm your assistant for internal company information. How can I help you today?\"\n\nUser: \"How are you?\"\nAssistant: \"Thanks for asking! I'm ready to help you with questions about our documents and processes. What would you like to know?\"\n\nUser: \"Thanks\"\nAssistant: \"You're welcome! If you have any more questions, I'm always here for you.\""
},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "0177c211-483d-469e-9373-c205f275b19f",
"name": "Ollama Chat Model (Small Talk \u2014 Qwen3:14b)",
"type": "@n8n/n8n-nodes-langchain.lmChatOllama",
"position": [
144,
352
],
"parameters": {
"model": "qwen3:14b",
"options": {
"numPredict": 4096,
"temperature": 0.7
}
},
"typeVersion": 1
},
{
"id": "a04efb6a-0365-4d88-8bf8-7cf663d53103",
"name": "Ollama Chat Model (Classifier \u2014 Qwen2.5:7b)",
"type": "@n8n/n8n-nodes-langchain.lmChatOllama",
"position": [
-1408,
1072
],
"parameters": {
"model": "qwen2.5:7b",
"options": {
"numPredict": 300,
"temperature": 0.7
}
},
"typeVersion": 1
},
{
"id": "583b4379-e1e3-4821-8611-ae5b104a9572",
"name": "Postgres Chat Memory (RAG Answer)",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"position": [
272,
864
],
"parameters": {
"tableName": "chat_histories",
"sessionKey": "={{ $('Webhook').item.json.body.session_id }}",
"sessionIdType": "customKey",
"contextWindowLength": 10
},
"typeVersion": 1.3
},
{
"id": "2e041581-2d5d-4144-9c39-340d37f1d47b",
"name": "Answer Generator AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
128,
640
],
"parameters": {
"text": "=## User Question: \n{{$('Webhook').item.json.body.chatInput}}\n## Retrieved Knowledge Base Data \n{{ JSON.stringify($json['Knowledge base retrieval']) }}",
"options": {
"systemMessage": "=# ROLE\nYou are a RAG answer generator. You MUST ALWAYS follow the exact 3-step format below.\n\n# STRICTLY FORBIDDEN\n- Long answers on the first response\n- Answers without source citations\n- Additional explanations before the follow-up question\n- Multiple paragraphs in the short answer\n- Answers without the follow-up question at the end\n\n# REQUIRED FORMAT (WITH EVIDENCE)\n\nStep 1: SHORT ANSWER (maximum 1\u20133 sentences)\n<A precise, direct answer to the question>\n\nStep 2: SOURCES (blank line before)\nSources:\n- <Filename> \u2014 <File path>\n- <Filename> \u2014 <File path>\n\nStep 3: FOLLOW-UP (blank line before)\nWould you like a more detailed explanation?\n\n# REQUIRED FORMAT (WITHOUT EVIDENCE)\n\nNo relevant information found in the database.\n\nMay I use general model knowledge to attempt an answer?\n\n# CRITICAL RULES\n1. The short answer must NEVER be longer than 3 sentences\n2. ALWAYS insert a blank line before \"Sources:\"\n3. ALWAYS insert a blank line before the follow-up question\n4. NEVER add additional information after the follow-up question\n5. ALWAYS list all sources used (Filename \u2014 Path)\n6. If multiple chunks reference the same file, list it only once\n\n# LANGUAGE\nMatch the user's language. Default to English if unclear."
},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "e8cfa385-6f6c-4d67-9dcc-664777e246f8",
"name": "Ollama Chat Model (Answer Generator \u2014 Qwen3:14b)",
"type": "@n8n/n8n-nodes-langchain.lmChatOllama",
"position": [
144,
864
],
"parameters": {
"model": "qwen3:14b",
"options": {
"topP": 0.9,
"numPredict": 4096,
"temperature": 0.3,
"repeatPenalty": 1.05
}
},
"typeVersion": 1
},
{
"id": "d84e1c8d-a94d-4b67-bee1-413d707e81eb",
"name": "Loop Over Sub-Queries",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-448,
1184
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "71056de5-2e7e-4bcc-842a-29edd7937098",
"name": "Ollama Embeddings (BGE-M3)",
"type": "@n8n/n8n-nodes-langchain.embeddingsOllama",
"position": [
-144,
1408
],
"parameters": {
"model": "bge-m3:latest"
},
"typeVersion": 1
},
{
"id": "3c5c0ef3-9f38-4f79-926a-68da7bafa27b",
"name": "PGVector Store \u2014 Retrieve Chunks",
"type": "@n8n/n8n-nodes-langchain.vectorStorePGVector",
"position": [
-224,
1184
],
"parameters": {
"mode": "load",
"prompt": "={{ $json.query || $json.queries }}",
"options": {
"metadata": {
"metadataValues": [
{
"name": "user_id",
"value": "={{$json.user_id || \"YOUR_USER_ID\"}}"
}
]
},
"columnNames": {
"values": {
"contentColumnName": "content"
}
}
},
"tableName": "vector_store"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "b56a9ace-af25-4ed0-8d85-23fd4ebc5ffd",
"name": "Remove Think Tags (Small Talk Path)",
"type": "n8n-nodes-base.code",
"position": [
528,
224
],
"parameters": {
"jsCode": "// Remove <think> tags and their content\nconst response = $json.output;\nconst cleaned = response.replace(/[\\s\\S]*?<\\/think>/gi, '').trim();\n\nreturn {\n json: {\n output: cleaned\n }\n};"
},
"typeVersion": 2
},
{
"id": "67f63fd9-b99b-45a0-add5-379d20eb1ad6",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-1696,
848
],
"parameters": {
"path": "rag-chatbot",
"options": {
"binaryPropertyName": "data"
},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "43fdf886-a2f1-4871-98c8-e1ff8d20ea0d",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
976,
448
],
"parameters": {
"options": {}
},
"typeVersion": 1.4
},
{
"id": "b49a2fb5-6c95-459c-aaab-01b639dd3079",
"name": "Understand Request",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
-1472,
848
],
"parameters": {
"text": "={{ $json.body.chatInput }}",
"batching": {},
"messages": {
"messageValues": [
{
"message": "=You are a classifier and query planner for a RAG chatbot. Your job:\n1) Decide if the user input is a genuine question.\n2) If it is a question, assign a question type (1\u20135) from the taxonomy below and produce 1\u20135 focused sub-queries to send to a retrieval workflow.\n3) If it is NOT a question, mark it as not a question and do not generate sub-queries.\n\nTaxonomy (choose one best fit):\n1 = Factual lookup about known entities, product facts, definitions, specs\n2 = How-to / procedure / step-by-step instructions\n3 = Troubleshooting / diagnostics / error understanding\n4 = Policy / pricing / terms / compliance / rules\n5 = Comparative / decision support / pros-cons / selection criteria\n\nStrict rules:\n- Output ONLY valid JSON matching the schema below. No extra text.\n- Keep sub-queries precise, non-redundant, and self-contained.\n- Language: Match the user's language if detectable; otherwise default to German.\n- If not a question: set is_question = false, question_type = 0, queries = [].\n\nOutput JSON schema (all fields required):\n{\n \"is_question\": boolean,\n \"question_type\": 0 | 1 | 2 | 3 | 4 | 5,\n \"queries\": [\n { \"query\": \"string\" }\n ],\n \"notes\": \"short reasoning (1\u20132 sentences)\"\n}\n"
}
]
},
"promptType": "define"
},
"typeVersion": 1.7
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "f8ab270c-ac47-4afa-9fdd-64bd0a778566",
"connections": {
"Switch": {
"main": [
[
{
"node": "Small Talk AI Agent",
"type": "main",
"index": 0
}
],
[
{
"node": "Split Sub-Queries",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Understand Request",
"type": "main",
"index": 0
}
]
]
},
"Any chunk?": {
"main": [
[
{
"node": "Aggregate Matching Chunks",
"type": "main",
"index": 0
}
],
[
{
"node": "Say no chunk match",
"type": "main",
"index": 0
}
]
]
},
"JSON Formatter": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Clean RAG output": {
"main": [
[
{
"node": "Keep score over 0.4",
"type": "main",
"index": 0
}
]
]
},
"Split Sub-Queries": {
"main": [
[
{
"node": "Loop Over Sub-Queries",
"type": "main",
"index": 0
}
]
]
},
"Say no chunk match": {
"main": [
[
{
"node": "Prepare loop output",
"type": "main",
"index": 0
}
]
]
},
"Understand Request": {
"main": [
[
{
"node": "JSON Formatter",
"type": "main",
"index": 0
}
]
]
},
"Keep score over 0.4": {
"main": [
[
{
"node": "Any chunk?",
"type": "main",
"index": 0
}
]
]
},
"Prepare loop output": {
"main": [
[
{
"node": "Loop Over Sub-Queries",
"type": "main",
"index": 0
}
]
]
},
"Small Talk AI Agent": {
"main": [
[
{
"node": "Remove Think Tags (Small Talk Path)",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Sub-Queries": {
"main": [
[
{
"node": "Aggregate All Retrieval Results",
"type": "main",
"index": 0
}
],
[
{
"node": "PGVector Store \u2014 Retrieve Chunks",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Matching Chunks": {
"main": [
[
{
"node": "Prepare loop output",
"type": "main",
"index": 0
}
]
]
},
"Answer Generator AI Agent": {
"main": [
[
{
"node": "Remove Think Tags (RAG Path)",
"type": "main",
"index": 0
}
]
]
},
"Ollama Embeddings (BGE-M3)": {
"ai_embedding": [
[
{
"node": "PGVector Store \u2014 Retrieve Chunks",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Remove Think Tags (RAG Path)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Aggregate All Retrieval Results": {
"main": [
[
{
"node": "Answer Generator AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Postgres Chat Memory (RAG Answer)": {
"ai_memory": [
[
{
"node": "Answer Generator AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Postgres Chat Memory (Small Talk)": {
"ai_memory": [
[
{
"node": "Small Talk AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"PGVector Store \u2014 Retrieve Chunks": {
"main": [
[
{
"node": "Clean RAG output",
"type": "main",
"index": 0
}
]
]
},
"Remove Think Tags (Small Talk Path)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Ollama Chat Model (Small Talk \u2014 Qwen3:14b)": {
"ai_languageModel": [
[
{
"node": "Small Talk AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Ollama Chat Model (Classifier \u2014 Qwen2.5:7b)": {
"ai_languageModel": [
[
{
"node": "Understand Request",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Ollama Chat Model (Answer Generator \u2014 Qwen3:14b)": {
"ai_languageModel": [
[
{
"node": "Answer Generator AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Build a fully local RAG chatbot using Ollama that works without tool calling — ideal for smaller open-source models like Qwen that don't support native function calls. This template lets you run a private, self-hosted AI assistant with retrieval-augmented generation using only…
Source: https://n8n.io/workflows/14782/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Camila IA. Uses postgres, crypto, redis, agent. Webhook trigger; 92 nodes.
V3 Local Agentic RAG AI Agent. Uses documentDefaultDataLoader, memoryPostgresChat, chatTrigger, agent. Webhook trigger; 41 nodes.
Author: Jadai kongolo
Hi! I’m Amanda, a creator of intelligent automations using n8n and Make. I’ve been building AI-powered workflows for over 2 years, always focused on usability and innovation. This one here is very spe
local_RAG. Uses documentDefaultDataLoader, textSplitterRecursiveCharacterTextSplitter, chatTrigger, memoryBufferWindow. Event-driven trigger; 39 nodes.