AutomationFlowsAI & RAG › Create a Self-updating RAG Chatbot with Google Drive, Gemini, and Supabase

Create a Self-updating RAG Chatbot with Google Drive, Gemini, and Supabase

ByAnirudh Aeran @anirudhaeran on n8n.io

This template creates a comprehensive, production-ready Retrieval-Augmented Generation (RAG) system. It builds a sophisticated AI agent that can answer questions based on documents stored in a specific Google Drive folder, and it automatically keeps its knowledge base up-to-date…

Event trigger★★★★★ complexityAI-powered45 nodesReranker CohereSupabase Vector StoreAgentGoogle Drive TriggerSupabaseText Splitter Character Text SplitterPostgresDocument Default Data Loader
AI & RAG Trigger: Event Nodes: 45 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #9007 — we link there as the canonical source.

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 →

Download .json
{
  "nodes": [
    {
      "id": "fbeb9ada-34d8-440a-b843-ff139e8e979c",
      "name": "Reranker Cohere",
      "type": "@n8n/n8n-nodes-langchain.rerankerCohere",
      "position": [
        1456,
        368
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "11e0434a-904c-48ca-b119-978dd68996db",
      "name": "Supabase Vector Store",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        1216,
        224
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "topK": 20,
        "options": {},
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "documents",
          "cachedResultName": "documents"
        },
        "useReranker": true,
        "toolDescription": "Use this tool to search the database"
      },
      "typeVersion": 1.3
    },
    {
      "id": "68112d8c-e204-451f-b5b3-a10f69738506",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        80
      ],
      "parameters": {
        "color": 4,
        "width": 1372,
        "height": 396,
        "content": "## RAG Agent (Step 2)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b011d310-348d-4726-b2b3-785ac9b081e0",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1072,
        80
      ],
      "parameters": {
        "color": 6,
        "width": 572,
        "height": 396,
        "content": "## Vector Store\n"
      },
      "typeVersion": 1
    },
    {
      "id": "9f12dcc8-423c-42f6-a0de-522b5897c620",
      "name": "RAG Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        528,
        176
      ],
      "parameters": {
        "options": {
          "systemMessage": "=You are a helpful and friendly AI assistant for our company. Your primary goal is to assist users by answering their questions based on a knowledge base, but you should also be ableto handle simple conversation. You have access to the Supabase tool. Always call on this tool to answer questions if the user is asking for information.\n\nFirst, analyze the user's message to determine their intent.\n\n**Behavior 1: If the user's message is a simple greeting, thank you, or other conversational filler (e.g., \"hello\", \"thanks!\", \"how are you?\").**\n- You should respond politely and conversationally.\n- Do NOT use the provided [CONTEXT].\n- Do NOT mention the documents or your knowledge base.\n\n**Behavior 2: If the user's message is a question asking for information, instructions, or specific details.**\n- You must switch to your role as a specialized knowledge base assistant and follow these strict rules:\n1.  **Analyze the Context:** Carefully read the provided [CONTEXT] section. This is your only source of truth.\n2.  **Answer the Question:** Formulate a direct and concise answer to the [QUESTION] using only the information from the [CONTEXT].\n3.  **Strictly Adhere to Context:** Do NOT use any external knowledge, make assumptions, or fill in gaps.\n4.  **Handling Insufficient Information:** If the answer cannot be found within the [CONTEXT], you must respond with the exact phrase: \"I could not find an answer in the provided documents.\" Do not apologize or offer to search elsewhere.\n5.  **Cite Your Sources:** After your answer, add a \"Sources:\" section. List the title of each source document you used. Use the metadata provided in the context to format each source as a clickable Markdown link.\n\n**[CONTEXT]**\n{context_from_retriever}\n**[/CONTEXT]**\n\n**[QUESTION]**\n{user_question}\n**[/QUESTION]**"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "61d43f61-e071-4d2d-a714-eac42d4acbd2",
      "name": "File Created",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "disabled": true,
      "position": [
        128,
        560
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "Your Folder ID",
          "cachedResultUrl": "https://drive.google.com/drive/folders/Your Folder ID",
          "cachedResultName": "1) RAG Demo"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "52fa8440-7c5a-4a2e-bd6b-17cbb22c7d6a",
      "name": "File Updated",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "disabled": true,
      "position": [
        128,
        1024
      ],
      "parameters": {
        "event": "fileUpdated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "Your Folder ID",
          "cachedResultUrl": "https://drive.google.com/drive/folders/Your Folder ID",
          "cachedResultName": "1) RAG Demo"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "06cd8ce9-4d3c-412e-9688-a181f6aadc38",
      "name": "Extract Document Text",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1296,
        944
      ],
      "parameters": {
        "options": {},
        "operation": "text"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "8a280ac3-a27f-469c-9885-3482051e2268",
      "name": "Delete Old Doc Rows",
      "type": "n8n-nodes-base.supabase",
      "position": [
        576,
        880
      ],
      "parameters": {
        "tableId": "documents",
        "operation": "delete",
        "filterType": "string",
        "filterString": "=metadata->>file_id=like.*{{ $json.file_id }}*"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "2fca17ab-ec90-4877-936b-45a651a567d1",
      "name": "Set File ID",
      "type": "n8n-nodes-base.set",
      "position": [
        672,
        624
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "10646eae-ae46-4327-a4dc-9987c2d76173",
              "name": "file_id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "f4536df5-d0b1-4392-bf17-b8137fb31a44",
              "name": "file_type",
              "type": "string",
              "value": "={{ $json.mimeType }}"
            },
            {
              "id": "77d782de-169d-4a46-8a8e-a3831c04d90f",
              "name": "file_title",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "9bde4d7f-e4f3-4ebd-9338-dce1350f9eab",
              "name": "file_url",
              "type": "string",
              "value": "={{ $json.webViewLink }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a3a6aca4-5932-4b13-9466-de1fadee3392",
      "name": "Extract PDF Text",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1296,
        784
      ],
      "parameters": {
        "options": {},
        "operation": "pdf"
      },
      "typeVersion": 1
    },
    {
      "id": "86094f10-2a02-431f-b0ec-d7cd5dffb98b",
      "name": "Character Text Splitter",
      "type": "@n8n/n8n-nodes-langchain.textSplitterCharacterTextSplitter",
      "position": [
        1552,
        1280
      ],
      "parameters": {
        "chunkSize": 750,
        "chunkOverlap": 200
      },
      "typeVersion": 1
    },
    {
      "id": "35366f16-4f00-4544-9f7e-aac1a5571e7f",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        1072,
        880
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Set File ID').item.json.file_type }}",
                    "rightValue": "application/pdf"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "b69f5605-0179-4b02-9a32-e34bb085f82d",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Set File ID').item.json.file_type }}",
                    "rightValue": "application/vnd.google-apps.document"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": 3
        }
      },
      "typeVersion": 3
    },
    {
      "id": "0edf1ac5-2469-451e-81cb-6b6267427b9f",
      "name": "Insert into Supabase Vectorstore",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "onError": "continueRegularOutput",
      "position": [
        1552,
        928
      ],
      "parameters": {
        "mode": "insert",
        "options": {
          "queryName": "match_documents"
        },
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "documents",
          "cachedResultName": "documents"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f5c2d73e-fdb7-4e2c-8fae-74e2dd483b99",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        448,
        608
      ],
      "parameters": {
        "options": {
          "reset": false
        }
      },
      "typeVersion": 3
    },
    {
      "id": "80ca7123-c4d6-4184-83db-3a9cd7eea5be",
      "name": "Insert Document Metadata",
      "type": "n8n-nodes-base.postgres",
      "position": [
        752,
        880
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "document_metadata",
          "cachedResultName": "document_metadata"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "id": "={{ $('Set File ID').item.json.file_id }}",
            "url": "={{ $('Set File ID').item.json.file_url }}",
            "title": "={{ $('Set File ID').item.json.file_title }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": true,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "title",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "schema",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "schema",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "upsert"
      },
      "executeOnce": true,
      "typeVersion": 2.5
    },
    {
      "id": "75602bb9-30a7-409c-8aaa-38f9923cf08d",
      "name": "Default Data Loader1",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        1632,
        1136
      ],
      "parameters": {
        "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 }}"
              },
              {
                "name": "url",
                "value": "={{ $('Set File ID').first().json.file_url }}"
              }
            ]
          }
        },
        "jsonData": "={{ $json.data || $json.text || $json.concatenated_data }}",
        "jsonMode": "expressionData"
      },
      "typeVersion": 1
    },
    {
      "id": "902bfe64-17c3-45aa-8434-cb4241aa150b",
      "name": "Download File1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        928,
        880
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set File ID').item.json.file_id }}"
        },
        "options": {
          "googleFileConversion": {
            "conversion": {
              "docsToFormat": "text/plain"
            }
          }
        },
        "operation": "download"
      },
      "executeOnce": true,
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "87aecf50-86dc-48db-9eac-b34fd6a4938d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        480
      ],
      "parameters": {
        "color": 3,
        "width": 2192,
        "height": 976,
        "content": "## RAG Ingestion System (Step 1)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n                                                                                              \n\n\n\n\n\n\n\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e67da326-ff09-4f72-a146-19c342dc8b1f",
      "name": "Get File IDs",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        816,
        1568
      ],
      "parameters": {
        "filter": {},
        "options": {
          "fields": [
            "id"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "'Your Folder ID' in parents and trashed=false",
        "searchMethod": "query"
      },
      "typeVersion": 3
    },
    {
      "id": "b5b91dde-0afb-493f-b336-ea84017d8171",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        1088,
        1648
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "74a8e170-040a-42f4-b593-a2206527f655",
      "name": "Supabase",
      "type": "n8n-nodes-base.supabase",
      "position": [
        816,
        1728
      ],
      "parameters": {
        "tableId": "documents",
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1
    },
    {
      "id": "a763d918-e045-461a-b081-2670f7d3f1af",
      "name": "Code1",
      "type": "n8n-nodes-base.code",
      "position": [
        1312,
        1648
      ],
      "parameters": {
        "jsCode": "// Grab the raw data from all inputs\nconst inputData = $input.all().map(item => item.json);\n\n// Separate out the Google Drive items (no \"metadata\") vs. Supabase items (have \"metadata\")\nconst googleDriveItems = inputData.filter(item => item.id && !item.metadata);\nconst supabaseItems = inputData.filter(item => item.metadata);\n\n// Extract just the file IDs from Google Drive\nconst googleDriveIds = googleDriveItems.map(item => item.id);\n\n// Build a Set for quick membership checks (recommended for large arrays)\nconst driveIdSet = new Set(googleDriveIds);\n\n// Filter Supabase rows to find those whose file_id is not in the Drive set\nconst orphanedSupabaseRows = supabaseItems.filter(item => {\n  return !driveIdSet.has(item.metadata.file_id);\n});\n\n// Return each orphaned row as a separate n8n item\nreturn orphanedSupabaseRows.map(row => ({ json: row }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "c5a5c9c8-07fe-4c09-87ac-c0dd0dbaf17e",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "disabled": true,
      "position": [
        512,
        1904
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ec4c1998-6079-4a91-a8ba-b6fed99e93a7",
      "name": "When clicking \u2018Test workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -112,
        784
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "29b49cd7-64ce-4752-a07b-3afebf19219b",
      "name": "Delete Rows",
      "type": "n8n-nodes-base.supabase",
      "position": [
        1536,
        1648
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "keyValue": "={{ $json.id }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "documents",
        "matchType": "allFilters",
        "operation": "delete"
      },
      "typeVersion": 1
    },
    {
      "id": "3c1b0427-02df-481a-94b1-63a22ca243af",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        1456
      ],
      "parameters": {
        "color": 6,
        "width": 1440,
        "height": 956,
        "content": "## RAG: Clean up (Step 3)"
      },
      "typeVersion": 1
    },
    {
      "id": "3ea2baf0-fac7-440b-bd6c-4f7f689844cc",
      "name": "Get File IDs2",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        816,
        1968
      ],
      "parameters": {
        "filter": {},
        "options": {
          "fields": [
            "id"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "'Your Folder ID' in parents and trashed=false",
        "searchMethod": "query"
      },
      "typeVersion": 3
    },
    {
      "id": "8002bd2f-29da-40fe-b909-cdcc7d3f5fde",
      "name": "Supabase2",
      "type": "n8n-nodes-base.supabase",
      "position": [
        816,
        2192
      ],
      "parameters": {
        "tableId": "document_metadata",
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1
    },
    {
      "id": "f11e2063-d42c-4d07-86d8-b916467b5b3a",
      "name": "Merge2",
      "type": "n8n-nodes-base.merge",
      "position": [
        1104,
        2048
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "4b4a4689-2767-49a9-8f8f-2a33d9cd7e84",
      "name": "Code2",
      "type": "n8n-nodes-base.code",
      "position": [
        1328,
        2048
      ],
      "parameters": {
        "jsCode": "// Simple code to handle empty Google Drive\n\n// Determine if we have Google Drive data\nlet hasDriveData = false;\nlet driveFileIds = new Set();\n\n// Check the first item to see if it's a Google Drive file or a file list\nif (items[0] && items[0].json) {\n  // Is it a files array?\n  if (items[0].json.files && Array.isArray(items[0].json.files)) {\n    hasDriveData = true;\n    for (const file of items[0].json.files) {\n      if (file && file.id) driveFileIds.add(file.id);\n    }\n  }\n  // Is it a single file with no metadata-like properties?\n  else if (items[0].json.id && !items[0].json.title && !items[0].json.created_at) {\n    hasDriveData = true;\n    driveFileIds.add(items[0].json.id);\n  }\n}\n\nconsole.log(\"Has Drive data:\", hasDriveData);\nconsole.log(\"Drive file IDs:\", Array.from(driveFileIds));\n\n// Determine which items are metadata records\nlet metadataRecords = [];\n\n// If the first item looks like a metadata record (has title, url, created_at)\nif (!hasDriveData) {\n  // All items are metadata records\n  metadataRecords = items.map(item => item.json).filter(Boolean);\n  console.log(\"All items are metadata records:\", metadataRecords.length);\n} else {\n  // Only items after the first are metadata records\n  metadataRecords = items.slice(1).map(item => item.json).filter(Boolean);\n  console.log(\"Items after first are metadata records:\", metadataRecords.length);\n}\n\n// If there are no Drive files, mark all metadata records for deletion\nconst recordsToDelete = [];\n\nif (driveFileIds.size === 0) {\n  console.log(\"No Drive files, marking ALL metadata records for deletion\");\n  for (const record of metadataRecords) {\n    if (record && record.id) {\n      recordsToDelete.push({\n        ...record,\n        _shouldDelete: true\n      });\n    }\n  }\n} else {\n  // Otherwise, only mark records not in Drive\n  console.log(\"Checking metadata records against Drive files\");\n  for (const record of metadataRecords) {\n    if (record && record.id && !driveFileIds.has(record.id)) {\n      recordsToDelete.push({\n        ...record,\n        _shouldDelete: true\n      });\n    }\n  }\n}\n\nconsole.log(\"Records to delete:\", recordsToDelete.length);\nreturn recordsToDelete;"
      },
      "typeVersion": 2
    },
    {
      "id": "d12aeac5-f570-49c7-8276-5a53648026cb",
      "name": "Delete Rows2",
      "type": "n8n-nodes-base.supabase",
      "position": [
        1568,
        2048
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "keyValue": "={{ $json.id }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "document_metadata",
        "matchType": "allFilters",
        "operation": "delete"
      },
      "typeVersion": 1
    },
    {
      "id": "5b4cd434-4799-4981-a585-21c69d8329d5",
      "name": "Search files and folders",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        128,
        784
      ],
      "parameters": {
        "filter": {},
        "options": {
          "fields": [
            "webViewLink",
            "id",
            "name",
            "mimeType"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "='Your Folder ID' in parents and trashed=false",
        "searchMethod": "query"
      },
      "typeVersion": 3
    },
    {
      "id": "e2bbc2ba-cce7-4410-b5e9-60fc1bf7dacb",
      "name": "Postgres Chat Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "position": [
        592,
        352
      ],
      "parameters": {},
      "typeVersion": 1.3
    },
    {
      "id": "33dbd2eb-d1dc-426c-9939-45461780cffe",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        304,
        176
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "554ad606-2bd7-49c9-a415-0c9f88ae4ac8",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        448,
        352
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "0b83f6fc-e67c-4a00-a26d-80efdf87213b",
      "name": "Embeddings Google Gemini",
      "type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
      "position": [
        1200,
        368
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "052b2e8f-de1a-4bea-b67c-387c362f23f7",
      "name": "Embeddings Google Gemini1",
      "type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
      "position": [
        1488,
        1136
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "17f0d107-e2e4-4719-826d-33e647c96ed5",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        -688
      ],
      "parameters": {
        "width": 560,
        "height": 320,
        "content": "=========================\n        RAG Agent with G-Drive Sync\n=======================================\nFor any questions or support, please contact:\n    anirudh.n.aeran@gmail.com\n\nExplore more tips here:\n   - LinkedIn: https://www.linkedin.com/in/anirudh-narayan-a-/\n\nHappy learning! -- Anirudh Aeran\n\n\n======================================="
      },
      "typeVersion": 1
    },
    {
      "id": "0a09459f-ceeb-44f9-93ee-c3bdbfa3a527",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -416,
        752
      ],
      "parameters": {
        "width": 256,
        "height": 208,
        "content": "#### This Manual Trigger is Used \n#### for the Initial Ingestion of \n#### Documents to the Vectorbase\n\n**-->After the initial ingestion, \n activate the 2 Google drive \ntriggers to make this \nworkflow Production Ready**"
      },
      "typeVersion": 1
    },
    {
      "id": "7a52403a-8ba4-4a07-81fe-f5ee0c3b63d8",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        -16
      ],
      "parameters": {
        "width": 272,
        "height": 80,
        "content": "\n**--> The Prompt inside the RAG agent can be fine tuned according to your needs**"
      },
      "typeVersion": 1
    },
    {
      "id": "1a0f8c51-1376-4520-a123-75d400095ecf",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        -336
      ],
      "parameters": {
        "color": 5,
        "width": 380,
        "height": 776,
        "content": "## Try It Out!\n\nThis is a comprehensive, production-ready Retrieval-Augmented Generation (RAG) system. It builds a sophisticated AI agent that can answer questions based on documents in a specific Google Drive folder, and it automatically keeps its knowledge base up-to-date as you add, update, or remove files.\n\n**To get started:**\n\n1. **Connect all credentials** (Gemini, supabase, postgres, drive, and Cohere). Refer the Sticky Notes and [n8n docs](https://docs.n8n.io/)\n\n2. **Create the Tables** inside Supabase by copying the code from here. If You don't have an account create one and then on the side panel click on SQL Editor to copy paste the code [Code](https://docs.google.com/document/d/1tLJ7fndrDjYMfyQ1R61q5NbqDs5ZMgvhzcMzkoIzj5M/edit?usp=sharing)\n\n3. **Activate the workflow** by replacing the [Folder ID] with your drive folder ID inside \"Search files and folders\" Node and then upload file(s) which are of doc or pdf format.\n\n4. **For the First Time** use the manual Trigger to vectorize and push the contents of the files to Supabase\n\n5. **Ask any question** related to the the contents of the file using the Chat Trigger in Step 2 and Experience the magic of the RAG Agent.\n\n6. **Once The test is completed**, activate both the google drive trigger nodes in the step 1 flow. This will make sure that the workflow is production ready."
      },
      "typeVersion": 1
    },
    {
      "id": "9c12acb0-3516-4573-8468-eabb1548fbac",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        -224
      ],
      "parameters": {
        "width": 304,
        "height": 288,
        "content": "## --> Postgres Connection\n\nClick on \"connect\" on the top of your Supabase account. Then click on the \"Connection Pooling\" tab and make sure the \"Transaction\" pooler is selected. \n\nYou will see something similar to this screenshot: [View Image](https://i.postimg.cc/htxnsprc/Screenshot-2025-10-02-143424.png)\n\nReplace the fields inside your n8n Postgres credential with the matching values from that page."
      },
      "typeVersion": 1
    },
    {
      "id": "67aac6f9-e5aa-4c7f-aea3-e19d32e36367",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1664,
        336
      ],
      "parameters": {
        "height": 128,
        "content": "**Go to this website, https://dashboard.cohere.com/  create an account and copy the API key to connect Reranker Cohere**"
      },
      "typeVersion": 1
    },
    {
      "id": "a34b0cd1-51fd-469e-9ba0-7961cea3f2d1",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        1536
      ],
      "parameters": {
        "width": 304,
        "height": 576,
        "content": "## How the Cleanup Works\n\nThis is a scheduled process that runs automatically once every day. Its purpose is to keep your knowledge base synchronized by removing data from files that have been deleted in Google Drive.\n\nHere\u2019s the step-by-step process:\n\n* The workflow fetches a list of all current file IDs from your designated Google Drive folder.\n* It also fetches a list of all file IDs stored in your Supabase tables.\n* A **Code node** compares these two lists to identify \"orphaned\" data\u2014entries in Supabase that no longer have a matching file in Google Drive.\n* Finally, the workflow deletes all data associated with those orphaned IDs.\n\nThis cleanup process targets **two separate tables** to ensure all related information is removed: the main `documents` table (storing the content) and the `document_metadata` table (storing the file titles and URLs)."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Code1": {
      "main": [
        [
          {
            "node": "Delete Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code2": {
      "main": [
        [
          {
            "node": "Delete Rows2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge2": {
      "main": [
        [
          {
            "node": "Code2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Extract PDF Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Extract Document Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Supabase2": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Set File ID": {
      "main": [
        [
          {
            "node": "Delete Old Doc Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "File Created": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "File Updated": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get File IDs": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get File IDs2": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download File1": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Set File ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reranker Cohere": {
      "ai_reranker": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_reranker",
            "index": 0
          }
        ]
      ]
    },
    "Extract PDF Text": {
      "main": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get File IDs",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get File IDs2",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Delete Old Doc Rows": {
      "main": [
        [
          {
            "node": "Insert Document Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Default Data Loader1": {
      "ai_document": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "RAG Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Extract Document Text": {
      "main": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Vector Store": {
      "ai_tool": [
        [
          {
            "node": "RAG Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Character Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Default Data Loader1",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings Google Gemini": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "RAG Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Insert Document Metadata": {
      "main": [
        [
          {
            "node": "Download File1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search files and folders": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings Google Gemini1": {
      "ai_embedding": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "RAG Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert into Supabase Vectorstore": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Test workflow\u2019": {
      "main": [
        [
          {
            "node": "Search files and folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This template creates a comprehensive, production-ready Retrieval-Augmented Generation (RAG) system. It builds a sophisticated AI agent that can answer questions based on documents stored in a specific Google Drive folder, and it automatically keeps its knowledge base up-to-date…

Source: https://n8n.io/workflows/9007/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Your AI workforce is ready. Are you?

Google Sheets Tool, Mcp Trigger, Google Drive +29
AI & RAG

Automate Outreach Prospect automates finding, enriching, and messaging potential partners (like restaurants, malls, and bars) using Apify Google Maps scraping, Perplexity enrichment, OpenAI LLMs, Goog

@Devlikeapro/N8N Nodes Waha, Google Drive Trigger, @Apify/N8N Nodes Apify +14
AI & RAG

This simple philosophy changes the way we think about automated sales agents. Context changes everything. In this 4-part workflow, we start by creating a knowledge base that will act as context across

Pinecone Vector Store, Document Default Data Loader, Text Splitter Recursive Character Text Splitter +12
AI & RAG

Chat with docs - 5minAI New version. Uses httpRequest, documentDefaultDataLoader, textSplitterRecursiveCharacterTextSplitter, embeddingsOpenAi. Event-driven trigger; 62 nodes.

HTTP Request, Document Default Data Loader, Text Splitter Recursive Character Text Splitter +10
AI & RAG

I prepared a detailed guide that illustrates the entire process of building an AI agent using Supabase and Google Drive within N8N workflows.

HTTP Request, Document Default Data Loader, Text Splitter Recursive Character Text Splitter +10