递归混合RAG 1
高级
这是一个Internal Wiki, AI RAG领域的自动化工作流,包含 25 个节点。主要使用 Set, Code, Switch, SplitOut, Summarize 等节点。 使用Google Drive、OpenAI和Gemini RAG进行递归分块的文档处理
前置要求
- •Google Drive API 凭证
- •可能需要目标 API 的认证凭证
- •OpenAI API Key
- •Google Gemini API Key
- •Supabase URL 和 API Key
使用的节点 (25)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "gqPf4clVkEeEFul1",
"meta": {
"instanceId": "0fa2e5f9f1c8b82cfe9c3f2c5d75842c6c2d1b07596b807d7aaa439c3a697b30",
"templateCredsSetupCompleted": true
},
"name": "递归混合 RAG 1",
"tags": [],
"nodes": [
{
"id": "95e00865-e2e3-4db6-a423-43488be3da42",
"name": "Google Drive 触发器",
"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": {
"id": "gLXppgYt00TU079t",
"name": "Google Drive account"
}
},
"typeVersion": 1
},
{
"id": "43fe3da8-bc96-44da-a298-bb3ab59e6328",
"name": "遍历项目",
"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": {
"id": "gLXppgYt00TU079t",
"name": "Google Drive account"
}
},
"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": "基础LLM链",
"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 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1928,
180
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "N8oave6roxa4SXEA",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.2
},
{
"id": "c60ac23d-f256-4960-a1c2-b3238f018751",
"name": "总结",
"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": {
"id": "N8oave6roxa4SXEA",
"name": "OpenAi account 2"
}
},
"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": {
"id": "KC4GHDFxEISJGMwB",
"name": "Supabase account 3"
}
},
"typeVersion": 1.2
},
{
"id": "ec2fa582-cc8b-4284-90e4-4dccb4f11779",
"name": "默认数据加载器",
"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": "字符文本分割器",
"type": "@n8n/n8n-nodes-langchain.textSplitterCharacterTextSplitter",
"position": [
2644,
380
],
"parameters": {
"chunkSize": 1200,
"separator": "###SPLIT###"
},
"typeVersion": 1
},
{
"id": "e0d17eb8-5bf9-40d1-9642-6d853598a5aa",
"name": "AI 代理",
"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": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-980,
-260
],
"parameters": {
"width": 540,
"height": 640,
"content": "1. **文档摄取和处理**"
},
"typeVersion": 1
},
{
"id": "7989a21e-2947-4ba4-bd42-21a169de2e70",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
500
],
"parameters": {
"color": 4,
"width": 380,
"height": 420,
"content": "**向我提问**"
},
"typeVersion": 1
},
{
"id": "dfe4fbd8-b358-46a2-bcf9-c2c5027cca9d",
"name": "点击\"执行工作流\"时",
"type": "n8n-nodes-base.manualTrigger",
"position": [
720,
600
],
"parameters": {},
"typeVersion": 1
},
{
"id": "aed9c156-dcea-4fd8-887e-cb993e50e18b",
"name": "Google Gemini 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1440,
820
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.5-flash-preview-04-17"
},
"credentials": {
"googlePalmApi": {
"id": "DWxgjfTLFzyeKnsm",
"name": "Google Gemini(PaLM) Api account"
}
},
"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": {
"id": "N8oave6roxa4SXEA",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.8
},
{
"id": "803ccebd-69fe-4954-809d-9cd0b355fd6e",
"name": "文件信息",
"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": "从 PDF 提取",
"type": "n8n-nodes-base.extractFromFile",
"position": [
740,
-140
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "e4fc2a52-e1ea-424e-861f-fee7fceaa1cc",
"name": "从 TEXT 提取",
"type": "n8n-nodes-base.extractFromFile",
"position": [
960,
60
],
"parameters": {
"options": {},
"operation": "text"
},
"typeVersion": 1
},
{
"id": "09a9112a-9c72-4965-818e-2351aad7528e",
"name": "PDF 转 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": "递归分割器",
"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": "文档数据",
"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": "分块分割",
"type": "n8n-nodes-base.splitOut",
"position": [
1620,
-40
],
"parameters": {
"options": {},
"fieldToSplitOut": "chunks"
},
"typeVersion": 1
},
{
"id": "46440496-6abc-46a2-843a-15988a4f717a",
"name": "SupaBase 查询",
"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,
"pinData": {},
"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 ‘Execute workflow’": {
"main": [
[
{
"node": "OpenAI",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 内部知识库, AI RAG 检索增强
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
AI驱动的RAG文档处理与聊天机器人 - Google Drive、Supabase、OpenAI
基于Google Drive、Supabase和OpenAI的AI驱动RAG文档处理与聊天机器人
Set
Code
Limit
+19
35 节点Billy Christi
人工智能
宠物店 4
🐶 宠物店预约 AI 代理
If
Set
Code
+41
187 节点Bruno Dias
人工智能
交付汉堡店MVP
🤖 餐厅与配送自动化的 AI 驱动 WhatsApp 助手
If
Set
Code
+37
152 节点Bruno Dias
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+93
113 节点I versus AI
其他
[模板] AI宠物店 v8
🐶 AI宠物店助手 - 集成GPT-4o、Google日历和WhatsApp/Instagram/Facebook
If
N8n
Set
+38
244 节点Amanda Benks
销售
AI 代理餐厅 [模板]
🤖 WhatsApp、Instagram 和 Messenger 的 AI 餐厅助手
If
N8n
Set
+37
239 节点Amanda Benks
其他
工作流信息
难度等级
高级
节点数量25
分类2
节点类型21
作者
Mohsin Ali
@binbakhshAs an AI Automation Specialist on a mission to revolutionise how businesses operate, I’m passionate about turning complex technology into actionable solutions. My journey into AI isn’t just about algorithms—it’s about empowering leaders like you to reclaim time, slash inefficiencies, and unlock growth through smart automation.
外部链接
在 n8n.io 查看 →
分享此工作流