This workflow follows the Agent → HTTP Request recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Polish AI RAG - Direct Qdrant (NO HF Space)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "rag-agent",
"responseMode": "lastNode",
"options": {}
},
"id": "webhook-1",
"name": "Webhook: RAG Question",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
240,
300
]
},
{
"parameters": {
"model": "anthropic/claude-3.5-sonnet",
"options": {
"baseURL": "https://openrouter.ai/api/v1",
"temperature": 0.3
}
},
"id": "openrouter-analyze",
"name": "OpenRouter: Analyze Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [
560,
420
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"description": "Analyzes the user question and determines optimal top_k value (10-15)",
"jsCode": "const question = $fromAI('question', 'User question', 'string');\nconst lowerQ = question.toLowerCase();\nconst result = { query: question, top_k: 10 };\nif (lowerQ.includes('szczeg\u00f3\u0142') || lowerQ.includes('jak')) result.top_k = 15;\nelse if (lowerQ.includes('przyk\u0142ad')) result.top_k = 12;\nreturn JSON.stringify(result, null, 2);"
},
"id": "code-tool-params",
"name": "Code Tool: Build Parameters",
"type": "@n8n/n8n-nodes-langchain.toolCode",
"typeVersion": 1.3,
"position": [
680,
420
]
},
{
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"query\": {\"type\": \"string\"},\n \"top_k\": {\"type\": \"number\"}\n },\n \"required\": [\"query\", \"top_k\"]\n}"
},
"id": "output-parser",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"typeVersion": 1.3,
"position": [
800,
420
]
},
{
"parameters": {
"promptType": "define",
"text": "={{ $json.body.question }}",
"hasOutputParser": true,
"options": {
"systemMessage": "Jeste\u015b ekspertem analizy zapyta\u0144 u\u017cytkownik\u00f3w dla systemu RAG. Przeanalizuj pytanie i u\u017cyj narz\u0119dzia Build Parameters aby okre\u015bli\u0107 liczb\u0119 wynik\u00f3w (top_k: 10-15). Zwr\u00f3\u0107 JSON z query i top_k."
}
},
"id": "agent-analyze",
"name": "AI Agent: Analyze Question",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
480,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://router.huggingface.co/models/nomic-ai/nomic-embed-text-v1.5",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ \"Bearer \" + $env.HF_API_TOKEN }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"inputs\": \"search_query: \" + $json.output.query } }}",
"options": {
"response": {
"response": {
"neverError": true
}
},
"timeout": 30000
}
},
"id": "http-embedding",
"name": "HTTP: Generate Embedding",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
720,
300
]
},
{
"parameters": {
"jsCode": "// Przygotuj query dla Qdrant API\nconst embedding = $input.item.json;\nconst params = $('AI Agent: Analyze Question').item.json.output;\n\n// HF API zwraca embedding jako array lub nested array\nconst vector = Array.isArray(embedding[0]) ? embedding[0] : embedding;\n\n// Buduj Qdrant search request\nconst qdrantQuery = {\n vector: {\n name: \"dense\",\n vector: vector\n },\n limit: params.top_k || 10,\n with_payload: true,\n score_threshold: 0.5\n};\n\nreturn {\n json: {\n qdrantQuery,\n originalQuestion: $('Webhook: RAG Question').item.json.body.question,\n top_k: params.top_k\n }\n};"
},
"id": "code-prepare-qdrant",
"name": "Code: Prepare Qdrant Query",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
960,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.QDRANT_URL }}/collections/wordpress_articles/points/search",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api-key",
"value": "={{ $env.QDRANT_API_KEY }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ $json.qdrantQuery }}",
"options": {
"response": {
"response": {
"neverError": true
}
},
"timeout": 60000
}
},
"id": "http-qdrant",
"name": "HTTP: Qdrant Search",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1200,
300
]
},
{
"parameters": {
"jsCode": "// Format Qdrant results do formatu dla LLM\nconst response = $input.item.json;\nconst originalQuestion = $('Code: Prepare Qdrant Query').item.json.originalQuestion;\n\n// Sprawd\u017a czy s\u0105 wyniki\nif (!response || !response.result || response.result.length === 0) {\n return {\n json: {\n context: 'Brak wynik\u00f3w. System RAG nie znalaz\u0142 odpowiednich artyku\u0142\u00f3w.',\n hasResults: false,\n resultCount: 0,\n results: [],\n originalQuestion\n }\n };\n}\n\nconst results = response.result;\n\n// Buduj formatowany kontekst\nlet context = `Znaleziono ${results.length} wynik\u00f3w z bazy wiedzy:\\n\\n`;\n\nconst formattedResults = [];\n\nresults.forEach((hit, index) => {\n const payload = hit.payload || {};\n \n context += `--- Wynik ${index + 1} (Score: ${(hit.score * 100).toFixed(1)}%) ---\\n`;\n context += `Tytu\u0142: ${payload.title || 'Brak tytu\u0142u'}\\n`;\n context += `URL: ${payload.url || ''}\\n`;\n context += `Typ sekcji: ${payload.section_type || 'content'}\\n`;\n \n if (payload.publication_date) {\n context += `Data publikacji: ${payload.publication_date}\\n`;\n }\n \n if (payload.tags && payload.tags.length > 0) {\n context += `Tagi: ${payload.tags.join(', ')}\\n`;\n }\n \n if (payload.categories && payload.categories.length > 0) {\n context += `Kategorie: ${payload.categories.join(', ')}\\n`;\n }\n \n context += `\\nTre\u015b\u0107:\\n${payload.text || ''}\\n\\n`;\n \n // Zapisz dla sources array\n formattedResults.push({\n title: payload.title || 'Brak tytu\u0142u',\n url: payload.url || '',\n score: hit.score,\n text: payload.text || '',\n section_type: payload.section_type || 'content'\n });\n});\n\nreturn {\n json: {\n context,\n hasResults: true,\n resultCount: results.length,\n results: formattedResults,\n originalQuestion\n }\n};"
},
"id": "code-format-results",
"name": "Code: Format Qdrant Results",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1440,
300
]
},
{
"parameters": {
"model": "anthropic/claude-3.5-sonnet",
"options": {
"baseURL": "https://openrouter.ai/api/v1",
"temperature": 0.5
}
},
"id": "openrouter-answer",
"name": "OpenRouter: Answer Generator",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [
1800,
420
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"promptType": "define",
"text": "={{ $('Code: Format Qdrant Results').item.json.originalQuestion }}",
"options": {
"systemMessage": "Jeste\u015b pomocnym asystentem AI, kt\u00f3ry odpowiada na pytania u\u017cytkownik\u00f3w w j\u0119zyku polskim na podstawie kontekstu z bazy wiedzy RAG.\\n\\n=== PYTANIE U\u017bYTKOWNIKA ===\\n{{ $('Code: Format Qdrant Results').item.json.originalQuestion }}\\n\\n=== KONTEKST Z BAZY WIEDZY ===\\n{{ $('Code: Format Qdrant Results').item.json.context }}\\n\\n=== INSTRUKCJE ===\\n1. Odpowiedz zwi\u0119\u017ale i konkretnie w j\u0119zyku polskim\\n2. Bazuj TYLKO na dostarczonym kontek\u015bcie\\n3. Cytuj \u017ar\u00f3d\u0142a - podawaj tytu\u0142y artyku\u0142\u00f3w i linki\\n4. Uwzgl\u0119dnij score i daty publikacji\\n5. Je\u015bli brak odpowiedzi, powiedz wprost i zasugeruj przeformu\u0142owanie\\n6. U\u017cywaj formatowania markdown\\n7. Wyr\u00f3\u017cnij checklisty i key insights\\n\\nOdpowiedz teraz:"
}
},
"id": "agent-answer",
"name": "AI Agent: Generate Answer",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
1680,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ {\n \"question\": $('Code: Format Qdrant Results').item.json.originalQuestion,\n \"answer\": $json.output,\n \"sources\": $('Code: Format Qdrant Results').item.json.results.map(r => ({\"title\": r.title, \"url\": r.url, \"score\": r.score})),\n \"sources_count\": $('Code: Format Qdrant Results').item.json.resultCount,\n \"has_results\": $('Code: Format Qdrant Results').item.json.hasResults\n} }}",
"options": {}
},
"id": "respond",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
1920,
300
]
}
],
"connections": {
"Webhook: RAG Question": {
"main": [
[
{
"node": "AI Agent: Analyze Question",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter: Analyze Model": {
"ai_languageModel": [
[
{
"node": "AI Agent: Analyze Question",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Code Tool: Build Parameters": {
"ai_tool": [
[
{
"node": "AI Agent: Analyze Question",
"type": "ai_tool",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "AI Agent: Analyze Question",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"AI Agent: Analyze Question": {
"main": [
[
{
"node": "HTTP: Generate Embedding",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Generate Embedding": {
"main": [
[
{
"node": "Code: Prepare Qdrant Query",
"type": "main",
"index": 0
}
]
]
},
"Code: Prepare Qdrant Query": {
"main": [
[
{
"node": "HTTP: Qdrant Search",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Qdrant Search": {
"main": [
[
{
"node": "Code: Format Qdrant Results",
"type": "main",
"index": 0
}
]
]
},
"Code: Format Qdrant Results": {
"main": [
[
{
"node": "AI Agent: Generate Answer",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter: Answer Generator": {
"ai_languageModel": [
[
{
"node": "AI Agent: Generate Answer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Agent: Generate Answer": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "direct-qdrant-v1"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Polish AI RAG - Direct Qdrant (NO HF Space). Uses lmChatOpenAi, toolCode, outputParserStructured, agent. Webhook trigger; 12 nodes.
Source: https://github.com/a-michalski/wordpress-rag/blob/87141bd131e299f2b80489e37b71036c6922550a/n8n_workflow_direct_qdrant.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Alfred (funcional). Uses gmailTool, googleCalendarTool, gmail, embeddingsOpenAi. Event-driven trigger; 83 nodes.
Turn unstructured pitch decks and investment memos into polished Due Diligence PDF reports automatically. This n8n workflow handles everything from document ingestion to final delivery, combining inte
Transform raw investment memorandums and financial decks into comprehensive, professional Due Diligence (DD) PDF reports. This workflow automates document parsing via LlamaParse, enriches internal dat
AI Multi-Document Analyzer with Smart Recommendations & Reporting
This workflow automates business intelligence reporting by aggregating data from multiple sources, processing it through AI models, and delivering formatted dashboards via email. Designed for business