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
- 1Connect OpenAI and Supabase credentials
- 2Point the vector search request at your Supabase RPC/table endpoint
- 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": []
}