This workflow follows the Agent → Chat Trigger 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 →
{
"name": "RAG AI Agent Template V5",
"nodes": [
{
"parameters": {
"model": "gpt-4.1-mini",
"options": {}
},
"id": "c5cf0bd5-c789-4357-bc62-0cf37339158c",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1,
"position": [
-816,
368
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsonMode": "expressionData",
"jsonData": "={{ $json.content || $json.data || $json.text || $json.concatenated_data }}",
"options": {
"metadata": {
"metadataValues": [
{
"name": "=file_id",
"value": "={{ $('Set File ID').first().json.file_id }}"
},
{
"name": "file_title",
"value": "={{ $('Set File ID').first().json.file_title }}"
}
]
}
}
},
"id": "516e500d-6d1f-4add-8826-3104158f8d19",
"name": "Default Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"typeVersion": 1,
"position": [
992,
1104
]
},
{
"parameters": {
"model": "text-embedding-3-small",
"options": {}
},
"id": "0ea0d942-70a1-4816-8839-1408a936f969",
"name": "Embeddings OpenAI1",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"typeVersion": 1,
"position": [
816,
1152
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "## Agent Tools for RAG",
"height": 528.85546469693,
"width": 583.4552380860637,
"color": 4
},
"id": "c502bc2b-ea0e-4161-877a-e93249a0a4ec",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
0,
0
]
},
{
"parameters": {
"content": "## Tool to Add a Google Drive File to Vector DB",
"height": 867,
"width": 3073,
"color": 5
},
"id": "26ae0e8e-33d6-4045-9419-1b696426aefe",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1744,
544
]
},
{
"parameters": {
"operation": "download",
"fileId": {
"__rl": true,
"value": "={{ $('Set File ID').item.json.file_id }}",
"mode": "id"
},
"options": {
"googleFileConversion": {
"conversion": {
"docsToFormat": "text/plain"
}
}
}
},
"id": "d4a482e9-dd96-4fa9-9da7-cbedb195cebc",
"name": "Download File",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
-656,
832
],
"executeOnce": true,
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"value": "1yfaYWtBKooyiiJbM3hQRda1v6aK0akdo",
"mode": "list",
"cachedResultName": "Neon n8n",
"cachedResultUrl": "https://drive.google.com/drive/folders/1yfaYWtBKooyiiJbM3hQRda1v6aK0akdo"
},
"event": "fileCreated",
"options": {}
},
"id": "da212e8b-3ecc-44c2-9a44-d0719308191a",
"name": "File Created",
"type": "n8n-nodes-base.googleDriveTrigger",
"typeVersion": 1,
"position": [
-1680,
672
],
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"value": "1yfaYWtBKooyiiJbM3hQRda1v6aK0akdo",
"mode": "list",
"cachedResultName": "Neon n8n",
"cachedResultUrl": "https://drive.google.com/drive/folders/1yfaYWtBKooyiiJbM3hQRda1v6aK0akdo"
},
"event": "fileUpdated",
"options": {}
},
"id": "1fa80cf6-0c63-4a23-8836-9924c2327e0d",
"name": "File Updated",
"type": "n8n-nodes-base.googleDriveTrigger",
"typeVersion": 1,
"position": [
-1680,
832
],
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "text",
"options": {}
},
"id": "37544f87-630a-49b7-96ad-176d81eb296b",
"name": "Extract Document Text",
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
48,
1248
],
"alwaysOutputData": true
},
{
"parameters": {},
"id": "c89b4001-13ba-4828-a5d6-16fe1bcf7521",
"name": "Postgres Chat Memory",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"typeVersion": 1,
"position": [
-672,
368
],
"notesInFlow": false,
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "10646eae-ae46-4327-a4dc-9987c2d76173",
"name": "file_id",
"value": "={{ $json.id }}",
"type": "string"
},
{
"id": "f4536df5-d0b1-4392-bf17-b8137fb31a44",
"name": "file_type",
"value": "={{ $json.mimeType }}",
"type": "string"
},
{
"id": "77d782de-169d-4a46-8a8e-a3831c04d90f",
"name": "file_title",
"value": "={{ $json.name }}",
"type": "string"
},
{
"id": "9bde4d7f-e4f3-4ebd-9338-dce1350f9eab",
"name": "file_url",
"value": "={{ $json.webViewLink }}",
"type": "string"
}
]
},
"options": {}
},
"id": "dde7c46d-93b2-4192-9715-d88cd2a6515c",
"name": "Set File ID",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-1328,
832
]
},
{
"parameters": {
"content": "## RAG AI Agent with Chat Interface",
"height": 464.8027193303974,
"width": 1035.6381264595484
},
"id": "9faf8f9f-5995-4b73-abb9-a3ce34fc06d6",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1040,
64
]
},
{
"parameters": {
"options": {}
},
"id": "4f4cd0bc-c934-4662-b397-7c9b36dcb77d",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
-176,
144
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "9a9a245e-f1a1-4282-bb02-a81ffe629f0f",
"name": "chatInput",
"value": "={{ $json?.chatInput || $json.body.chatInput }}",
"type": "string"
},
{
"id": "b80831d8-c653-4203-8706-adedfdb98f77",
"name": "sessionId",
"value": "={{ $json?.sessionId || $json.body.sessionId}}",
"type": "string"
}
]
},
"options": {}
},
"id": "7bb5b8fa-306c-44d7-a6aa-c6f31c3ccace",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-736,
144
]
},
{
"parameters": {
"public": true,
"options": {}
},
"id": "30d0381f-54de-4354-92c7-8d912d71c1d4",
"name": "When chat message received",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"typeVersion": 1.1,
"position": [
-1008,
144
]
},
{
"parameters": {
"httpMethod": "POST",
"path": "af814d99-8106-4daa-8821-28a93bafe55b",
"authentication": "headerAuth",
"responseMode": "responseNode",
"options": {}
},
"id": "8766f397-3b49-452a-bf94-9025ec8b7397",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-1008,
352
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "pdf",
"options": {}
},
"id": "854c9afb-49a3-495c-bf16-c7054bba9f86",
"name": "Extract PDF Text",
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
48,
1072
]
},
{
"parameters": {
"aggregate": "aggregateAllItemData",
"options": {}
},
"id": "4eba3ef6-a627-4c36-81b6-fbd56bd2a1a7",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"typeVersion": 1,
"position": [
256,
640
]
},
{
"parameters": {
"fieldsToSummarize": {
"values": [
{
"aggregation": "concatenate",
"field": "data"
}
]
},
"options": {}
},
"id": "ecd85489-99c2-4829-bd32-fa0b71bb8c07",
"name": "Summarize",
"type": "n8n-nodes-base.summarize",
"typeVersion": 1,
"position": [
464,
720
]
},
{
"parameters": {
"promptType": "define",
"text": "={{ $json.chatInput }}",
"options": {
"systemMessage": "You are a personal assistant who helps answer questions from a corpus of documents. The documents are either text based (Txt, docs, extracted PDFs, etc.) or tabular data (CSVs or Excel documents).\n\nYou are given tools to perform RAG in the 'documents' table, look up the documents available in your knowledge base in the 'document_metadata' table, extract all the text from a given document, and query the tabular files with SQL in the 'document_rows' table.\n\nAlways start by performing RAG unless the question requires a SQL query for tabular data (fetching a sum, finding a max, something a RAG lookup would be unreliable for). If RAG doesn't help, then look at the documents that are available to you, find a few that you think would contain the answer, and then analyze those.\n\nUse the search_memory_nodes tool to search the knowledge graph.\n\nAlways tell the user if you didn't find the answer. Don't make something up just to please them."
}
},
"id": "92adb1ab-11be-47bf-bf1a-836cc00a74b1",
"name": "RAG AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 1.6,
"position": [
-528,
144
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "2ae7faa7-a936-4621-a680-60c512163034",
"leftValue": "=FixedExpression{{ $('Set File ID').item.json.file_type }}FixedExpressionRename Output FixedExpression{{ $('Set File ID').item.json.file_type }}",
"rightValue": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "fc193b06-363b-4699-a97d-e5a850138b0e",
"leftValue": "={{ $('Set File ID').item.json.file_type }}",
"rightValue": "=application/vnd.google-apps.spreadsheet",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"leftValue": "={{ $('Set File ID').item.json.file_type }}",
"rightValue": "application/pdf",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "5fe78f9b-2ff3-4adc-954e-53bfce35c142"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "b69f5605-0179-4b02-9a32-e34bb085f82d",
"leftValue": "={{ $('Set File ID').item.json.file_type }}",
"rightValue": "application/vnd.google-apps.document",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"id": "b467dbbd-b0c2-408c-bace-3f5ce9db9d35",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
-464,
800
]
},
{
"parameters": {
"operation": "xlsx",
"options": {}
},
"id": "c86c3a2e-1c72-41ea-b2da-83736f9c84f6",
"name": "Extract from Excel",
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
48,
640
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "f422e2e0-381c-46ea-8f38-3f58c501d8b9",
"name": "schema",
"value": "={{ $('Extract from Excel').isExecuted ? $('Extract from Excel').first().json.keys().toJsonString() : $('Extract from CSV').first().json.keys().toJsonString() }}",
"type": "string"
},
{
"id": "bb07c71e-5b60-4795-864c-cc3845b6bc46",
"name": "data",
"value": "={{ $json.concatenated_data }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
880,
656
],
"id": "ef55092c-97e1-47ab-9714-d1278d5deb06",
"name": "Set Schema"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
48,
816
],
"id": "278000fc-13ab-429a-9870-c7fd0b051c95",
"name": "Extract from CSV"
},
{
"parameters": {
"content": "## Run Each Node Once to Set Up Database Tables",
"height": 300,
"width": 680,
"color": 3
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-1744,
224
],
"typeVersion": 1,
"id": "3ebed7b3-0aff-4a9c-b50c-b810888ec4ee",
"name": "Sticky Note3"
},
{
"parameters": {
"operation": "executeQuery",
"query": "CREATE TABLE document_metadata (\n id TEXT PRIMARY KEY,\n title TEXT,\n url TEXT,\n created_at TIMESTAMP DEFAULT NOW(),\n schema TEXT\n);",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
-1632,
320
],
"id": "fedafd7a-0947-45b5-90df-c40051a8b263",
"name": "Create Document Metadata Table",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "CREATE TABLE document_rows (\n id SERIAL PRIMARY KEY,\n dataset_id TEXT REFERENCES document_metadata(id),\n row_data JSONB -- Store the actual row data\n);",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
-1328,
320
],
"id": "8ba7103a-e1e3-45d6-8c74-c0244b3e0271",
"name": "Create Document Rows Table (for Tabular Data)",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"descriptionType": "manual",
"toolDescription": "Use this tool to fetch all available documents, including the table schema if the file is a CSV or Excel file.",
"operation": "select",
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "document_metadata",
"mode": "list",
"cachedResultName": "document_metadata"
},
"returnAll": true,
"options": {}
},
"type": "n8n-nodes-base.postgresTool",
"typeVersion": 2.5,
"position": [
-544,
368
],
"id": "69d858ca-7057-4803-b15a-cdbe5e71b21e",
"name": "List Documents",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"descriptionType": "manual",
"toolDescription": "Given a file ID, fetches the text from the document.",
"operation": "executeQuery",
"query": "SELECT \n string_agg(text, ' ') as document_text\nFROM documents_pg\n WHERE metadata->>'file_id' = $1\nGROUP BY metadata->>'file_id';",
"options": {
"queryReplacement": "={{ $fromAI('file_id') }}"
}
},
"type": "n8n-nodes-base.postgresTool",
"typeVersion": 2.5,
"position": [
-400,
368
],
"id": "a308c83d-9963-4555-8413-60bcead6ce2d",
"name": "Get File Contents",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"descriptionType": "manual",
"toolDescription": "Run a SQL query - use this to query from the document_rows table once you know the file ID you are querying. dataset_id is the file_id and you are always using the row_data for filtering, which is a jsonb field that has all the keys from the file schema given in the document_metadata table.\n\nExample query:\n\nSELECT AVG((row_data->>'revenue')::numeric)\nFROM document_rows\nWHERE dataset_id = '123';\n\nExample query 2:\n\nSELECT \n row_data->>'category' as category,\n SUM((row_data->>'sales')::numeric) as total_sales\nFROM dataset_rows\nWHERE dataset_id = '123'\nGROUP BY row_data->>'category';",
"operation": "executeQuery",
"query": "{{ $fromAI('sql_query') }}",
"options": {}
},
"type": "n8n-nodes-base.postgresTool",
"typeVersion": 2.5,
"position": [
-256,
368
],
"id": "2a3e56e9-3b26-46c2-8edb-b1690e7643d8",
"name": "Query Document Rows",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"typeVersion": 1.2,
"position": [
128,
352
],
"id": "70e35e3a-f75e-4dd3-9918-b13fc1b884ff",
"name": "Embeddings OpenAI2",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {
"reset": false
}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
-1504,
672
],
"id": "b3548d62-87ac-4bdd-9e1a-f05072570716",
"name": "Loop Over Items"
},
{
"parameters": {
"operation": "upsert",
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "document_metadata",
"mode": "list",
"cachedResultName": "document_metadata"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"id": "={{ $('Set File ID').item.json.file_id }}",
"title": "={{ $('Set File ID').item.json.file_title }}",
"url": "={{ $('Set File ID').item.json.file_url }}"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": true,
"defaultMatch": true,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "title",
"displayName": "title",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": false
},
{
"id": "url",
"displayName": "url",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": false,
"removed": false
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": false
},
{
"id": "schema",
"displayName": "schema",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": false,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
-816,
688
],
"id": "54b095ce-3182-43d3-be35-2286dd6ebcc0",
"name": "Insert Document Metadata",
"executeOnce": true,
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "document_rows",
"mode": "list",
"cachedResultName": "document_rows"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"dataset_id": "={{ $('Set File ID').item.json.file_id }}",
"row_data": "={{ $json.toJsonString().replaceAll(/'/g, \"''\") }}"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": false,
"defaultMatch": true,
"display": true,
"type": "number",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "dataset_id",
"displayName": "dataset_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "row_data",
"displayName": "row_data",
"required": false,
"defaultMatch": false,
"display": true,
"type": "object",
"canBeUsedToMatch": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
256,
816
],
"id": "61e77b70-07a9-4da2-92ac-0f960f6b2ce3",
"name": "Insert Table Rows",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "upsert",
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"table": {
"__rl": true,
"value": "document_metadata",
"mode": "list",
"cachedResultName": "document_metadata"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"id": "={{ $('Set File ID').item.json.file_id }}",
"schema": "={{ $json.schema }}"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": true,
"defaultMatch": true,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "title",
"displayName": "title",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": false,
"removed": true
},
{
"id": "url",
"displayName": "url",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": false,
"removed": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": false
},
{
"id": "schema",
"displayName": "schema",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": false,
"removed": false
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1104,
656
],
"id": "e948626c-11b3-45e3-a5c9-c481806cfa3f",
"name": "Update Schema for Document Metadata",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "## \ud83d\ude80 Ultimate n8n Agentic RAG Template\n\n**Author:** [Cole Medin](https://www.youtube.com/@ColeMedin)\n\n## What is this?\nThis template provides a complete implementation of an **Agentic RAG (Retrieval Augmented Generation)** system in n8n that can be extended easily for your specific use case and knowledge base. Unlike standard RAG which only performs simple lookups, this agent can reason about your knowledge base, self-improve retrieval, and dynamically switch between different tools based on the specific question. This agent uses Postgres with PGVector for the main knowledgebase and Graphiti + Neo4j for the knowledge graph. You can use Supabase, Neon, self host Postgres, etc.\n\n## Why Agentic RAG?\nStandard RAG has significant limitations:\n- Poor analysis of numerical/tabular data\n- Missing context due to document chunking\n- Inability to connect information across documents\n- No dynamic tool selection based on question type\n\n## What makes this template powerful:\n- **Intelligent tool selection**: Switches between RAG lookups, SQL queries, knowledge graph searches, or full document retrieval based on the question\n- **Complete document context**: Accesses entire documents when needed instead of just chunks\n- **Accurate numerical analysis**: Uses SQL for precise calculations on spreadsheet/tabular data\n- **Cross-document insights**: Connects information across your entire knowledge base\n- **Multi-file processing**: Handles multiple documents in a single workflow loop\n- **Efficient storage**: Uses JSONB in Postgres to store tabular data without creating new tables for each CSV\n\n## Getting Started\n1. Run the table creation nodes first to set up your database tables in Postgres\n2. Upload your documents through Google Drive (or swap out for a different file storage solution)\n3. The agent will process them automatically (chunking text, storing tabular data in Postgres)\n4. Start asking questions that leverage the agent's multiple reasoning approaches\n\n## Customization\nThis template provides a solid foundation that you can extend by:\n- Tuning the system prompt for your specific use case\n- Adding document metadata like summaries\n- Implementing more advanced RAG techniques\n- Optimizing for larger knowledge bases",
"height": 1224,
"width": 540,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-2320,
224
],
"typeVersion": 1,
"id": "804b3027-63f3-4c10-9a51-b4c7d779725d",
"name": "Sticky Note9"
},
{
"parameters": {
"topN": 4
},
"type": "@n8n/n8n-nodes-langchain.rerankerCohere",
"typeVersion": 1,
"position": [
320,
352
],
"id": "18ec526c-fcf0-4aa7-93e6-172fcef75a20",
"name": "Reranker Cohere",
"credentials": {
"cohereApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "retrieve-as-tool",
"toolDescription": "Use RAG to look up information in the knowledgebase.",
"tableName": "documents_pg",
"topK": 25,
"useReranker": true,
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStorePGVector",
"typeVersion": 1.3,
"position": [
192,
144
],
"id": "050dc458-3254-406f-95f1-f0c0e3a5cb39",
"name": "Postgres PGVector Store",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "insert",
"tableName": "documents_pg",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStorePGVector",
"typeVersion": 1.3,
"position": [
880,
848
],
"id": "3d2ed4d0-2f28-4ced-8bbe-4a0a9483e357",
"name": "Postgres PGVector Store1",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'documents_pg') THEN\n EXECUTE 'DELETE FROM documents_pg WHERE metadata->>''file_id'' LIKE ''%' || $1 || '%''';\n END IF;\nEND\n$$;",
"options": {
"queryReplacement": "={{ $json.file_id }}"
}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
-1152,
688
],
"id": "c5e2bf01-4854-4edf-bd89-517411e199d2",
"name": "Delete Old Data Rows",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM document_rows\nWHERE dataset_id LIKE '%' || $1 || '%';",
"options": {
"queryReplacement": "={{ $('Set File ID').item.json.file_id }}"
}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
-976,
848
],
"id": "b11bb82b-bb32-4912-803c-993f854bb828",
"name": "Delete Old Doc Rows",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"url": "https://www.googleapis.com/drive/v3/files",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleDriveOAuth2Api",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "q",
"value": "'1g7rnJHz14qbKel3CchFM6S0osMgXXblT' in parents and trashed = true"
},
{
"name": "fields",
"value": "files(id,name,mimeType,webViewLink,trashed,trashedTime)"
},
{
"name": "pageSize",
"value": "1000"
}
]
},
"options": {}
},
"id": "4e8066e9-783e-4ff1-b130-d306568b5457",
"name": "Get Trashed Files via API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-1440,
1552
],
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Parse the response from Google Drive API\nconst response = $input.first().json;\nconst trashedFiles = response.files || [];\n\nif (trashedFiles.length === 0) {\n return [{ message: 'No trashed files found', count: 0 }];\n}\n\n// Return each file as a separate item for processing\nreturn trashedFiles.map(file => ({\n file_id: file.id,\n file_name: file.name,\n file_type: file.mimeType,\n file_url: file.webViewLink,\n trashed_time: file.trashedTime\n}));"
},
"id": "5456628e-c1fb-43b2-8ca2-143ee4d46ac1",
"name": "Parse Trashed Files",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1248,
1552
]
},
{
"parameters": {
"conditions": {
"options": {
"conditions": [
{
"value1": "={{ $json.file_id }}",
"operation": "isNotEmpty"
}
]
}
},
"options": {}
},
"id": "5bc57683-26fe-47db-90c7-db01d4f7ef1a",
"name": "Has Files to Delete?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-1040,
1552
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT id FROM document_metadata WHERE id = '{{ $json.file_id }}'",
"options": {}
},
"id": "98550092-8d38-412c-a33f-93f06583aa49",
"name": "Check If Exists in DB",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
-848,
1552
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "992a20a8-5b6a-4ea4-b021-7458435e131a",
"leftValue": "",
"rightValue": "",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "5d1918c0-2864-4059-9dd8-a010e078a9c7",
"name": "Exists in DB?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-640,
1552
]
},
{
"parameters": {
"content": "## Vector Store Cleanup (Periodically)\nScan the Google Drive Folder regularely and deletes non existent documents from the vector store as well.",
"height": 305,
"width": 1976,
"color": 6
},
"id": "a13f6b7b-c4a3-412c-a929-4ca089da14ad",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1744,
1440
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM document_metadata WHERE id = '{{ $('Parse Trashed Files').first().json.file_id }}'",
"options": {}
},
"id": "ad7268cb-a691-4b34-8814-e7229203e282",
"name": "Delete Metadata",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
-32,
1552
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"id": "83c43863-d7a9-4a0b-9ecc-d1275478cbf0",
"name": "Check Every 15 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [
-1648,
1552
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "DO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'documents_pg') THEN\n EXECUTE 'DELETE FROM documents_pg WHERE metadata->>''file_id'' LIKE ''%' || $1 || '%''';\n END IF;\nEND\n$$;",
"options": {
"queryReplacement": "={{ $('Parse Trashed Files').item.json.file_id }}"
}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
-416,
1552
],
"id": "1fdd3185-27a9-4b25-a302-bc408eb8931f",
"name": "Delete Old Data Rows1",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM document_rows\nWHERE dataset_id LIKE '%' || $1 || '%';",
"options": {
"queryReplacement": "={{ $('Parse Trashed Files').first().json.file_id }}"
}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
-224,
1552
],
"id": "aceb5934-6f3a-49be-b0cd-65cef4607507",
"name": "Delete Old Doc Rows1",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
"typeVersion": 1,
"position": [
1104,
1264
],
"id": "d8c580f6-b2fd-4da1-8749-019501131d81",
"name": "Recursive Character Text Splitter"
},
{
"parameters": {
"code": {
"execute": {
"code": "const { PromptTemplate } = require('@langchain/core/prompts');\n\nconst documentContent = $input.item.json?.data || $input.item.json?.text;\nconst maxChunkSize = 1000;\nconst minChunkSize = 400;\n\nif (!documentContent) {\n throw new Error('No document found in input');\n}\n\nconst llm = await this.getInputConnectionData('ai_languageModel', 0);\n\nfunction cleanText(text) {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\nconst chunks = [];\nlet remainingText = cleanText(documentContent);\nlet chunkNumber = 1;\n\nif (remainingText.length <= maxChunkSize) {\n chunks.push({\n content: remainingText,\n chunk: chunkNumber,\n chunk_size: remainingText.length\n });\n} else {\n while (remainingText) {\n const textToAnalyze = remainingText.substring(0, maxChunkSize);\n \n const promptText = `You are analyzing a document to find the best transition point to split it into meaningful sections.\n\nYour goal: Keep related content together and split where topics naturally transition.\n\nRead this text carefully and identify where one topic/section ends and another begins:\n\n${textToAnalyze}\n\nFind the best transition point that occurs BEFORE character position ${maxChunkSize}.\n\nLook for:\n- Section headings or topic changes\n- Paragraph boundaries where the subject shifts\n- Complete conclusions before new ideas start\n- Natural breaks between different aspects of the content\n\nOutput the LAST WORD that appears right before your chosen split point.\nJust the single word itself, nothing else.\nExample: If you want to split after \"The company was founded in 2022.\" then output: \"2022\"`;\n \n const prompt = PromptTemplate.fromTemplate(promptText);\n const chain = prompt.pipe(llm);\n \n let breakPoint = maxChunkSize;\n \n try {\n const response = await chain.invoke();\n const responseText = response.content || response.text || response.toString();\n const breakWord = responseText.trim();\n \n if (breakWord) {\n // Find the last occurrence of this word in the text to analyze\n const wordIndex = textToAnalyze.lastIndexOf(breakWord);\n if (wordIndex !== -1) {\n // Split after the word (including any punctuation that follows)\n breakPoint = wordIndex + breakWord.length;\n // Move past any punctuation or single space after the word\n while (breakPoint < textToAnalyze.length && \n (textToAnalyze[breakPoint] === '.' || \n textToAnalyze[breakPoint] === '!' || \n textToAnalyze[breakPoint] === '?' || \n textToAnalyze[breakPoint] === ',' || \n textToAnalyze[breakPoint] === ';' || \n textToAnalyze[breakPoint] === ':' || \n textToAnalyze[breakPoint] === ' ')) {\n breakPoint++;\n // Stop after moving past one space\n if (textToAnalyze[breakPoint - 1] === ' ') break;\n }\n breakPoint = Math.min(breakPoint, maxChunkSize);\n }\n }\n } catch (error) {\n console.log('LLM failed to determine breakpoint, using max size:', error.message);\n breakPoint = maxChunkSize;\n }\n \n const chunk = remainingText.substring(0, breakPoint).trim();\n \n if (chunk) {\n chunks.push({\n content: chunk,\n chunk: chunkNumber,\n chunk_size: chunk.length\n });\n chunkNumber++;\n }\n \n remainingText = remainingText.substring(breakPoint).trim();\n \n if (!remainingText) {\n break;\n }\n }\n}\n\n// Merge chunks that are below minimum size with adjacent chunks if possible\nlet i = 0;\nwhile (i < chunks.length) {\n if (chunks[i].chunk_size < minChunkSize) {\n // Try to merge with next chunk first if it exists and won't exceed max\n if (i + 1 < chunks.length && \n chunks[i].chunk_size + chunks[i + 1].chunk_size <= maxChunkSize) {\n // Merge current with next\n chunks[i].content += ' ' + chunks[i + 1].content;\n chunks[i].chunk_size = chunks[i].content.length;\n chunks.splice(i + 1, 1);\n // Don't increment i, check this chunk again in case it's still small\n } \n // Otherwise try to merge with previous chunk if it exists and won't exceed max\n else if (i > 0 && \n chunks[i - 1].chunk_size + chunks[i].chunk_size <= maxChunkSize) {\n // Merge current into previous\n chunks[i - 1].content += ' ' + chunks[i].content;\n chunks[i - 1].chunk_size = chunks[i - 1].content.length;\n chunks.splice(i, 1);\n // Don't increment i, we removed current chunk\n } else {\n // Can't merge without exceeding max, move on\n i++;\n }\n } else {\n i++;\n }\n}\n\nconst returnData = chunks.map(chunk => ({\n json: chunk\n}));\n\nreturn returnData;"
}
},
"inputs": {
"input": [
{
"type": "ai_languageModel",
"maxConnections": 1,
"required": true
},
{
"type": "main",
"required": true
}
]
},
"outputs": {
"output": [
{
"type": "main"
}
]
}
},
"type": "@n8n/n8n-nodes-langchain.code",
"typeVersion": 1,
"position": [
320,
976
],
"id": "7877c994-6527-425c-aa4f-190d8344ee2d",
"name": "LangChain Code"
},
{
"parameters": {
"model": {
"__rl": true,
"value": "gpt-4.1",
"mode": "list",
"cachedResultName": "gpt-4.1"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.2,
"position": [
432,
1280
],
"id": "a803be08-7d91-47ad-8183-81a562ee3aff",
"name": "OpenAI Chat Model1",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"connectionType": "sse",
"operation": "executeTool",
"toolName": "add_memory",
"toolParameters": "={\n \"name\": {{ JSON.stringify($('Download File').item.json.title) }},\n \"episode_body\": {{ JSON.stringify($input.item.json?.data || $input.item.json?.text) }}\n}"
},
"type": "n8n-nodes-mcp.mcpClient",
"typeVersion": 1,
"position": [
608,
1120
],
"id": "8528f234-7761-4155-9550-20bfa6fb98d3",
"name": "MCP Client - Add to Knowledge Graph",
"credentials": {
"mcpClientSseApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"connectionType": "sse",
"operation": "executeTool",
"toolName": "search_memory_nodes",
"toolParameters": "={\"query\": {{ JSON.stringify($fromAI('query')) }}}"
},
"type": "n8n-nodes-mcp.mcpClientTool",
"typeVersion": 1,
"position": [
-128,
368
],
"id": "36e8af33-29b3-4b1f-bf64-d8e9f3b26739",
"name": "MCP Client",
"credentials": {
"mcpClientSseApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "RAG AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Download File": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"File Created": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Extract Document Text": {
"main": [
[
{
"node": "MCP Client - Add to Knowledge Graph",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI1": {
"ai_embedding": [
[
{
"node": "Postgres PGVector Store1",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Postgres PGVector Store1",
"type": "ai_document",
"index": 0
}
]
]
},
"Postgres Chat Memory": {
"ai_memory": [
[
{
"node": "RAG AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Set File ID": {
"main": [
[
{
"node": "Delete Old Data Rows",
"type": "main",
"index": 0
}
]
]
},
"File Updated": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "RAG AI Agent",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Extract PDF Text": {
"main": [
[
{
"node": "LangChain Code",
"type": "main",
"index": 0
},
{
"node": "MCP Client - Add to Knowledge Graph",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "Summarize",
"type": "main",
"index": 0
}
]
]
},
"Summarize": {
"main": [
[
{
"node": "Set Schema",
"type": "main",
"index": 0
},
{
"node": "Postgres PGVector Store1",
"type": "main",
"index": 0
},
{
"node": "MCP Client - Add to Knowledge Graph",
"type": "main",
"index": 0
}
]
]
},
"RAG AI Agent": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Extract from Excel",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract from CSV",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract PDF Text",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract Document Text",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract Document Text",
"type": "main",
"index": 0
}
]
]
},
"Extract from Excel": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
},
{
"node": "Insert Table Rows",
"type": "main",
"index": 0
}
]
]
},
"Set Schema": {
"main": [
[
{
"node": "Update Schema for Document Metadata",
"type": "main",
"index": 0
}
]
]
},
"Extract from CSV": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
},
{
"node": "Insert Table Rows",
"type": "main",
"index": 0
}
]
]
},
"Create Document Metadata Table": {
"main": [
[]
]
},
"List Documents": {
"ai_tool": [
[
{
"node": "RAG AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get File Contents": {
"ai_tool": [
[
{
"node": "RAG AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Query Document Rows": {
"ai_tool": [
[
{
"node": "RAG AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Embeddings OpenAI2": {
"ai_embedding": [
[
{
"node": "Postgres PGVector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Set File ID",
"type": "main",
"index": 0
}
]
]
},
"Insert Document Metadata": {
"main": [
[
{
"node": "Download File",
"type": "main",
"index": 0
}
]
]
},
"Reranker Cohere": {
"ai_reranker": [
[
{
"node": "Postgres PGVector Store",
"type": "ai_reranker",
"index": 0
}
]
]
},
"Postgres PGVector Store": {
"ai_tool": [
[
{
"node": "RAG AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Postgres PGVector Store1": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Delete Old Data Rows": {
"main": [
[
{
"node": "Delete Old Doc Rows",
"type": "main",
"index": 0
}
]
]
},
"Delete Old Doc Rows": {
"main": [
[
{
"node": "Insert Document Metadata",
"type": "main",
"index": 0
}
]
]
},
"Get Trashed Files via API": {
"main": [
[
{
"node": "Parse Trashed Files",
"type": "main",
"index": 0
}
]
]
},
"Parse Trashed Files": {
"main": [
[
{
"node": "Has Files to Delete?",
"type": "main",
"index": 0
}
]
]
},
"Has Files to Delete?": {
"main": [
[
{
"node": "Check If Exists in DB",
"type": "main",
"index": 0
}
]
]
},
"Check If Exists in DB": {
"main": [
[
{
"node": "Exists in DB?",
"type": "main",
"index": 0
}
]
]
},
"Exists in DB?": {
"main": [
[
{
"node": "Delete Old Data Rows1",
"type": "main",
"index": 0
}
]
]
},
"Check Every 15 Minutes": {
"main": [
[
{
"node": "Get Trashed Files via API",
"type": "main",
"index": 0
}
]
]
},
"Delete Old Data Rows1": {
"main": [
[
{
"node": "Delete Old Doc Rows1",
"type": "main",
"index": 0
}
]
]
},
"Delete Old Doc Rows1": {
"main": [
[
{
"node": "Delete Metadata",
"type": "main",
"index": 0
}
]
]
},
"Recursive Character Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "LangChain Code",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"LangChain Code": {
"main": [
[
{
"node": "Postgres PGVector Store1",
"type": "main",
"index": 0
}
]
]
},
"MCP Client - Add to Knowledge Graph": {
"main": [
[]
]
},
"MCP Client": {
"ai_tool": [
[
{
"node": "RAG AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "42b52887-0af7-45bc-9f92-fd78433b9fa5",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "BQvUPflyKG3xAjoO",
"tags": []
}
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.
cohereApigoogleDriveOAuth2ApihttpHeaderAuthmcpClientSseApiopenAiApipostgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
How this works
This workflow empowers teams to build intelligent AI agents that retrieve and generate responses from their own documents, ensuring accurate, context-aware answers without sifting through files manually. It suits knowledge workers, support teams, or researchers handling document-heavy queries, such as legal reviews or customer FAQs, by automating the process from file updates to personalised replies. The key step involves embedding documents via OpenAI and loading them with the default data loader to fuel a chat model that delivers precise, up-to-date information, integrated seamlessly with Google Drive for real-time file monitoring.
Use this template when you need an event-driven AI system to process new or updated documents in Google Drive and respond to queries intelligently, like in automated support bots or internal knowledge bases. Avoid it for simple data transfers without AI reasoning, or if your documents require advanced preprocessing beyond basic loading. Common variations include swapping Postgres memory for other storage options or adding webhooks for broader triggers.
About this workflow
RAG AI Agent Template V5. Uses lmChatOpenAi, documentDefaultDataLoader, embeddingsOpenAi, googleDrive. Event-driven trigger; 56 nodes.
Source: https://github.com/DPabloFlores/ottomator-agents/blob/main/n8n_knowledge_graph_rag/RAG_AI_Agent_Template_V5.json — 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.
Your AI workforce is ready. Are you?
This comprehensive workflow bundle is designed as a powerful starter kit, enabling you to build a multi-functional AI assistant on Telegram. It seamlessly integrates AI-powered voice interactions, an
This intelligent chatbot leverages cutting-edge financial APIs and AI-driven analysis to deliver comprehensive stock research reports. Get instant access to professional-grade investment analysis that
RAG_Ingest. Uses httpRequest, vectorStoreSupabase, documentDefaultDataLoader, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 73 nodes.
This advanced n8n workflow automates the full lead enrichment, qualification, and personalized outreach process tailored specifically for the B2B real estate sector. Integrating top platforms like Api