N
n8n Store
Workflow Market
Smarter RAG Agents with Enriched Retrieval, Filters & Memory - by ascuncia

Smarter RAG Agents with Enriched Retrieval, Filters & Memory - by ascuncia

by ascuncia0 views

描述

分类

🤖 AI & Machine Learning

使用的节点

n8n-nodes-base.setn8n-nodes-base.setn8n-nodes-base.waitn8n-nodes-base.mergen8n-nodes-base.supabasen8n-nodes-base.supabasen8n-nodes-base.supabasen8n-nodes-base.stickyNoten8n-nodes-base.stickyNoten8n-nodes-base.stickyNote
价格免费
浏览量0
最后更新11/28/2025
workflow.json
{
  "id": "cN01cF1imXdMQfro",
  "meta": {
    "instanceId": "adebbe2592e5612173c7a1dda20af6cbd944e35e3d0414c25474c49218afc346",
    "templateCredsSetupCompleted": true
  },
  "name": "Smarter RAG Agents with Enriched Retrieval, Filters & Memory - by ascuncia",
  "tags": [],
  "nodes": [
    {
      "id": "6052b910-009b-4db5-a956-096758e7cc07",
      "name": "Default Data Loader",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        320,
        704
      ],
      "parameters": {
        "options": {
          "metadata": {
            "metadataValues": [
              {
                "name": "=doc_id",
                "value": "={{ $('Set File Data').item.json.doc_id }}"
              },
              {
                "name": "doc_title",
                "value": "={{ $('Set File Data').item.json.doc_title }}"
              },
              {
                "name": "doc_type",
                "value": "={{ $('Set File Data').item.json.doc_type }}"
              },
              {
                "name": "source",
                "value": "={{ $('Set File Data').item.json.source }}"
              },
              {
                "name": "processed",
                "value": "false"
              }
            ]
          }
        },
        "jsonData": "={{ $('Extract from File').item.json.text }}",
        "jsonMode": "expressionData"
      },
      "typeVersion": 1
    },
    {
      "id": "c777cf9b-4048-4889-98e1-da1c38aaeb50",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        448
      ],
      "parameters": {
        "color": 5,
        "width": 1751,
        "height": 672,
        "content": "## File Ingestion pipeline"
      },
      "typeVersion": 1
    },
    {
      "id": "cb389645-8257-4542-9255-ada92122865f",
      "name": "Recursive Character Text Splitter",
      "type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
      "position": [
        400,
        912
      ],
      "parameters": {
        "options": {},
        "chunkSize": 1500,
        "chunkOverlap": 150
      },
      "typeVersion": 1
    },
    {
      "id": "a034b27b-f602-43b4-a588-c284610a0b90",
      "name": "Delete Old Doc Rows",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -256,
        768
      ],
      "parameters": {
        "tableId": "documents",
        "operation": "delete",
        "filterType": "string",
        "filterString": "=metadata->>doc_id=eq.{{ $('On form submission').item.json.File[0].filename }}"
      },
      "credentials": {
        "supabaseApi": {
          "id": "CJBJzRJNUpKL96fh",
          "name": "Supabase - RAG-DB"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "95aeede8-3cd7-489b-ae0e-f197af68fdde",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -736,
        -32
      ],
      "webhookId": "f3071b55-8fd9-4aea-ba97-8aeaaa6cf953",
      "parameters": {
        "public": true,
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "2a479838-750b-4a07-b58b-629040fef5f3",
      "name": "Insert into Supabase Vectorstore",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        224,
        480
      ],
      "parameters": {
        "mode": "insert",
        "options": {
          "queryName": "match_documents"
        },
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "documents",
          "cachedResultName": "documents"
        }
      },
      "credentials": {
        "supabaseApi": {
          "id": "CJBJzRJNUpKL96fh",
          "name": "Supabase - RAG-DB"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d3adc752-00a4-4e06-9d8b-93975b6248c2",
      "name": "Embeddings Google Gemini1",
      "type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
      "position": [
        192,
        704
      ],
      "parameters": {},
      "credentials": {
        "googlePalmApi": {
          "id": "qiYf0c3QAERXYWhH",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9b02b9e2-1883-4c81-bf70-0d07aafd8c4d",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -928,
        672
      ],
      "webhookId": "6c4668b3-6d00-4902-ace7-a9155048779a",
      "parameters": {
        "options": {},
        "formTitle": "Archivo",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "File",
              "multipleFiles": false,
              "requiredField": true,
              "acceptFileTypes": ".pdf"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1545a027-fa95-4344-84eb-54da0b454285",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -704,
        672
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "File"
      },
      "typeVersion": 1
    },
    {
      "id": "495722e8-2746-40ec-8793-667ab334bd89",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -512,
        1360
      ],
      "parameters": {
        "options": {},
        "batchSize": 5
      },
      "typeVersion": 3
    },
    {
      "id": "202868eb-6fab-4d39-a3c6-cdc0601abf86",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        1136
      ],
      "parameters": {
        "width": 1751,
        "height": 672,
        "content": "## Enrichment Pipeline"
      },
      "typeVersion": 1
    },
    {
      "id": "177b1443-2e70-40e0-9a5b-2885e0a95f85",
      "name": "Get many rows",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -736,
        1360
      ],
      "parameters": {
        "limit": 150,
        "tableId": "documents",
        "operation": "getAll",
        "filterType": "string",
        "filterString": "metadata->>processed=not.eq.true"
      },
      "credentials": {
        "supabaseApi": {
          "id": "CJBJzRJNUpKL96fh",
          "name": "Supabase - RAG-DB"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6cb4273c-9f85-46bf-aae6-5d1a7b33321a",
      "name": "Update a row",
      "type": "n8n-nodes-base.supabase",
      "position": [
        320,
        1360
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "=id",
              "keyValue": "={{ $('Edit Fields').item.json.row_id }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "documents",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "metadata",
              "fieldValue": "={{ JSON.stringify(\n  (() => {\n    const prev = $item(0).$node[\"Get many rows\"].json.metadata || {};\n    let enriched = {};\n    try {\n      const raw = $('Metadata Obtention').item.json.content?.parts?.[0]?.text || \"{}\";\n      enriched = JSON.parse(raw);\n    } catch(_) {}\n    return {\n      ...prev,\n      ...enriched,\n      processed: true,\n      enricher_version: \"v2-generic-2025-08\",\n      enriched_at: new Date().toISOString(),\n    };\n  })()\n) }}\n"
            }
          ]
        },
        "matchType": "allFilters",
        "operation": "update"
      },
      "credentials": {
        "supabaseApi": {
          "id": "CJBJzRJNUpKL96fh",
          "name": "Supabase - RAG-DB"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8f6c4eef-8e8a-4149-8547-d5154fc68348",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        -32,
        688
      ],
      "parameters": {
        "mode": "chooseBranch"
      },
      "typeVersion": 3.2
    },
    {
      "id": "ec4628dc-0b9b-416a-b9d8-bf5999828382",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        512,
        1360
      ],
      "webhookId": "f99c8e49-43ad-4b63-b788-2c91981647e7",
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "05d41aff-ac21-4f17-a807-485a8c6a58ba",
      "name": "Set File Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -480,
        672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "10646eae-ae46-4327-a4dc-9987c2d76173",
              "name": "doc_id",
              "type": "string",
              "value": "={{ $('On form submission').item.json.File.filename }}"
            },
            {
              "id": "d75d991a-98ce-4070-943d-22e555a074c5",
              "name": "doc_title",
              "type": "string",
              "value": "={{ $json.info.Title || $json.data.filename }}"
            },
            {
              "id": "d7cff574-0e40-4d67-9c88-dacb8e97c45e",
              "name": "doc_type",
              "type": "string",
              "value": "={{ \"guide\" }}"
            },
            {
              "id": "82b5bfb4-f33d-4268-b9d4-8dd3c2f0f097",
              "name": "source",
              "type": "string",
              "value": "={{ \"uploaded_pdf\" }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "74925cc0-31fb-4ff5-9dea-9af6b155ad63",
      "name": "Metadata Obtention",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "onError": "continueErrorOutput",
      "position": [
        -32,
        1360
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemma-3-12b-it",
          "cachedResultName": "models/gemma-3-12b-it"
        },
        "options": {
          "temperature": 0.1,
          "maxOutputTokens": 512
        },
        "messages": {
          "values": [
            {
              "content": "=You are a metadata enricher for arbitrary business documents (guides, manuals, best practices, policies, FAQs, playbooks).\n\nTASK\nAnalyze the provided TEXT CHUNK and return a SINGLE-LINE, MINIFIED JSON object (no backticks, no prose). Use ONLY what is explicitly present or safely implied by the chunk. If a field does not apply, use null or [] accordingly.\n\nINPUTS\n- chunk_text: {{ $json.content }}\n- file metadata (for disambiguation only; DO NOT copy values if not present in the chunk):\n  - doc_title: {{ $json.metadata.doc_title }}\n  - doc_type: {{ $json.metadata.doc_type }}\n\nOUTPUT SCHEMA (exact keys; keep values short and consistent):\n{\n  \"topics\": [\"keyword1\",\"keyword2\"],             // up to 8\n  \"feature\": \"short_tag\",                         // e.g., \"workspaces\", \"databases\", \"onboarding\", \"security\"\n  \"use_case\": \"short_tag\",                        // e.g., \"workspace_structure\", \"communication\", \"setup\", \"policy\"\n  \"audience\": \"beginner|intermediate|advanced|null\",\n  \"section\": \"section_or_heading_if_any\",\n  \"entities\": [\"product|role|team|concept\"],      // proper names or domain terms\n  \"key_recommendations\": [\"bullet1\",\"bullet2\"],   // up to 5 concise, actionable bullets\n  \"risks_or_pitfalls\": [\"risk1\",\"risk2\"],         // up to 5; [] if none\n  \"examples_present\": true,                       // whether the chunk includes an example\n  \"language\": \"auto_detected_iso_639_1\",          // e.g., \"en\", \"es\", \"pt\", \"it\"; infer from chunk_text\n  \"chunk_summary\": \"1-2 sentence neutral summary\" // plain, factual, grounded in the chunk\n}\n\nGUIDELINES\n- Prefer concrete nouns/verbs over vague words.\n- Do not invent entities or recommendations; keep them grounded in the text.\n- If multiple candidates exist, choose the most central one (or null).\n- Deduplicate arrays; keep strings on a single line; no trailing punctuation in bullets.\n\nRETURN ONLY THE MINIFIED JSON, ONE LINE.\n"
            }
          ]
        }
      },
      "credentials": {
        "googlePalmApi": {
          "id": "qiYf0c3QAERXYWhH",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "507d8646-ef0b-442a-a887-496dcec2dbd2",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -960,
        1360
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 25
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "a61859c2-872f-4510-a43f-c8490a76b938",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        -256,
        1360
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ea722112-aad6-419d-b187-f40044bf3b8a",
              "name": "row_id",
              "type": "number",
              "value": "={{$json.id}}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "63388b99-9d84-41cf-b8c6-94186db049b2",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        -384
      ],
      "parameters": {
        "color": 4,
        "width": 1744,
        "height": 800,
        "content": "## RAG Chat Agent"
      },
      "typeVersion": 1
    },
    {
      "id": "1689c6a8-ba5f-493b-b31b-718bf7ce2ada",
      "name": "Query Builder",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        -512,
        -32
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemma-3n-e2b-it",
          "cachedResultName": "models/gemma-3n-e2b-it"
        },
        "options": {
          "temperature": 0.1,
          "maxOutputTokens": 128
        },
        "messages": {
          "values": [
            {
              "content": "=You are a query builder for a document retrieval system (RAG). \nYour task: analyze the user’s question and output ONE SINGLE-LINE, MINIFIED JSON. No prose.\n\nOUTPUT SCHEMA (always valid JSON, one line):\n{\n  \"keywords\": [\"k1\",\"k2\",\"k3\"],          // up to 6 short terms from the question\n    \"filters\": {                           // OPTIONAL filters; include only if clearly implied, domain specific - do not include\n  }\n}\n\nRULES\n- Keep keywords concise; avoid stop-words or full sentences.\n- Only add filters if the intent is clear from the question.\n- If the user just greets or provides no query, return {\"keywords\":[]} with no filters.\n\n\nOUTPUT\n- Output ONLY valid JSON, minified, one single line.\n- Do NOT add ```json, code fences, or any text before/after.\n- Do NOT include newlines.\n\nINPUT\n{{ $json.chatInput }}\n\nNOTE\n- Domain-specific logic (e.g., mapping to product features, principles, policies) can be added here in future.\n"
            }
          ]
        }
      },
      "credentials": {
        "googlePalmApi": {
          "id": "qiYf0c3QAERXYWhH",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dee30e44-bd9b-421f-b9d0-5365ca8813bf",
      "name": "RAG Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -96,
        -240
      ],
      "parameters": {
        "text": "={{ $('When chat message received').item.json.chatInput }}",
        "options": {
          "systemMessage": "=You are a friendly but objective RAG assistant. You may only answer using passages returned by the tool \"Supabase Vector Store\". \nIf in this turn you did not call the tool at least once, reply:\n\"I don't have enough evidence in the indexed documents to answer this.\"\n\nLANGUAGE\n- Always answer in the user's language. Detect automatically from the user message.\n\nRECOVERY QUERY\n- Use the JSON line produced by \"Query Builder\". If it contains multiple keywords or filters, pass them to the retrieval tool.\n- If the query is ambiguous, still retrieve with general keywords and let the reranker select the best contexts.\n\nANSWER RULES\n\"\n- Prefer 2–4 distinct passages. If only 1 is available, say evidence is limited. Always form a concrete answer with the passages, not lost sentences.\n- Do NOT import outside knowledge. If relevant passages are weak or missing, say so and suggest a clearer question.\n- If the user's message is just a greeting (e.g., \"hi\"), do NOT call tools. Respond with a short greeting and invite a question.\n\nOUTPUT STYLE\n- Concise, friendly but objective.\n- Add a section below with References, with the format\n  \"Source: <doc_title> — <section>. Use a title for the section and bullets.\n- No hallucinations; everything must be grounded in retrieved text.\n\nFAILSAFE\n- If retrieval returns authors/topics unrelated to the user's intent, ignore them and state that no relevant evidence was found.\n"
        },
        "promptType": "define"
      },
      "typeVersion": 2
    },
    {
      "id": "14f8779d-043a-4b3b-8f96-ff6a0f5c1026",
      "name": "Reranker",
      "type": "@n8n/n8n-nodes-langchain.rerankerCohere",
      "position": [
        240,
        192
      ],
      "parameters": {
        "topN": 8
      },
      "credentials": {
        "cohereApi": {
          "id": "nqvzqvHfJbmT7AS2",
          "name": "CohereApi account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "024e08cb-30a6-4a1d-804c-f715b77ab220",
      "name": "Google Gemini 2.0 Flash",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -160,
        -16
      ],
      "parameters": {
        "options": {
          "temperature": 0.2
        },
        "modelName": "models/gemini-2.0-flash"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "qiYf0c3QAERXYWhH",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "af9307db-b459-4ce2-8dd6-c4207edfdc16",
      "name": "Postgres Chat Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "position": [
        -32,
        -16
      ],
      "parameters": {},
      "credentials": {
        "postgres": {
          "id": "DjwLcr6VNmIxcuo8",
          "name": "Postgres account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "ddc2ba09-f1bf-40e3-a48a-1cb08962279d",
      "name": "Embeddings Google Gemini",
      "type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
      "position": [
        112,
        192
      ],
      "parameters": {},
      "credentials": {
        "googlePalmApi": {
          "id": "qiYf0c3QAERXYWhH",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3fa897aa-3299-4198-9ed1-05808311e6dc",
      "name": "Supabase Vector Store",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        112,
        -16
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "topK": 48,
        "options": {
          "metadata": {
            "metadataValues": [
              {
                "name": "doc_type",
                "value": "={{ (() => { try { return (JSON.parse(($('Query Builder').item.json.content?.parts?.[0]?.text || '{}')).filters?.doc_type) } catch(e){ return undefined } })() }}"
              },
              {
                "name": "feature",
                "value": "={{ (() => { try { return (JSON.parse(($('Query Builder').item.json.content?.parts?.[0]?.text || '{}')).filters?.feature) } catch(e){ return undefined } })() }}"
              },
              {
                "name": "use_case",
                "value": "={{ (() => { try { return (JSON.parse(($('Query Builder').item.json.content?.parts?.[0]?.text || '{}')).filters?.use_case) } catch(e){ return undefined } })() }}"
              },
              {
                "name": "topics",
                "value": "={{ (() => { try { const t = JSON.parse(($('Query Builder').item.json.content?.parts?.[0]?.text || '{}')).filters?.topics; return Array.isArray(t) && t.length ? t : undefined } catch(e){ return undefined } })() }}"
              },
              {
                "name": "entities",
                "value": "={{ (() => { try { const t = JSON.parse(($('Query Builder').item.json.content?.parts?.[0]?.text || '{}')).filters?.entities; return Array.isArray(t) && t.length ? t : undefined } catch(e){ return undefined } })() }}"
              }
            ]
          }
        },
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "documents",
          "cachedResultName": "documents"
        },
        "useReranker": true,
        "toolDescription": "=Semantic retrieval tool. Queries the \"documents\" table and returns passages with metadata.\n\nUsage by the agent:\n- Always use the JSON line produced by the Query Builder to form keywords and (optional) metadata filters.\n- If scope is \"multi_document\", allow results from multiple documents; otherwise bias to a single document if clearly implied.\nOutput: fragments with metadata.doc_title, section (if any), feature, use_case, topics, chunk_summary.\n"
      },
      "credentials": {
        "supabaseApi": {
          "id": "CJBJzRJNUpKL96fh",
          "name": "Supabase - RAG-DB"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "84305b9d-2042-4f61-8d87-0208675d2d58",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1424,
        480
      ],
      "parameters": {
        "width": 272,
        "height": 256,
        "content": "## 🟩 File Ingestion Pipeline\n\nExtracts and chunks uploaded PDFs.\nEmbeds content and stores it in Supabase vector DB.\nClean and modular, ready for other sources (Notion, Drive, etc)."
      },
      "typeVersion": 1
    },
    {
      "id": "2eb9bc0a-08dc-468e-88d4-fafb76dddbbb",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1408,
        1152
      ],
      "parameters": {
        "width": 272,
        "height": 256,
        "content": "## 🟨 Enrichment Pipeline (Async)\n\nEnriches chunks with semantic metadata using a lightweight LLM.\nImproves retrieval and enables filters like audience, use_case, risks.\nRuns asynchronously to reduce cost — ideal for free-tier models."
      },
      "typeVersion": 1
    },
    {
      "id": "a8e76143-cb9f-412e-96c3-e9f5cfbf4e17",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1408,
        -384
      ],
      "parameters": {
        "width": 272,
        "height": 288,
        "content": "## 🟦 RAG Agent Pipeline\n\nHandles user questions with memory, filtering, reranking, and references.\nPowered by a Query Builder + Cohere Reranker + Gemini LLM.\nAnswers only with retrieved content — safe, explainable, production-grade."
      },
      "typeVersion": 1
    },
    {
      "id": "315431cf-6b7f-43e9-ac3a-a3b2bd1280d7",
      "cid": "Ikx1Y2FzIFBleXJpbiI",
      "name": "Sticky Note26",
      "type": "n8n-nodes-base.stickyNote",
      "notes": "© 2025 Lucas Peyrin",
      "creator": "Lucas Peyrin",
      "position": [
        -2672,
        -48
      ],
      "parameters": {
        "color": 2,
        "width": 832,
        "height": 1568,
        "content": "## 🧩 Prepare the Database (SQL)\n\nNow we’ll build the foundation that powers search, enrichment, and retrieval — think of it as creating the “semantic filing system” for your document library.\n\n### ✅ **Action Steps:**\n\n- In your Supabase project, open the SQL Editor.\n\n- Locate the sticky note below that includes the full SQL schema.\n\n- Copy the entire SQL code, paste it into the editor, and click “RUN”.\n\n### ⚠️ **Heads-Up:**\n\n- If you get an error saying pgvector already exists, simply delete the first line of the code (create extension vector;) and run it again.\n\n- This workflow uses Gemini embeddings with 768 dimensions.\n→ If you're switching to OpenAI embeddings, you must update the schema line:\nChange vector(768) to vector(1536) to match the correct dimensions.\n\n\n### SQL"
      },
      "typeVersion": 1
    },
    {
      "id": "d9415450-8f09-4120-aacb-af623509c0aa",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2640,
        512
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 896,
        "content": "-- 🧹 (Optional) Clean up any previous table for fresh setup\ndrop table documents;\n\n-- 🧠 Enable pgvector to store and search vector embeddings\ncreate extension vector;\n\n-- 📚 Create the main table to store your document chunks\ncreate table documents (\n  id bigserial primary key,         -- Unique ID for each chunk\n  content text,                     -- The chunk content (pageContent)\n  metadata jsonb,                   -- Metadata like filename, section, topic, etc.\n  embedding vector(768)             -- Gemini embedding vector (768 dims)\n                                    -- ⚠️ If using OpenAI: change to vector(1536)\n);\n\n-- 🔧 Drop older or conflicting versions of the matching function\ndrop function if exists public.match_documents(jsonb, int, vector);\ndrop function if exists public.match_documents(int, vector, jsonb);\ndrop function if exists public.match_documents(vector, int);\n\n-- 🔍 Create a custom function to perform vector search with optional filters\ncreate or replace function public.match_documents (\n  query_embedding vector(768),      -- Input embedding from user query\n  match_count int,                  -- Number of results to return\n  filter jsonb default '{}'::jsonb -- Optional filter using metadata\n)\nreturns table (\n  id bigint,\n  content text,\n  metadata jsonb,\n  embedding vector(768),\n  similarity float                  -- Cosine similarity score\n)\nlanguage sql stable\nas $$\n  select\n    id,\n    content,\n    metadata,\n    embedding,\n    1 - (embedding <#> query_embedding) as similarity  -- Cosine similarity = 1 - distance\n  from documents\n  where (filter is null or filter = '{}'::jsonb or metadata @> filter)\n  order by embedding <#> query_embedding                -- Order by closest match\n  limit match_count;\n$$;\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5e6d500c-a7c9-4618-8eb1-9687146b726f",
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reranker": {
      "ai_reranker": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_reranker",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Metadata Obtention",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update a row": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get many rows": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Builder": {
      "main": [
        [
          {
            "node": "RAG Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set File Data": {
      "main": [
        [
          {
            "node": "Delete Old Doc Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get many rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "Set File Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Metadata Obtention": {
      "main": [
        [
          {
            "node": "Update a row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Default Data Loader": {
      "ai_document": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Delete Old Doc Rows": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "RAG Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Vector Store": {
      "ai_tool": [
        [
          {
            "node": "RAG Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini 2.0 Flash": {
      "ai_languageModel": [
        [
          {
            "node": "RAG Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings Google Gemini": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings Google Gemini1": {
      "ai_embedding": [
        [
          {
            "node": "Insert into Supabase Vectorstore",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Query Builder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert into Supabase Vectorstore": {
      "main": [
        []
      ]
    },
    "Recursive Character Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Default Data Loader",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    }
  }
}

相关工作流