{
  "name": "Maintain RAG embeddings with OpenAI, Postgres and auto drift rollback",
  "nodes": [
    {
      "id": "e5d849d1-ca42-457f-8bf6-9afce5e203cd",
      "name": "Daily RAG Maintenance Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -2592,
        544
      ]
    },
    {
      "id": "46c10059-edfb-410f-afd0-c5841f9eb0db",
      "name": "Source Change Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2592,
        720
      ]
    },
    {
      "id": "ebd11e90-ec01-4770-9050-df2590234763",
      "name": "Workflow Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -2176,
        624
      ]
    },
    {
      "id": "9a9337b0-f69e-4a48-b6b2-41671d4ce27f",
      "name": "Fetch Documents from Source",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1888,
        544
      ]
    },
    {
      "id": "75dcd272-6cde-4182-a737-5878dfb6ef6a",
      "name": "Chunk Documents & Compute Hash",
      "type": "n8n-nodes-base.code",
      "position": [
        -1712,
        544
      ]
    },
    {
      "id": "e2465a66-7ebc-4397-821b-1e3db90bb3e1",
      "name": "Fetch Previous Chunk Hashes",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -1808,
        784
      ]
    },
    {
      "id": "f3c313cc-22bd-43d5-8e2d-711dcb51ca45",
      "name": "Detect Changed Chunks",
      "type": "n8n-nodes-base.compareDatasets",
      "position": [
        -1440,
        608
      ]
    },
    {
      "id": "cc6d43e4-ce35-46dc-89e0-3535da38f600",
      "name": "OpenAI Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        -528,
        1136
      ]
    },
    {
      "id": "7b6b95f5-6b60-4f06-86fd-866759f00ae5",
      "name": "Recursive Text Splitter",
      "type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
      "position": [
        -1088,
        960
      ]
    },
    {
      "id": "a8c7e05c-fe84-4de9-bdaa-f33edd20c288",
      "name": "Document Loader",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        -1120,
        768
      ]
    },
    {
      "id": "a6d72254-9a77-401c-b86d-1b4c58030403",
      "name": "New Vector Store (Candidate)",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
      "position": [
        -1104,
        576
      ]
    },
    {
      "id": "2959fcfd-5b93-4468-b295-4a87fcf55a4c",
      "name": "Store Embedding Metadata",
      "type": "n8n-nodes-base.code",
      "position": [
        -800,
        576
      ]
    },
    {
      "id": "d221d657-735f-458b-89d6-b9bee5203678",
      "name": "Save Embedding Version Metadata",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -608,
        608
      ]
    },
    {
      "id": "3f59580c-fd71-4d0f-a207-3e2abe4f931c",
      "name": "Fetch Golden Questions",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -272,
        560
      ]
    },
    {
      "id": "80ea7d22-0593-4381-9ed5-ce11efd2be2f",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -64,
        336
      ]
    },
    {
      "id": "65567321-858a-46fa-a1b8-e59ce5e7304f",
      "name": "Fetch Previous Embeddings",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -272,
        736
      ]
    },
    {
      "id": "b3acc41b-0d1c-4d01-8408-314a53ffc44c",
      "name": "Calculate Quality Metrics",
      "type": "n8n-nodes-base.code",
      "position": [
        464,
        560
      ]
    },
    {
      "id": "5c3f669c-f827-4d1d-ab6c-0683eb23d368",
      "name": "Calculate Embedding Drift",
      "type": "n8n-nodes-base.code",
      "position": [
        688,
        560
      ]
    },
    {
      "id": "8b968fe4-643a-456e-9203-b8ed6b55fa72",
      "name": "Quality Improved?",
      "type": "n8n-nodes-base.if",
      "position": [
        912,
        560
      ]
    },
    {
      "id": "59d710fc-e69a-4579-8481-99820b6f7906",
      "name": "Promote New Embeddings",
      "type": "n8n-nodes-base.postgres",
      "position": [
        1264,
        336
      ]
    },
    {
      "id": "5bd21c63-c692-46ba-85c9-375d058d44df",
      "name": "Rollback to Previous Embeddings",
      "type": "n8n-nodes-base.postgres",
      "position": [
        1264,
        528
      ]
    },
    {
      "id": "fe56b7a7-9b48-4027-b2be-671e7a5c8087",
      "name": "Flag for Human Review",
      "type": "n8n-nodes-base.set",
      "position": [
        1264,
        704
      ]
    },
    {
      "id": "2f1c22b3-3b65-49f5-8589-07cb9f1275aa",
      "name": "Send Notification",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1616,
        496
      ]
    },
    {
      "id": "926483cd-5885-4965-8041-52249e122a34",
      "name": "Generate Answers (New)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        32,
        -96
      ]
    },
    {
      "id": "8ccd53ea-448c-4ac8-83cb-f3b1569886d0",
      "name": "Generate Answers (Old)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        32,
        720
      ]
    },
    {
      "id": "ea0fdd00-42ef-4cf1-8717-31878250a696",
      "name": "Query New Vector Store (Tool)",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
      "position": [
        112,
        272
      ]
    },
    {
      "id": "10b00af5-e40b-434b-9f8a-12423c457ec9",
      "name": "Query Old Vector Store (Tool)",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
      "position": [
        32,
        944
      ]
    },
    {
      "id": "4fff807d-8058-4315-bf37-57fc21e0b51d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        272
      ],
      "parameters": {
        "width": 400,
        "height": 464,
        "content": "## Retrieval Quality Evaluation\n\nThis step evaluates answers generated from the new and old embeddings.\n\nMetrics calculated include:\n• Recall@K for retrieved passages\n• Keyword similarity in answers\n•"
      }
    },
    {
      "id": "22c2e5d7-ba09-4287-87ec-692f038b063b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -656,
        1024
      ],
      "parameters": {
        "width": 368,
        "height": 256,
        "content": "## OpenAI Embeddings"
      }
    },
    {
      "id": "65a88fe4-9094-4166-b1c0-05facfaddbdf",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        112
      ],
      "parameters": {
        "width": 336,
        "height": 256,
        "content": "## Vector Store Retrieval Tools\n\nThese vector store tools allow AI agents to retrieve relevant context from embeddings.\nQuery New Vector Store searches candidate embeddings."
      }
    },
    {
      "id": "8346cd65-581b-43ac-aa4d-8359584c625d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -256
      ],
      "parameters": {
        "width": 384,
        "height": 352,
        "content": "## RAG Answer Generation\n\nThis agents answer the same questions using different vector stores.\nOne agent queries the new candidate embeddings."
      }
    },
    {
      "id": "f925fc28-3bc9-4a90-96dc-7b0f52368a8d",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        384
      ],
      "parameters": {
        "width": 288,
        "height": 272,
        "content": "A notification is then sent through the configured webhook to inform the team about the update status."
      }
    },
    {
      "id": "ccc28ddf-cd78-4160-8e3b-dd853bfc5f50",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1120,
        192
      ],
      "parameters": {
        "width": 384,
        "height": 672,
        "content": " ## Deployment Outcome\n\nBased on evaluation results, the workflow either promotes the new embeddings, rolls back to the previous version, or flags the update for manual review."
      }
    },
    {
      "id": "8321cb20-23f8-409e-bc20-9e4e5f0a8060",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -688,
        464
      ],
      "parameters": {
        "width": 656,
        "height": 496,
        "content": "## Golden Question Evaluation\n\nThe system runs predefined golden questions against both the new and old vector stores.\nAI agents generate answers using retrieved context so the workflow can evaluate r"
      }
    },
    {
      "id": "af796be8-4449-47d5-9ffb-882b1278bc37",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1136,
        448
      ],
      "parameters": {
        "width": 304,
        "height": 736,
        "content": "## Embedding Creation\n\nChanged document chunks are embedded using OpenAI embeddings."
      }
    },
    {
      "id": "84cbef0e-1d93-440e-9bc9-e5e310df8389",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        368
      ],
      "parameters": {
        "width": 320,
        "height": 576,
        "content": "##Chunk Change Detection\n\nNew document chunk hashes are compared with hashes stored in Postgres."
      }
    },
    {
      "id": "049e6eb0-c276-49fb-b188-6ed8a568249d",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        560
      ],
      "parameters": {
        "width": 368,
        "height": 528,
        "content": "## RAG Answer Generation\n\nThis agents answer the same questions using existing vector stores.\nOne agent queries the old candidate embeddings"
      }
    },
    {
      "id": "18631d03-add9-43d2-ba34-47e86af6cc79",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1968,
        336
      ],
      "parameters": {
        "width": 384,
        "height": 576,
        "content": "## Document Retrieval & Chunking\n\nDocuments are fetched from the configured source and split into deterministic chunks.\nEach chunk receives a SHA-256 hash to detect content changes and ensure only mod"
      }
    },
    {
      "id": "f178914d-4ac1-4941-a6df-fab448ea6c68",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2688,
        384
      ],
      "parameters": {
        "width": 672,
        "height": 528,
        "content": "## Workflow Trigger & Config\n\nThis section starts the workflow via schedule or webhook trigger.\nIt defines key parameters such as document source URL, chunk size, overlap, quality threshold, drift thr"
      }
    },
    {
      "id": "ac724435-1642-4bc8-a66c-47f95dcc45ba",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        464
      ],
      "parameters": {
        "width": null,
        "height": 240,
        "content": "## compare scores"
      }
    },
    {
      "id": "ec692a1c-7ff4-46bf-8798-29752574ac24",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3392,
        464
      ],
      "parameters": {
        "width": 576,
        "height": 544,
        "content": " This workflow maintains a self-healing Retrieval-Augmented Generation (RAG) system by automatically updating document embeddings, evaluating quality, detecting embedding drift, and safely promoting o"
      }
    }
  ],
  "connections": {
    "Document Loader": {
      "ai_document": [
        [
          {
            "node": "New Vector Store (Candidate)",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Answers (New)",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Generate Answers (Old)",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "New Vector Store (Candidate)",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "Query New Vector Store (Tool)",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "Query Old Vector Store (Tool)",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Quality Improved?": {
      "main": [
        [
          {
            "node": "Promote New Embeddings",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Rollback to Previous Embeddings",
            "type": "main",
            "index": 0
          },
          {
            "node": "Flag for Human Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Changed Chunks": {
      "main": [
        [
          {
            "node": "New Vector Store (Candidate)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Flag for Human Review": {
      "main": [
        [
          {
            "node": "Send Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Source Change Webhook": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Golden Questions": {
      "main": [
        [
          {
            "node": "Generate Answers (New)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate Answers (Old)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Answers (New)": {
      "main": [
        [
          {
            "node": "Calculate Quality Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Answers (Old)": {
      "main": [
        [
          {
            "node": "Calculate Quality Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Promote New Embeddings": {
      "main": [
        [
          {
            "node": "Send Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Fetch Documents from Source",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Previous Chunk Hashes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Recursive Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Document Loader",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    },
    "Store Embedding Metadata": {
      "main": [
        [
          {
            "node": "Save Embedding Version Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Embedding Drift": {
      "main": [
        [
          {
            "node": "Quality Improved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Quality Metrics": {
      "main": [
        [
          {
            "node": "Calculate Embedding Drift",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Documents from Source": {
      "main": [
        [
          {
            "node": "Chunk Documents & Compute Hash",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Previous Chunk Hashes": {
      "main": [
        [
          {
            "node": "Detect Changed Chunks",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "New Vector Store (Candidate)": {
      "main": [
        [
          {
            "node": "Store Embedding Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query New Vector Store (Tool)": {
      "ai_tool": [
        [
          {
            "node": "Generate Answers (New)",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Query Old Vector Store (Tool)": {
      "ai_tool": [
        [
          {
            "node": "Generate Answers (Old)",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Chunk Documents & Compute Hash": {
      "main": [
        [
          {
            "node": "Detect Changed Chunks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily RAG Maintenance Schedule": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rollback to Previous Embeddings": {
      "main": [
        [
          {
            "node": "Send Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Embedding Version Metadata": {
      "main": [
        [
          {
            "node": "Fetch Golden Questions",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Previous Embeddings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}