AutomationFlowsAI & RAG › LLM Chat Sqls

LLM Chat Sqls

Llm-Chat-Sqls. Uses agent, memoryManager, crypto, postgres. Webhook trigger; 52 nodes.

Webhook trigger★★★★★ complexityAI-powered52 nodesAgentMemory ManagerCryptoPostgresMemory Postgres ChatLm Chat Azure Open AiVector Store Azure AisearchDocument Default Data Loader
AI & RAG Trigger: Webhook Nodes: 52 Complexity: ★★★★★ AI nodes: yes Added:

This workflow follows the Agent → Documentdefaultdataloader 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 →

Download .json
{
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $('Chat').item.json.body.chatInput }}",
        "options": {
          "systemMessage": "Voc\u00ea \u00e9 um assistente virtual prestativo. IMPORTANTE: Nunca inclua no seu texto ou na mem\u00f3ria de chat os logs internos de chamadas de ferramentas, IDs de execu\u00e7\u00e3o ou frases como 'Calling Azure AI Search'. Retorne \u00fanica e exclusivamente a resposta final formatada, amig\u00e1vel e direta para o usu\u00e1rio humano.",
          "passthroughBinaryImages": true
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3,
      "position": [
        1728,
        896
      ],
      "id": "97f28b37-3ec9-46f1-a56e-9667d3c0eaea",
      "name": "AI Agent",
      "executeOnce": true
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "624b3b7a-6a7c-423e-9e60-418969715811",
              "name": "output",
              "value": "={{ $('AI Agent').item.json.output }}",
              "type": "string"
            },
            {
              "id": "286c4d90-fe38-40ef-90e7-f60310b7fdf2",
              "name": "thread_id",
              "value": "={{ $json.id }}",
              "type": "string"
            },
            {
              "id": "61132193-d114-446c-95fb-20d410e9c464",
              "name": "created_at",
              "value": "={{ $json.created_at }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2288,
        896
      ],
      "id": "63dd5d20-0916-44d5-a2b5-a6059fd8837d",
      "name": "Edit Fields"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "/llmchat/chat",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        400,
        928
      ],
      "id": "88a47026-d241-4bca-8fbc-cdd3f80163bf",
      "name": "Chat"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "/llmchat/auth",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        400,
        352
      ],
      "id": "692204e4-1103-4c09-9f85-f001e02264ce",
      "name": "Auth"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "llmchat/auth/validate-token",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        400,
        656
      ],
      "id": "bdde5e3d-e495-4dee-9e74-e3f3edfb7e60",
      "name": "Valida Token",
      "executeOnce": true
    },
    {
      "parameters": {
        "jsCode": "// Pega o header Authorization enviado pelo React\nconst authHeader = $input.first().json.headers.authorization;\n\nif (!authHeader) {\n  throw new Error('Header Authorization n\u00e3o encontrado');\n}\n\n// Remove o prefixo \"Bearer \" para pegar s\u00f3 o hash\nconst tokenRecebido = authHeader.replace('Bearer ', '').trim();\n\ntry {\n  // 1. Decodifica Base64 para String (Simulando a verifica\u00e7\u00e3o de assinatura)\n  // No Node.js do n8n, usamos Buffer em vez de atob()\n  const jsonString = Buffer.from(tokenRecebido, 'base64').toString('utf-8');\n  \n  // 2. Transforma em Objeto JSON\n  const payload = JSON.parse(jsonString);\n\n  // 3. Verifica Expira\u00e7\u00e3o (Timestamp atual em segundos vs payload.exp)\n  const agora = Math.floor(Date.now() / 1000);\n  \n  if (payload.exp < agora) {\n    // Se o token venceu, retornamos valid: false\n    return {\n      json: {\n        valid: false,\n        message: 'Token expirado'\n      }\n    };\n  }\n\n  // 4. Se chegou aqui, \u00e9 v\u00e1lido! Retornamos os dados do usu\u00e1rio para o front\n  return {\n    json: {\n      valid: true,\n      user: {\n        //id: payload.sub,\n        email: payload.email,\n        name: payload.name\n      }\n    }\n  };\n\n} catch (error) {\n  // Se o token for lixo ou mal formatado, cai aqui\n  return {\n    json: {\n      valid: false,\n      message: 'Token inv\u00e1lido ou mal formatado'\n    }\n  };\n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        608,
        656
      ],
      "id": "889c85a0-6fd5-45e8-81cb-d6ff05576a7a",
      "name": "Verifica Token"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"valid\": \"{{ $json.valid }}\"\n}",
        "options": {
          "responseCode": "={{ $json.valid ? 200 : 401 }}"
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        816,
        656
      ],
      "id": "b30323aa-33ce-46b0-842e-92b7f45c136b",
      "name": "Retorna Validacao"
    },
    {
      "parameters": {
        "options": {
          "groupMessages": true
        }
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        608,
        1808
      ],
      "id": "e1f69393-9c89-4c56-98e9-7f1fed2931fc",
      "name": "Chat Memory Manager"
    },
    {
      "parameters": {
        "action": "generate",
        "dataPropertyName": "=thread_id"
      },
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        1456,
        992
      ],
      "id": "3a0c2651-a0c9-43bb-a991-14486b7f2663",
      "name": "Crypto"
    },
    {
      "parameters": {
        "jsCode": "// Acessa o primeiro item de entrada para extrair headers e dados bin\u00e1rios\nconst inputItem = $input.first();\nconst authHeader = inputItem.json.headers.authorization;\n\nif (!authHeader) {\n  throw new Error('Header Authorization n\u00e3o encontrado');\n}\n\n// Remove o prefixo \"Bearer \" para pegar s\u00f3 o hash\nconst tokenRecebido = authHeader.replace('Bearer ', '').trim();\n\ntry {\n  // ... Sua l\u00f3gica de decodifica\u00e7\u00e3o e valida\u00e7\u00e3o do token ...\n  const jsonString = Buffer.from(tokenRecebido, 'base64').toString('utf-8');\n  const payload = JSON.parse(jsonString);\n  const agora = Math.floor(Date.now() / 1000);\n\n  let outputJson;\n\n  if (payload.exp < agora) {\n    outputJson = {\n      valid: false,\n      message: 'Token expirado'\n    };\n  } else {\n    outputJson = {\n      valid: true,\n      user: {\n        id: payload.sub,\n        email: payload.email,\n        name: payload.name\n      }\n    };\n  }\n\n  // --- PARTE CRUCIAL PARA BIN\u00c1RIOS ---\n  // Cria o objeto de retorno.\n  const outputItem = {\n    json: outputJson\n  };\n\n  // Se o item de entrada possu\u00eda dados bin\u00e1rios, anexe-os ao item de sa\u00edda.\n  if (inputItem.binary) {\n    outputItem.binary = inputItem.binary;\n  }\n  // ------------------------------------\n\n  return [outputItem]; // Retorna um array contendo o item modificado\n\n} catch (error) {\n  // ... Sua l\u00f3gica de erro ...\n  const outputItem = {\n    json: {\n      valid: false,\n      message: 'Token inv\u00e1lido ou mal formatado'\n    }\n  };\n  \n  // No caso de erro, voc\u00ea tamb\u00e9m pode optar por propagar o bin\u00e1rio ou n\u00e3o.\n  // Se quiser propagar, adicione a mesma l\u00f3gica de 'if (inputItem.binary)'.\n\n  return [outputItem];\n}\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        608,
        928
      ],
      "id": "19b943e5-4761-4ef8-8137-d2b0970b2c56",
      "name": "Verifica Token1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "6b50c317-ce4b-475d-aef4-504c77d8153c",
              "leftValue": "={{ $json.valid }}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        816,
        928
      ],
      "id": "eb065d25-1ea2-41df-ab60-8dfa4ac2a404",
      "name": "token v\u00e1lido?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "0e13063a-1e68-450b-b35b-658ba3beeae4",
              "name": "user.id",
              "value": "={{ $json.user.id }}",
              "type": "string"
            },
            {
              "id": "1caf328e-baa6-442b-8587-a6d38b34a8ce",
              "name": "user.email",
              "value": "={{ $json.user.email }}",
              "type": "string"
            },
            {
              "id": "f08d74ef-0160-4318-adde-3d6ec7a3a427",
              "name": "user.name",
              "value": "={{ $json.user.name }}",
              "type": "string"
            },
            {
              "id": "ba23d850-cb13-4dee-914a-ddf8d0ca2396",
              "name": "body.chatInput",
              "value": "={{ $('Chat').item.json.body.chatInput }}",
              "type": "string"
            },
            {
              "id": "188713f2-2c64-42d3-a0bb-52d86e07f373",
              "name": "body.thread_id",
              "value": "={{ $('Chat').item.json.body.thread_id }}",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {
          "stripBinary": false
        }
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1024,
        912
      ],
      "id": "bbc9e4f1-10c2-4b68-8278-131ee762b3a6",
      "name": "Informacoes"
    },
    {
      "parameters": {
        "jsCode": "// Pega o header Authorization enviado pelo React\nconst authHeader = $input.first().json.headers.authorization;\n\nif (!authHeader) {\n  throw new Error('Header Authorization n\u00e3o encontrado');\n}\n\n// Remove o prefixo \"Bearer \" para pegar s\u00f3 o hash\nconst tokenRecebido = authHeader.replace('Bearer ', '').trim();\n\ntry {\n  // 1. Decodifica Base64 para String (Simulando a verifica\u00e7\u00e3o de assinatura)\n  // No Node.js do n8n, usamos Buffer em vez de atob()\n  const jsonString = Buffer.from(tokenRecebido, 'base64').toString('utf-8');\n  \n  // 2. Transforma em Objeto JSON\n  const payload = JSON.parse(jsonString);\n\n  // 3. Verifica Expira\u00e7\u00e3o (Timestamp atual em segundos vs payload.exp)\n  const agora = Math.floor(Date.now() / 1000);\n  \n  if (payload.exp < agora) {\n    // Se o token venceu, retornamos valid: false\n    return {\n      json: {\n        valid: false,\n        message: 'Token expirado'\n      }\n    };\n  }\n\n  // 4. Se chegou aqui, \u00e9 v\u00e1lido! Retornamos os dados do usu\u00e1rio para o front\n  return {\n    json: {\n      valid: true,\n      user: {\n        id: payload.sub,\n        email: payload.email,\n        name: payload.name\n      }\n    }\n  };\n\n} catch (error) {\n  // Se o token for lixo ou mal formatado, cai aqui\n  return {\n    json: {\n      valid: false,\n      message: 'Token inv\u00e1lido ou mal formatado'\n    }\n  };\n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        592,
        2288
      ],
      "id": "2b8a8b45-2b44-45d1-b2e0-d0e582000d5c",
      "name": "Verifica Token2"
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "include": "specifiedFields",
        "fieldsToInclude": "id, name, created_at",
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        1008,
        2288
      ],
      "id": "cdc93ffc-3fdb-4451-aeca-ca6df1ab2d34",
      "name": "Aggregate"
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "threads",
          "mode": "list",
          "cachedResultName": "threads"
        },
        "where": {
          "values": [
            {
              "column": "user_id",
              "value": "={{ $json.user.id }}"
            }
          ]
        },
        "sort": {
          "values": [
            {
              "column": "created_at",
              "direction": "DESC"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        800,
        2288
      ],
      "id": "0692794f-5c41-46da-becf-c45397b19fe5",
      "name": "Select rows from a table",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "path": "/llmchat/threads/:thread-id",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        400,
        1808
      ],
      "id": "e5c0a31b-017f-46d6-b020-def6f998ceb8",
      "name": "Obter thread"
    },
    {
      "parameters": {
        "path": "/llmchat/threads",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        384,
        2288
      ],
      "id": "33dc6389-aa7e-449d-bd08-4bfa5eb6837c",
      "name": "Obter thread's"
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $json.params['thread-id'] }}"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        624,
        2016
      ],
      "id": "16f4de65-73d4-4be7-b2b1-46105e2fbfa2",
      "name": "Postgres Chat Memory1",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "# Autentica\u00e7\u00e3o",
        "height": 368,
        "width": 1328
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        208
      ],
      "typeVersion": 1,
      "id": "79754682-b64f-4986-9fcf-4fafd09e2aa4",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "# Valida\u00e7\u00e3o",
        "height": 240,
        "width": 1328,
        "color": 3
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        592
      ],
      "typeVersion": 1,
      "id": "d002e87e-5e66-4d8e-9be4-39e02c89abd3",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "# Chat",
        "height": 400,
        "width": 2320,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        848
      ],
      "typeVersion": 1,
      "id": "f15cc3ca-6f51-4e13-9103-40d9001f49a0",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "# Obter Thread",
        "height": 432,
        "width": 1136,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        1712
      ],
      "typeVersion": 1,
      "id": "71c942cd-bac8-429a-bdb0-c5798ba222cd",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "# Obter TODAS Threads do User",
        "height": 352,
        "width": 1136,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        2160
      ],
      "typeVersion": 1,
      "id": "56512777-b944-413a-baed-28da76a092c9",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"message\": \"sucesso!\"\n}",
        "options": {
          "responseCode": 200
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1024,
        -64
      ],
      "id": "73120c56-4de6-4f96-8efa-f46b021da80c",
      "name": "Respond to Webhook5"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"message\": \"Usu\u00e1rio n\u00e3o autenticado\"\n}",
        "options": {
          "responseCode": 401
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1024,
        1056
      ],
      "id": "f043e391-7224-4b87-a8f6-d47695bbb822",
      "name": "Respond unauthenticated user"
    },
    {
      "parameters": {
        "model": "gpt-5-mini",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "typeVersion": 1,
      "position": [
        1600,
        1104
      ],
      "id": "0a951fa3-a840-4c9f-ad60-03140daa9c6f",
      "name": "Azure OpenAI Chat Model1",
      "credentials": {
        "azureOpenAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "email",
              "value": "={{ $json.body.email }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        816,
        352
      ],
      "id": "aed301d0-6e49-4bb6-b571-b4a5295863bc",
      "name": "Get a row",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "# Cadastro de usu\u00e1rio\n ",
        "height": 352,
        "width": 944,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        -160
      ],
      "typeVersion": 1,
      "id": "8d7456f2-4792-46a6-aaae-25815b5d9296",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "users",
          "mode": "list",
          "cachedResultName": "users"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "email": "={{ $json.body.email }}",
            "password_hash": "={{ $json.password_hash }}",
            "name": "={{ $json.body.name }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "email",
              "displayName": "email",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "password_hash",
              "displayName": "password_hash",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "name",
              "displayName": "name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        816,
        -64
      ],
      "id": "2892f89c-ff9b-4e52-bb10-972f36ae7ab5",
      "name": "Insert new user in \"users\" table",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "/user/create",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        400,
        -64
      ],
      "id": "f152f3e5-a0eb-47ff-9a45-1dabdc261c48",
      "name": "New User Webhook"
    },
    {
      "parameters": {
        "type": "SHA3-256",
        "value": "={{ $json.body.password }}",
        "dataPropertyName": "password_hash"
      },
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        608,
        352
      ],
      "id": "36c85098-3c04-4383-8f17-ed9ad5bd846c",
      "name": "Auth password hash"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"message\": \"Usu\u00e1rio ou senha incorretos\"\n}",
        "options": {
          "responseCode": 401
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1232,
        432
      ],
      "id": "a063e6fe-cf5a-46b6-89bd-7b6a854b86f7",
      "name": "Respond incorrect user"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"token\": \"{{ $json.token }}\",\n  \"user\": {\n            \"id\": \"{{ $('Get a row').item.json.id }}\",\n            \"email\": \"{{ $('Get a row').item.json.email }}\", \n            \"name\": \"{{ $('Get a row').item.json.name }}\"\n          }\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1440,
        272
      ],
      "id": "02fa3a4d-b125-4ff7-af20-64267b514b2b",
      "name": "Respond success to Auth"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "d6546914-8f14-4341-9a5b-3d1e3bc4501d",
              "leftValue": "={{ $json.password_hash }}",
              "rightValue": "={{ $('Auth password hash').item.json.password_hash }}",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1024,
        352
      ],
      "id": "4cf2cb09-aa8a-429b-bfd9-e6a27256f227",
      "name": "User found?"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "6653b41a-0d1e-4977-bd2b-736053231a6c",
              "leftValue": "={{ $json.body.thread_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1232,
        912
      ],
      "id": "7dc13c9d-92ca-4292-bc00-c54a6ea6007c",
      "name": "Have thread?"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1216,
        2288
      ],
      "id": "38fea260-f473-4d03-a5eb-799ed711b7e3",
      "name": "Respond with thread list"
    },
    {
      "parameters": {
        "jsCode": "// Este \u00e9 um exemplo simplificado para a palestra.\n// Ele pega os dados do user e timestamp atual e codifica em Base64 para simular um token.\n\nconst payload = {\n  sub: $input.first().json.id,\n  email: $input.first().json.email,\n  name: $input.first().json.name,\n  exp: (Date.now() / 1000) + 7200 // Expira em 2 horas\n};\n\n// Codifica o payload JSON em uma string Base64 para simular o formato JWT\nconst tokenSimulado = btoa(JSON.stringify(payload));\n\n\nreturn [{ json: { token: tokenSimulado } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1232,
        272
      ],
      "id": "184d9965-92a5-47ff-8f02-165684617ea3",
      "name": "Gera token de Auth"
    },
    {
      "parameters": {
        "type": "SHA3-256",
        "value": "={{ $json.body.password }}",
        "dataPropertyName": "password_hash"
      },
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        608,
        -64
      ],
      "id": "89d2b880-07f6-46f7-8a70-d3a763a47f04",
      "name": "Encrypt password"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        2496,
        896
      ],
      "id": "2c5dc397-e0ca-4d77-be70-b612bd4b466c",
      "name": "Chat response"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        944,
        1808
      ],
      "id": "59de7ae6-5c72-4326-9359-cecb8fae4c70",
      "name": "Respond with thread messages"
    },
    {
      "parameters": {
        "mode": "insert",
        "options": {
          "clearIndex": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreAzureAISearch",
      "typeVersion": 1.3,
      "position": [
        1296,
        1360
      ],
      "id": "d9134f8b-2949-4781-83da-7d5fe85cea44",
      "name": "Azure AI Search Vector Store (insert)",
      "credentials": {
        "azureAiSearchApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "=**SEMPRE** use essa tool para consultar informa\u00e7\u00f5es que n\u00e3o souber exatamente.",
        "includeDocumentMetadata": false,
        "options": {
          "queryType": "hybrid",
          "filter": "=metadata/attributes/any(attr: attr/key eq 'user' and attr/value eq '{{ $('Informacoes').item.json.user.id }}')"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreAzureAISearch",
      "typeVersion": 1.3,
      "position": [
        1856,
        1104
      ],
      "id": "82f91855-3ec6-425d-9fb2-7109b4081ba9",
      "name": "Azure AI Search Vector Store (Retrieve)",
      "rewireOutputLogTo": "ai_tool",
      "credentials": {
        "azureAiSearchApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "dataType": "binary",
        "binaryMode": "specificField",
        "binaryDataKey": "file",
        "options": {
          "metadata": {
            "metadataValues": [
              {
                "name": "user",
                "value": "={{ $json.user.id }}"
              }
            ]
          }
        }
      },
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "typeVersion": 1.1,
      "position": [
        1344,
        1552
      ],
      "id": "10ebce81-8299-4c39-9b2d-e3e16bb7b5d5",
      "name": "Default Data Loader"
    },
    {
      "parameters": {
        "model": "text-embedding-3-small",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsAzureOpenAi",
      "typeVersion": 1,
      "position": [
        1856,
        1472
      ],
      "id": "b4b133d9-b2c9-4ab2-8f41-378cd76e852a",
      "name": "Embeddings Azure OpenAI",
      "credentials": {
        "azureOpenAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Acessa o primeiro item de entrada para extrair headers e dados bin\u00e1rios\nconst inputItem = $input.first();\nconst authHeader = inputItem.json.headers.authorization;\n\nif (!authHeader) {\n  throw new Error('Header Authorization n\u00e3o encontrado');\n}\n\n// Remove o prefixo \"Bearer \" para pegar s\u00f3 o hash\nconst tokenRecebido = authHeader.replace('Bearer ', '').trim();\n\ntry {\n  // ... Sua l\u00f3gica de decodifica\u00e7\u00e3o e valida\u00e7\u00e3o do token ...\n  const jsonString = Buffer.from(tokenRecebido, 'base64').toString('utf-8');\n  const payload = JSON.parse(jsonString);\n  const agora = Math.floor(Date.now() / 1000);\n\n  let outputJson;\n\n  if (payload.exp < agora) {\n    outputJson = {\n      valid: false,\n      message: 'Token expirado'\n    };\n  } else {\n    outputJson = {\n      valid: true,\n      user: {\n        id: payload.sub,\n        email: payload.email,\n        name: payload.name\n      }\n    };\n  }\n\n  // --- PARTE CRUCIAL PARA BIN\u00c1RIOS ---\n  // Cria o objeto de retorno.\n  const outputItem = {\n    json: outputJson\n  };\n\n  // Se o item de entrada possu\u00eda dados bin\u00e1rios, anexe-os ao item de sa\u00edda.\n  if (inputItem.binary) {\n    outputItem.binary = inputItem.binary;\n  }\n  // ------------------------------------\n\n  return [outputItem]; // Retorna um array contendo o item modificado\n\n} catch (error) {\n  // ... Sua l\u00f3gica de erro ...\n  const outputItem = {\n    json: {\n      valid: false,\n      message: 'Token inv\u00e1lido ou mal formatado'\n    }\n  };\n  \n  // No caso de erro, voc\u00ea tamb\u00e9m pode optar por propagar o bin\u00e1rio ou n\u00e3o.\n  // Se quiser propagar, adicione a mesma l\u00f3gica de 'if (inputItem.binary)'.\n\n  return [outputItem];\n}\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        608,
        1376
      ],
      "id": "451de4fa-211b-4c8d-a776-6bf1710f3338",
      "name": "Verifica Token3"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "/llmchat/rag/",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        400,
        1376
      ],
      "id": "e524ef83-e1cf-4241-8f70-187b94b29c63",
      "name": "Webhook1"
    },
    {
      "parameters": {
        "content": "# Inser\u00e7\u00e3o RAG\n",
        "height": 432,
        "width": 1776,
        "color": 2
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        1264
      ],
      "typeVersion": 1,
      "id": "b4dd257f-e3cb-4f92-a488-3644741257b4",
      "name": "Sticky Note6"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "6b50c317-ce4b-475d-aef4-504c77d8153c",
              "leftValue": "={{ $json.valid }}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        816,
        1376
      ],
      "id": "f2e9d2ac-008e-4b91-8da0-0c75880fdabc",
      "name": "token v\u00e1lido?1"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"message\": \"Usu\u00e1rio n\u00e3o autenticado\"\n}",
        "options": {
          "responseCode": 401
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1024,
        1520
      ],
      "id": "98149bda-da77-4d05-80e4-1b9a484e0725",
      "name": "Respond unauthenticated user1"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1648,
        1360
      ],
      "id": "d9da1831-4bcd-48d7-9828-ca46d07e57fa",
      "name": "Upload response"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "table": {
          "__rl": true,
          "value": "threads",
          "mode": "list",
          "cachedResultName": "threads"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "user_id": "={{ $('Informacoes').item.json.user.id }}",
            "id": "={{ $('Informacoes').item.json.body.thread_id || $('Crypto').item.json.thread_id }}",
            "name": "={{ $('Informacoes').item.json.body.chatInput }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "name",
              "displayName": "name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "skipOnConflict": true
        }
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        2080,
        896
      ],
      "id": "3170baeb-b6d7-4452-8740-84c581076955",
      "name": "add new thread  in \"threads\" table",
      "executeOnce": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $json.thread_id || $json.body.thread_id }}",
        "contextWindowLength": 10
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        1744,
        1104
      ],
      "id": "8b46a209-ebd3-4b18-8eaf-8c9932cb44c1",
      "name": "Postgres Chat Memory",
      "executeOnce": false,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "add new thread  in \"threads\" table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Chat response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat": {
      "main": [
        [
          {
            "node": "Verifica Token1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Auth": {
      "main": [
        [
          {
            "node": "Auth password hash",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Valida Token": {
      "main": [
        [
          {
            "node": "Verifica Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verifica Token": {
      "main": [
        [
          {
            "node": "Retorna Validacao",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Memory Manager": {
      "main": [
        [
          {
            "node": "Respond with thread messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Crypto": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verifica Token1": {
      "main": [
        [
          {
            "node": "token v\u00e1lido?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "token v\u00e1lido?": {
      "main": [
        [
          {
            "node": "Informacoes",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond unauthenticated user",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Informacoes": {
      "main": [
        [
          {
            "node": "Have thread?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verifica Token2": {
      "main": [
        [
          {
            "node": "Select rows from a table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "Respond with thread list",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select rows from a table": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obter thread": {
      "main": [
        [
          {
            "node": "Chat Memory Manager",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obter thread's": {
      "main": [
        [
          {
            "node": "Verifica Token2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory1": {
      "ai_memory": [
        [
          {
            "node": "Chat Memory Manager",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Azure OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Get a row": {
      "main": [
        [
          {
            "node": "User found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert new user in \"users\" table": {
      "main": [
        [
          {
            "node": "Respond to Webhook5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New User Webhook": {
      "main": [
        [
          {
            "node": "Encrypt password",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Auth password hash": {
      "main": [
        [
          {
            "node": "Get a row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "User found?": {
      "main": [
        [
          {
            "node": "Gera token de Auth",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond incorrect user",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Have thread?": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Crypto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gera token de Auth": {
      "main": [
        [
          {
            "node": "Respond success to Auth",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Encrypt password": {
      "main": [
        [
          {
            "node": "Insert new user in \"users\" table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Azure AI Search Vector Store (insert)": {
      "main": [
        [
          {
            "node": "Upload response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Azure AI Search Vector Store (Retrieve)": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Default Data Loader": {
      "ai_document": [
        [
          {
            "node": "Azure AI Search Vector Store (insert)",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings Azure OpenAI": {
      "ai_embedding": [
        [
          {
            "node": "Azure AI Search Vector Store (Retrieve)",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "Azure AI Search Vector Store (insert)",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Verifica Token3": {
      "main": [
        [
          {
            "node": "token v\u00e1lido?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook1": {
      "main": [
        [
          {
            "node": "Verifica Token3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "token v\u00e1lido?1": {
      "main": [
        [
          {
            "node": "Azure AI Search Vector Store (insert)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond unauthenticated user1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "add new thread  in \"threads\" table": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Llm-Chat-Sqls. Uses agent, memoryManager, crypto, postgres. Webhook trigger; 52 nodes.

Source: https://github.com/talleswp/n8n-llm-chat-tester/blob/fd920d7bc9c440b56b2c399e6422840327bafd69/fluxo_n8n/llm-chat-SQLS.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Camila IA. Uses postgres, crypto, redis, agent. Webhook trigger; 92 nodes.

Postgres, Crypto, Redis +13
AI & RAG

Hi! I’m Amanda, a creator of intelligent automations using n8n and Make. I’ve been building AI-powered workflows for over 2 years, always focused on usability and innovation. This one here is very spe

OpenAI Chat, Redis, OpenAI +11
AI & RAG

AI Multi-Document Analyzer with Smart Recommendations & Reporting

Crypto, Agent, OpenAI Chat +8
AI & RAG

V3 Local Agentic RAG AI Agent. Uses documentDefaultDataLoader, memoryPostgresChat, chatTrigger, agent. Webhook trigger; 41 nodes.

Document Default Data Loader, Memory Postgres Chat, Chat Trigger +9
AI & RAG

Author: Jadai kongolo

Document Default Data Loader, Memory Postgres Chat, Chat Trigger +9