{
  "name": "Nodbot - Qdrant RAG FAQ bot",
  "nodes": [
    {
      "parameters": {
        "path": "qdrant-rag-faq-bot",
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "id": "9a6f0ebc-f3df-483a-ab0b-dac0e746777c",
      "name": "Webhook question",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        260
      ]
    },
    {
      "parameters": {
        "jsCode": "const src = $json.body ?? $json;\nconst question = String(src.question ?? '').replace(/\\s+/g, ' ').trim();\nif (question.length < 8) throw new Error('Question is too short for RAG search');\nif (question.length > 1200) throw new Error('Question is too long: ask user to shorten it');\n\nconst topK = Math.min(Number(src.top_k ?? 5), 8);\nconst filters = src.filters ?? {};\nconst qdrantFilter = { must: [] };\nfor (const [key, value] of Object.entries(filters)) {\n  if (value) qdrantFilter.must.push({ key, match: { value } });\n}\n\nconst systemGuard = [\n  'Отвечай только по контексту из найденных источников.',\n  'Если ответа нет в контексте, скажи: \"В базе знаний нет точного ответа\".',\n  'Не придумывай тарифы, сроки, ссылки и команды.',\n  'В конце укажи source_ids использованных фрагментов.'\n].join(' ');\n\nreturn [{\n  json: {\n    question,\n    top_k: topK,\n    qdrant_search: { limit: topK, with_payload: true, filter: qdrantFilter },\n    system_guard: systemGuard,\n    audit_key: `qdrant-rag:${src.user_id ?? 'anon'}:${Date.now()}`,\n    min_score: Number(src.min_score ?? 0.72)\n  }\n}];"
      },
      "id": "5296045d-2806-4d31-b7e5-13189dd66874",
      "name": "Normalize query",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        260
      ]
    },
    {
      "parameters": {},
      "id": "eea2cb96-cddb-4887-b055-a9edacab14c9",
      "name": "Create embedding",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        560,
        260
      ]
    },
    {
      "parameters": {},
      "id": "674b20fe-8334-4ab8-a304-882e0f6df47f",
      "name": "Search Qdrant points",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        840,
        260
      ]
    },
    {
      "parameters": {
        "jsCode": "const src = $json.body ?? $json;\nconst question = String(src.question ?? '').replace(/\\s+/g, ' ').trim();\nif (question.length < 8) throw new Error('Question is too short for RAG search');\nif (question.length > 1200) throw new Error('Question is too long: ask user to shorten it');\n\nconst topK = Math.min(Number(src.top_k ?? 5), 8);\nconst filters = src.filters ?? {};\nconst qdrantFilter = { must: [] };\nfor (const [key, value] of Object.entries(filters)) {\n  if (value) qdrantFilter.must.push({ key, match: { value } });\n}\n\nconst systemGuard = [\n  'Отвечай только по контексту из найденных источников.',\n  'Если ответа нет в контексте, скажи: \"В базе знаний нет точного ответа\".',\n  'Не придумывай тарифы, сроки, ссылки и команды.',\n  'В конце укажи source_ids использованных фрагментов.'\n].join(' ');\n\nreturn [{\n  json: {\n    question,\n    top_k: topK,\n    qdrant_search: { limit: topK, with_payload: true, filter: qdrantFilter },\n    system_guard: systemGuard,\n    audit_key: `qdrant-rag:${src.user_id ?? 'anon'}:${Date.now()}`,\n    min_score: Number(src.min_score ?? 0.72)\n  }\n}];"
      },
      "id": "edd43cdb-fd75-428d-b818-8ca5c66387fd",
      "name": "Build grounded prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        260
      ]
    },
    {
      "parameters": {},
      "id": "750c842c-29c7-4165-9155-28d1142fd54a",
      "name": "Respond or human review",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 2,
      "position": [
        1400,
        260
      ]
    }
  ],
  "connections": {
    "Webhook question": {
      "main": [
        [
          {
            "node": "Normalize query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize query": {
      "main": [
        [
          {
            "node": "Create embedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create embedding": {
      "main": [
        [
          {
            "node": "Search Qdrant points",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Qdrant points": {
      "main": [
        [
          {
            "node": "Build grounded prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build grounded prompt": {
      "main": [
        [
          {
            "node": "Respond or human review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    "nodbot",
    "production",
    "template"
  ],
  "triggerCount": 1,
  "updatedAt": "2026-05-30T00:00:00.000Z",
  "versionId": "f5d978be-b27b-4110-a028-3764737cb4e7",
  "meta": {
    "templateCredsSetupCompleted": false
  }
}