Moonwalk Projects logoMoonwalk Projects
Back to templates

n8n workflow template

Knowledge Base Search Sub-workflow

Called as a tool by other workflows (e.g. the WhatsApp agent). Embeds the incoming query with OpenAI, performs a vector similarity search against Supabase, and returns a numbered context block plus a source list for citations.

Starter10-15 minutesn8nOpenAISupabase
01

What this workflow handles

  • Drop-in RAG retrieval tool for any n8n AI agent
  • Source-attributed answers
02

Setup steps

  1. 1Connect OpenAI and Supabase credentials
  2. 2Point the vector search request at your Supabase RPC/table endpoint
  3. 3Call this workflow as a tool from your main agent workflow
03

Values to replace

Review every placeholder below before activating this workflow. Public downloads should never include live credentials or client data.

  • Supabase vector table endpoint URL
  • OpenAI credential

Workflow JSON preview

Review before downloading or importing.

{
  "name": "search_kb",
  "nodes": [
    {
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "user_query"
            }
          ]
        }
      },
      "id": "c055762a-8fe7-4141-a639-df2372f30060",
      "typeVersion": 1.1,
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        464,
        480
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/embeddings",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openAiApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"text-embedding-3-small\",\n  \"input\": \"{{ $json.user_query }}\"\n}",
        "options": {}
      },
      "id": "076080af-c0e3-4ce1-b868-eb33255a1cd7",
      "name": "Embed Question",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        720,
        480
      ],
      "retryOnFail": true,
      "credentials": {
        "openAiApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "OpenAI account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "LINK TO YOUR SUPABASE VECTOR TABLE",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"query_embedding\": {{ JSON.stringify($json.data[0].embedding) }},\n  \"match_count\": 5\n}",
        "options": {}
      },
      "id": "4afd33e7-92d0-43b0-ad05-d7eb35882000",
      "name": "Supabase: Vector Search",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        960,
        480
      ],
      "retryOnFail": true,
      "credentials": {
        "supabaseApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "Supabase account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Build the context block (numbered chunks) and a matching sources list for citations.\nconst question = $('When Executed by Another Workflow').first().json.user_query|| $('Ask Question (Webhook)').item.json.question\n  || '';\n\nconst matches = $input.all().map(i => i.json);\n\nconst contextParts = matches.map((m, idx) => `[${idx + 1}] ${m.content}`);\nconst context = contextParts.join('\\n\\n');\n\nconst sources = matches.map((m, idx) => ({\n  n: idx + 1,\n  title: m.metadata?.title || 'Untitled',\n  url: m.metadata?.notion_url || ''\n}));\n\nreturn [{ json: { question, context, sources } }];"
      },
      "id": "531471b9-172b-4c5f-9dac-ac6928fb1af8",
      "name": "Build Context & Sources",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        480
      ]
    }
  ],
  "pinData": {},
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Embed Question",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embed Question": {
      "main": [
        [
          {
            "node": "Supabase: Vector Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Vector Search": {
      "main": [
        [
          {
            "node": "Build Context & Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Context & Sources": {
      "main": [
        []
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "timeSavedMode": "fixed",
    "saveDataErrorExecution": "all",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "versionId": "47df270b-9bf4-4432-8dc2-eb8cdc021ffe",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodeGroups": [],
  "id": "AvvHbJ6ltlTEfPPa",
  "tags": []
}