{ "updatedAt": "2026-05-06T23:25:33.293Z", "createdAt": "2026-05-06T23:25:29.005Z", "id": "gYyOggC4J98keLbj", "name": "RAG Pipeline v1.0", "description": null, "active": true, "isArchived": false, "nodes": [ { "parameters": { "httpMethod": "POST", "path": "rag/ingest", "responseMode": "lastNode", "responseData": "allEntries", "options": {} }, "id": "31ce8413-d15c-490f-92d1-956ef214e9a3", "name": "Ingest Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [ 0, 0 ], "webhookId": "411ad4e3-eb9f-49e2-97c4-2f30e01dd609" }, { "parameters": { "jsCode": "// Split incoming text into chunks for embedding\nconst input = $input.first().json.body || $input.first().json;\nconst text = input.text || input.content || '';\nconst source = input.source || 'manual';\nconst metadata = input.metadata || {};\n\nconst CHUNK_SIZE = 500;\nconst OVERLAP = 50;\n\nconst chunks = [];\nconst sentences = text.split(/(?<=[.!?])\\s+/);\nlet current = '';\n\nfor (const sentence of sentences) {\n if ((current + ' ' + sentence).length > CHUNK_SIZE && current.length > 0) {\n chunks.push(current.trim());\n // Keep overlap\n const words = current.split(' ');\n current = words.slice(-OVERLAP).join(' ') + ' ' + sentence;\n } else {\n current = current ? current + ' ' + sentence : sentence;\n }\n}\nif (current.trim()) chunks.push(current.trim());\n\nreturn chunks.map((chunk, i) => ({\n json: {\n chunk,\n chunkIndex: i,\n totalChunks: chunks.length,\n source,\n metadata\n }\n}));" }, "id": "5d5aa0b1-c84b-48f6-9b5e-618cb05e5e61", "name": "Chunk Text", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 224, 0 ] }, { "parameters": { "method": "POST", "url": "http://10.5.1.6:11434/v1/embeddings", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"model\": \"nomic-embed-text\",\n \"input\": \"{{ $json.chunk }}\"\n}", "options": { "batching": { "batch": { "batchSize": 5, "batchInterval": 500 } } } }, "id": "89c692c6-b987-409c-b5c1-3533097d06e3", "name": "Get Embedding", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 448, 0 ] }, { "parameters": { "jsCode": "const embeddingResponse = $input.first().json;\nconst chunkData = $('Chunk Text').item;\nconst embedding = embeddingResponse.data?.[0]?.embedding || [];\n\nconst pointId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); });\n\nreturn [{\n json: {\n id: pointId,\n vector: embedding,\n payload: {\n text: chunkData.json.chunk,\n source: chunkData.json.source,\n chunkIndex: chunkData.json.chunkIndex,\n totalChunks: chunkData.json.totalChunks,\n metadata: chunkData.json.metadata,\n ingested_at: new Date().toISOString()\n }\n }\n}];" }, "id": "fec59066-958f-4b96-8224-6f4e48ad5abb", "name": "Prepare Qdrant Point", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 672, 0 ] }, { "parameters": { "method": "PUT", "url": "http://10.5.1.6:6333/collections/knowledge_base/points", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"points\": [\n {\n \"id\": \"{{ $json.id }}\",\n \"vector\": {{ JSON.stringify($json.vector) }},\n \"payload\": {{ JSON.stringify($json.payload) }}\n }\n ]\n}", "options": {} }, "id": "9404c8fe-46ae-4d8a-bf35-35ecba4939c0", "name": "Upsert to Qdrant", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 880, 0 ] }, { "parameters": { "httpMethod": "POST", "path": "rag/query", "responseMode": "lastNode", "responseData": "allEntries", "options": {} }, "id": "1a5c921c-0351-4a5e-a3e4-0aab71313af1", "name": "Query Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [ 0, 304 ], "webhookId": "aad4fe04-74b0-4136-80e9-380a7e4db1c2" }, { "parameters": { "method": "POST", "url": "http://10.5.1.6:11434/v1/embeddings", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"model\": \"nomic-embed-text\",\n \"input\": \"{{ $json.body.query || $json.query }}\"\n}", "options": {} }, "id": "0a294ba5-a890-4dfa-8ae7-ba25cd0a4534", "name": "Embed Query", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 224, 304 ] }, { "parameters": { "method": "POST", "url": "http://10.5.1.6:6333/collections/knowledge_base/points/search", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"vector\": {{ JSON.stringify($json.data[0].embedding) }},\n \"limit\": 5,\n \"with_payload\": true\n}", "options": {} }, "id": "2cb68891-c57e-4006-b3ac-c290aec28220", "name": "Search Qdrant", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 448, 304 ] }, { "parameters": { "jsCode": "const searchResults = $input.first().json.result || [];\nconst query = $('Query Webhook').first().json.body?.query || $('Query Webhook').first().json.query || '';\n\nconst context = searchResults.map((r, i) => \n `[${i+1}] (score: ${r.score.toFixed(3)}) ${r.payload.text}`\n).join('\\n\\n');\n\nreturn [{\n json: {\n query,\n context,\n sources: searchResults.map(r => ({\n source: r.payload.source,\n score: r.score,\n text_preview: r.payload.text.substring(0, 100) + '...'\n }))\n }\n}];" }, "id": "d32ee814-81d0-4ea6-8f28-59632d09b1b9", "name": "Build Context", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 672, 304 ] }, { "parameters": { "method": "POST", "url": "http://10.5.1.6:4000/v1/chat/completions", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" }, { "name": "Authorization", "value": "={{'Bearer ' + $env.LITELLM_API_KEY}}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"model\": \"medium\",\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a helpful knowledge base assistant. Answer the user's question using ONLY the provided context. If the context doesn't contain enough information, say so. Cite which source numbers you used.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"Context:\\n{{ $json.context }}\\n\\nQuestion: {{ $json.query }}\"\n }\n ],\n \"max_tokens\": 500,\n \"temperature\": 0.2\n}", "options": {} }, "id": "e1360454-8457-40ce-b179-670c182da59e", "name": "LiteLLM Answer", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 880, 304 ] }, { "parameters": { "jsCode": "const response = $input.first().json;\nconst contextData = $('Build Context').first().json;\n\nreturn [{\n json: {\n answer: response.choices?.[0]?.message?.content || 'No answer generated',\n sources: contextData.sources,\n query: contextData.query\n }\n}];" }, "id": "fe16d3a1-0d11-442f-b941-56fb74804601", "name": "Format Response", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1104, 304 ] } ], "connections": { "Ingest Webhook": { "main": [ [ { "node": "Chunk Text", "type": "main", "index": 0 } ] ] }, "Chunk Text": { "main": [ [ { "node": "Get Embedding", "type": "main", "index": 0 } ] ] }, "Get Embedding": { "main": [ [ { "node": "Prepare Qdrant Point", "type": "main", "index": 0 } ] ] }, "Prepare Qdrant Point": { "main": [ [ { "node": "Upsert to Qdrant", "type": "main", "index": 0 } ] ] }, "Query Webhook": { "main": [ [ { "node": "Embed Query", "type": "main", "index": 0 } ] ] }, "Embed Query": { "main": [ [ { "node": "Search Qdrant", "type": "main", "index": 0 } ] ] }, "Search Qdrant": { "main": [ [ { "node": "Build Context", "type": "main", "index": 0 } ] ] }, "Build Context": { "main": [ [ { "node": "LiteLLM Answer", "type": "main", "index": 0 } ] ] }, "LiteLLM Answer": { "main": [ [ { "node": "Format Response", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "staticData": null, "meta": null, "pinData": {}, "versionId": "832248e5-106e-4fc4-8ebd-a5d0034e2b14", "activeVersionId": "832248e5-106e-4fc4-8ebd-a5d0034e2b14", "versionCounter": 14, "triggerCount": 2, "tags": [ { "updatedAt": "2026-05-06T22:38:51.678Z", "createdAt": "2026-05-06T22:38:51.678Z", "id": "S9FxzVfHLsHmyzyt", "name": "ai" }, { "updatedAt": "2026-05-06T22:39:33.284Z", "createdAt": "2026-05-06T22:39:33.284Z", "id": "7uuEyQrIlcuruZBk", "name": "rag" } ], "shared": [ { "updatedAt": "2026-05-06T23:25:29.005Z", "createdAt": "2026-05-06T23:25:29.005Z", "role": "workflow:owner", "workflowId": "gYyOggC4J98keLbj", "projectId": "dxCRnBdX5uJizCGa", "project": { "updatedAt": "2026-05-06T01:10:37.484Z", "createdAt": "2026-05-06T01:08:07.721Z", "id": "dxCRnBdX5uJizCGa", "name": "Wilfred Fizzlepoof ", "type": "personal", "icon": null, "description": null, "creatorId": "47b2227f-2fc2-4a08-bd35-ea157b92df0d" } } ], "versionMetadata": { "name": "Version 832248e5", "description": "" } }