This workflow corresponds to n8n.io template #5521 — 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": "gqPf4clVkEeEFul1",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Recursive Hybrid RAG 1",
"tags": [],
"nodes": [
{
"id": "95e00865-e2e3-4db6-a423-43488be3da42",
"name": "Google Drive Trigger",
"type": "n8n-nodes-base.googleDriveTrigger",
"position": [
-360,
-40
],
"parameters": {
"event": "fileCreated",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "10c4lWGMSkqZc5JhsyDxZ-jzgBaEEItqU",
"cachedResultUrl": "https://drive.google.com/drive/folders/10c4lWGMSkqZc5JhsyDxZ-jzgBaEEItqU",
"cachedResultName": "OpenAI IMG Gen 1"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "43fe3da8-bc96-44da-a298-bb3ab59e6328",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-140,
-40
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "746c437e-ad11-4e79-995f-50d6e1211748",
"name": "Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
300,
-40
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.File_id }}"
},
"options": {
"googleFileConversion": {
"conversion": {
"docsToFormat": "text/plain"
}
}
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "5ffd763b-e0f7-4ed4-8195-9a4da5b281bb",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
520,
-40
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "471108e8-3209-46d7-9a70-4b3ba48a5e2e",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.File_Type }}",
"rightValue": "application/pdf"
}
]
}
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "217bb864-29af-43a0-9705-8222e095b48c",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.File_Type }}",
"rightValue": "text/plain"
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "a5b0335e-f355-4959-9ece-7187d1dfd0eb",
"name": "Basic LLM Chain",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1840,
-40
],
"parameters": {
"text": "=<document> \n{{ $('Document Data').item.json.data }}\n\n</document> \n\nHere is the chunk we want to situate within the overall document:\n<chunk> \n{{ $json.chunks }}\n</chunk> \n\nPlease: \n- Provide a short and succinct <<context>> to situate this chunk within the document for improved search retrieval. \n- Rather than describing numbers, terms, or phrases as provided unless a correction is necessary. \n- If the chunk contains an <<incomplete number, percentage, or entity>>, correct it using the full document. \n- If part of a sentence is cut off, reconstruct the missing words only if necessary for clarity. \n- If the chunk is part of a table, include the complete table entry to preserve data integrity \n- Do not add any additional explanations or formatting beyond the required output. \n\nFill in the following format: [succinct context]: [original chunk or corrected version if necessary] \n\nYour response should contain only the text that replaces these placeholders, without including the placeholders, tags, or these themselves.",
"batching": {},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "cff6ca9c-0e14-4096-8d58-d9ea332752f3",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1928,
180
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "c60ac23d-f256-4960-a1c2-b3238f018751",
"name": "Summarize",
"type": "n8n-nodes-base.summarize",
"position": [
2220,
-40
],
"parameters": {
"options": {},
"fieldsToSummarize": {
"values": [
{
"field": "text",
"separateBy": "other",
"aggregation": "concatenate",
"customSeparator": "###SPLIT###"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "68beae62-7378-4ef6-a6fc-8d5f73eb5f19",
"name": "Embeddings OpenAI",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
2436,
180
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "f395021c-634c-4615-9630-bb1b06020504",
"name": "Supabase Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"position": [
2452,
-40
],
"parameters": {
"mode": "insert",
"options": {},
"tableName": {
"__rl": true,
"mode": "list",
"value": "documents",
"cachedResultName": "documents"
}
},
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "ec2fa582-cc8b-4284-90e4-4dccb4f11779",
"name": "Default Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
2556,
182.5
],
"parameters": {
"options": {
"metadata": {
"metadataValues": [
{
"name": "File_url",
"value": "={{ $('File info').item.json.File_url }}"
}
]
}
}
},
"typeVersion": 1
},
{
"id": "e1f6953c-4fe0-43fa-bb86-77371e956d9b",
"name": "Character Text Splitter",
"type": "@n8n/n8n-nodes-langchain.textSplitterCharacterTextSplitter",
"position": [
2644,
380
],
"parameters": {
"chunkSize": 1200,
"separator": "###SPLIT###"
},
"typeVersion": 1
},
{
"id": "e0d17eb8-5bf9-40d1-9642-6d853598a5aa",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1400,
600
],
"parameters": {
"text": "question: 1a(i)\nAnswer:Ammonia\nMark scheme:Pearson Edexcel International Advanced Level in Chemistry (WCH16) Paper 01 Unit 6: Practical Skills in Chemistry II.",
"options": {
"systemMessage": "=You are an AI Examiner Agent with access to a Supabase database containing exam markschemes via HTTP API. Your primary role is to mark student exam answers fairly, consistently, and accurately according to the official markscheme.\n\n## Core Responsibilities\n\n1. **Mark individual or bulk student answers** against the official markscheme stored in your database\n2. **Provide detailed feedback** explaining how marks were awarded or deducted\n3. **Maintain consistency** in marking standards across all submissions\n4. **Handle various input formats** (single answers, bulk submissions with question numbers)\n\n## Database Access Instructions\n\n- Use HTTP requests to query your Supabase database for markscheme data\n- Query markschemes by question number, exam code, or other relevant identifiers\n- Always verify you have the correct markscheme before marking any answer\n\n## Marking Process\n\n### For Individual Answers:\n1. **Identify the question** from context or ask for question number if unclear\n2. **Retrieve the relevant markscheme** from database\n3. **Compare student answer** against marking criteria\n4. **Award marks** based on markscheme rubric\n5. **Provide specific feedback** citing which criteria were met/missed\n\n### For Bulk Submissions:\n1. **Parse the submission** to extract question numbers and corresponding answers\n2. **Retrieve all relevant markschemes** in batch where possible\n3. **Mark each answer systematically**\n4. **Provide summary report** with individual question breakdowns\n5. **Calculate total score** and percentage if applicable\n\n## Marking Standards\n\n- **Accuracy**: Follow markscheme exactly - do not deviate from official criteria\n- **Fairness**: Apply same standards to all students consistently \n- **Partial Credit**: Award partial marks for partially correct answers as specified in markscheme\n- **Alternative Answers**: Accept equivalent correct answers not explicitly listed if they demonstrate same understanding\n- **Spelling/Grammar**: Only penalize if markscheme specifically addresses language accuracy\n\n## Response Format\n\n### Individual Answer Marking:\n```\n**Question [X] - [Y] marks available**\n\n**Student Answer Analysis:**\n[Brief summary of student's response]\n\n**Marking Breakdown:**\n- Criterion 1: [X/Y marks] - [Explanation]\n- Criterion 2: [X/Y marks] - [Explanation]\n- etc.\n\n**Total Score: [X/Y] marks**\n\n**Feedback:**\n[Constructive feedback on strengths and areas for improvement]\n```\n\n### Bulk Marking Summary:\n```\n**Exam Marking Summary**\n\n**Overall Score: [X/Y] marks ([Z]%)**\n\n**Question-by-Question Breakdown:**\nQ1: [X/Y] marks - [Brief comment]\nQ2: [X/Y] marks - [Brief comment]\n[etc.]\n\n**Detailed Analysis:**\n[Per question detailed breakdown using individual format above]\n\n**Overall Performance Summary:**\n[Strengths, weaknesses, grade indication if applicable]\n```\n\n## Error Handling\n\n- If question number is unclear, ask for clarification\n- If markscheme cannot be found, request exam details (exam code, subject, etc.)\n- If student answer is ambiguous, explain interpretation used for marking\n- If database access fails, inform user and request manual markscheme provision\n\n## Key Behaviors\n\n- **Be objective and impartial** in all marking decisions\n- **Explain your reasoning** clearly for all mark allocations\n- **Be constructive** in feedback while maintaining marking integrity\n- **Ask for clarification** when inputs are ambiguous\n- **Maintain professional tone** appropriate for educational assessment\n\n## Input Processing\n\nYou can handle various input formats:\n- Single question: \"Q5: [student answer]\"\n- Multiple questions: \"Q1: [answer] Q2: [answer] Q3: [answer]\" \n- Formatted submissions with clear question/answer separation\n- Requests for specific question markschemes for student review\n\nAlways confirm the question number and retrieve the correct markscheme before beginning marking.\n\nReady to begin marking. Please provide the student answer(s) along with question number(s) for assessment."
},
"promptType": "define"
},
"typeVersion": 2
},
{
"id": "cc7fc092-1975-45ef-ac8c-62196b4d5796",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-980,
-260
],
"parameters": {
"width": 540,
"height": 640,
"content": "1. **Document Ingestion & Processing**\n\nGoogle Drive Trigger monitors for new files \u2192 Loop Over Items processes each file \u2192 File Info extracts metadata \u2192 Google Drive downloads the actual content \u2192 Switch routes to appropriate extractors (PDF or TEXT) based on file type\n\n2. **Content Transformation & Chunking**\n\nDocument Data node processes extracted text \u2192 Recursive Splitter breaks content into contextual chunks \u2192 Chunk Splitting applies intelligent segmentation while preserving document context and relationships between chunks\n\n3. **Embedding & Storage**\n\nBasic LLM Chain processes chunks \u2192 OpenAI Chat Model generates contextual understanding \u2192 Summarize creates document summaries \u2192 Supabase Vector Store saves embeddings with metadata \u2192 Embeddings OpenAI creates vector representations \u2192 Default Data Loader handles storage operations\n\n"
},
"typeVersion": 1
},
{
"id": "7989a21e-2947-4ba4-bd42-21a169de2e70",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
500
],
"parameters": {
"color": 4,
"width": 380,
"height": 420,
"content": "**ASK ME**\n\n\n**Query Processing & Retrieval**\n\nWhen Clicking Execute triggers user queries \u2192 OpenAI processes and understands the question \u2192 AI Agent orchestrates hybrid search (combining vector similarity + keyword matching) \u2192 Google Gemini Chat Model generates final responses using retrieved context \u2192 HTTP Request handles additional external data sources"
},
"typeVersion": 1
},
{
"id": "dfe4fbd8-b358-46a2-bcf9-c2c5027cca9d",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
720,
600
],
"parameters": {},
"typeVersion": 1
},
{
"id": "aed9c156-dcea-4fd8-887e-cb993e50e18b",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1440,
820
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.5-flash-preview-04-17"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "d9be2c8f-9f4f-475a-a30f-303389524e28",
"name": "OpenAI",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1040,
600
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "chatgpt-4o-latest",
"cachedResultName": "CHATGPT-4O-LATEST"
},
"options": {},
"resource": "image",
"inputType": "base64",
"operation": "analyze"
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.8
},
{
"id": "803ccebd-69fe-4954-809d-9cd0b355fd6e",
"name": "File info",
"type": "n8n-nodes-base.set",
"position": [
80,
-40
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b4b888bd-827f-4721-b553-b3e1cf38e3fe",
"name": "File_id",
"type": "string",
"value": "={{ $json.id }}"
},
{
"id": "dcf732a3-aaf5-41a6-8bad-fc06a74e1263",
"name": "File_Type",
"type": "string",
"value": "={{ $json.mimeType }}"
},
{
"id": "5b9870de-94d0-470b-bb9c-e129e895feea",
"name": "File_url",
"type": "string",
"value": "={{ $json.webViewLink }}"
},
{
"id": "4ec5bfff-f78b-406b-a5da-ca2c81e3c41b",
"name": "File_name",
"type": "string",
"value": "={{ $json.name }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "c1926c20-88d6-4a95-a9d4-8dd2d1665b77",
"name": "Extract from PDF",
"type": "n8n-nodes-base.extractFromFile",
"position": [
740,
-140
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "e4fc2a52-e1ea-424e-861f-fee7fceaa1cc",
"name": "Extract from TEXT",
"type": "n8n-nodes-base.extractFromFile",
"position": [
960,
60
],
"parameters": {
"options": {},
"operation": "text"
},
"typeVersion": 1
},
{
"id": "09a9112a-9c72-4965-818e-2351aad7528e",
"name": "PDF to DATA",
"type": "n8n-nodes-base.set",
"position": [
960,
-140
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={\n \"data\":{{JSON.stringify($json.text)}}\n}\n"
},
"typeVersion": 3.4
},
{
"id": "d4b03066-b191-439c-b1e9-f3a5b325f1fd",
"name": "Recursive Splitter",
"type": "n8n-nodes-base.code",
"position": [
1400,
-40
],
"parameters": {
"jsCode": "const chunkSize = 1000;\nconst chunkOverlap = 200;\nconst text = $input.item.json.data.replace(/\\n/g, '');\n\nconst chunks = [];\nlet remainingText = text;\n\nwhile (remainingText.length > 0) {\n let splitPoint;\n \n // Try splitting at paragraph level first\n splitPoint = remainingText.lastIndexOf(\"\\n\\n\", chunkSize);\n \n // If no paragraph split, try splitting at sentence level\n if (splitPoint === -1) {\n splitPoint = remainingText.lastIndexOf(\". \", chunkSize);\n }\n \n // If no sentence split, try splitting at word level\n if (splitPoint === -1) {\n splitPoint = remainingText.lastIndexOf(\" \", chunkSize);\n }\n \n // If still no split point, force split at chunkSize\n if (splitPoint === -1 || splitPoint < chunkSize * 0.5) {\n splitPoint = chunkSize; // Hard split if no good split point\n }\n \n // Extract chunk and adjust remaining text with overlap\n let chunk = remainingText.substring(0, splitPoint).trim();\n chunks.push(chunk);\n \n // Move the pointer forward while keeping the overlap\n remainingText = remainingText.substring(Math.max(0, splitPoint - chunkOverlap)).trim();\n \n // Break if remaining text is too small to form another chunk\n if (remainingText.length < chunkSize * 0.2) {\n chunks.push(remainingText);\n break;\n }\n}\n\nreturn { chunks };"
},
"typeVersion": 2
},
{
"id": "1f9b5ef2-c719-44e2-95a5-80566739345a",
"name": "Document Data",
"type": "n8n-nodes-base.set",
"position": [
1180,
-40
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={\n \"data\":{{ JSON.stringify($json.data) }}\n}\n"
},
"typeVersion": 3.4
},
{
"id": "ba9f2a39-e3cb-45aa-9de7-8ae9a3331150",
"name": "Chunk Splitting",
"type": "n8n-nodes-base.splitOut",
"position": [
1620,
-40
],
"parameters": {
"options": {},
"fieldToSplitOut": "chunks"
},
"typeVersion": 1
},
{
"id": "46440496-6abc-46a2-843a-15988a4f717a",
"name": "SupaBase Query",
"type": "n8n-nodes-base.httpRequestTool",
"position": [
1680,
820
],
"parameters": {
"url": "https://etvncxazsxflierkgyge.supabase.co/functions/v1/query-DB",
"method": "POST",
"options": {
"redirect": {
"redirect": {}
}
},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "query",
"value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', ``, 'string') }}"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Your Supabase Key"
}
]
}
},
"typeVersion": 4.2
}
],
"active": false,
"settings": {
"timezone": "Asia/Dubai",
"callerPolicy": "workflowsFromSameOwner",
"executionOrder": "v1"
},
"versionId": "97fe98d5-09dc-43d7-a169-8de91c02fb37",
"connections": {
"OpenAI": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Extract from PDF",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract from TEXT",
"type": "main",
"index": 0
}
]
]
},
"File info": {
"main": [
[
{
"node": "Google Drive",
"type": "main",
"index": 0
}
]
]
},
"Summarize": {
"main": [
[
{
"node": "Supabase Vector Store",
"type": "main",
"index": 0
}
]
]
},
"PDF to DATA": {
"main": [
[
{
"node": "Document Data",
"type": "main",
"index": 0
}
]
]
},
"Google Drive": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Document Data": {
"main": [
[
{
"node": "Recursive Splitter",
"type": "main",
"index": 0
}
]
]
},
"SupaBase Query": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Basic LLM Chain": {
"main": [
[
{
"node": "Summarize",
"type": "main",
"index": 0
}
]
]
},
"Chunk Splitting": {
"main": [
[
{
"node": "Basic LLM Chain",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "File info",
"type": "main",
"index": 0
}
]
]
},
"Extract from PDF": {
"main": [
[
{
"node": "PDF to DATA",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI": {
"ai_embedding": [
[
{
"node": "Supabase Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Extract from TEXT": {
"main": [
[
{
"node": "Document Data",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Basic LLM Chain",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Recursive Splitter": {
"main": [
[
{
"node": "Chunk Splitting",
"type": "main",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Supabase Vector Store",
"type": "ai_document",
"index": 0
}
]
]
},
"Google Drive Trigger": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Character Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "OpenAI",
"type": "main",
"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.
googleDriveOAuth2ApigooglePalmApiopenAiApisupabaseApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Document Ingestion & Processing
Source: https://n8n.io/workflows/5521/ — 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
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
This n8n template automatically classifies incoming emails (Sales, Support, Internal, Finance, Promotions) and routes them to a dedicated OpenAI LLM Agent for processing. Depending on the category, th