La Casa de Aurelio / Resources
Video resources: Como crear un Agente de IA con n8n + Telegram + Supabase (10 min)
Resources for the Spanish tutorial: a Telegram bot connected to an LLM, deployed on Railway, and using Supabase as a vector base for document context.
Welcome to La Casa de Aurelio.
This post includes the files from the tutorial for building a Telegram bot connected to an LLM, deployed on Railway, and backed by Supabase vector search.
System idea
- Upload files or text.
- The content is vectorized and stored in Supabase.
- The agent uses that information as memory.
- You message it through Telegram.
- The bot answers using the context from your own documents.
Resources included
- Workflow JSON to import into n8n.
- SQL to create the Supabase table.
- Base structure for connecting Telegram, LLM, Railway, and Supabase.
How to use it
- Open SQL Editor in Supabase.
- Paste the SQL below and run it.
- Import the workflow JSON in n8n.
- Connect your credentials: Telegram, Supabase, LLM/API, and Railway.
- Test with a small document before loading more information.
Important
Do not share API keys, Telegram tokens, or service role keys publicly. The downloadable workflow is sanitized: it does not include credentials or webhook IDs from the original environment.
Supabase SQL
-- Extension
CREATE EXTENSION IF NOT EXISTS vector;
-- Tabla
CREATE TABLE documentos_negocio (
id BIGSERIAL PRIMARY KEY,
content TEXT,
metadata JSONB,
embedding VECTOR(1536)
);
-- Funcion con el nombre que espera n8n
CREATE OR REPLACE FUNCTION match_documents(
query_embedding VECTOR(1536),
match_count INT DEFAULT 5,
filter JSONB DEFAULT '{}'
)
RETURNS TABLE (
id BIGINT,
content TEXT,
metadata JSONB,
similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
documentos_negocio.id,
documentos_negocio.content,
documentos_negocio.metadata,
1 - (documentos_negocio.embedding <=> query_embedding) AS similarity
FROM documentos_negocio
ORDER BY documentos_negocio.embedding <=> query_embedding
LIMIT match_count;
END;
$$;
n8n workflow JSON
Import this JSON into n8n and reconnect every credential before activating the workflow.
{
"nodes": [
{
"parameters": {
"formTitle": "Upload your data to test RAG",
"formFields": {
"values": [
{
"fieldLabel": "Upload your file(s)",
"fieldType": "file",
"acceptFileTypes": ".pdf, .csv",
"requiredField": true
}
]
},
"options": {}
},
"type": "n8n-nodes-base.formTrigger",
"typeVersion": 2.2,
"position": [
3488,
1520
],
"id": "39ac0897-e878-4e87-a433-a89ef5e8c20c",
"name": "Upload your file here"
},
{
"parameters": {
"mode": "insert",
"tableName": {
"__rl": true,
"value": "documentos_negocio",
"mode": "list",
"cachedResultName": "documentos_negocio"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"typeVersion": 1.3,
"position": [
3664,
1520
],
"id": "8ec98120-fdcc-4a89-ba32-268c257238ca",
"name": "Supabase Vector Store"
},
{
"parameters": {
"jsCode": "const raw = $json.output || $json.respuesta || \"\";\n\nlet clean;\ntry {\n clean = raw\n // 0. Limpiar pre-escapado que viene del agente\n .replace(/\\\\\\\\/g, '\\\\')\n .replace(/\\\\\"/g, '\"')\n // 1. Viñetas a guiones\n .replace(/^\\*\\s+/gm, '- ')\n // 2. **negrita** → *negrita* (antes de escapar)\n .replace(/\\*\\*(.*?)\\*\\*/g, '*$1*')\n // 3. Escapar especiales para MarkdownV2 (excepto * que ya está formateado)\n .replace(/([_[\\]()~`>#+\\-=|{}.!\\\\])/g, '\\\\$1');\n} catch (e) {\n clean = \"Lo siento, hubo un error procesando la respuesta\\\\.\";\n}\n\nreturn [{ json: { output: clean } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3936,
1152
],
"id": "9e8cb775-d149-4ddd-8656-f0b0c4c85f6d",
"name": "formateo"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $json.message.text }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"id": "864a8a1f-8ded-419e-8680-0fc8663930c1"
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "texto"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "bd30d3c6-9f5e-43a1-b84a-a1ef0903b40d",
"leftValue": "={{$json.message.voice.file_id}}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "audio"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "994b4cac-7bbd-4652-94d5-88f63f1d4d9a",
"leftValue": "={{$json.message.photo[0].file_id}}",
"rightValue": "foto",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "foto"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "b107b71a-8d71-4f76-9f6f-4c185b3c40ca",
"leftValue": "={{$json.message.document.mime_type}}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "documento"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
2736,
1280
],
"id": "2b29a043-5b08-4e86-a5e1-55c056c50ec8",
"name": "Switch"
},
{
"parameters": {
"chatId": "={{ $('trigger_aurelio').first().json.message.from.id }}",
"text": "=Formato no soportado. Intente de nuevo 🐶",
"additionalFields": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
3040,
1488
],
"id": "7493e86c-4054-44e1-a999-6f1f4ce6fdd0",
"name": "mensaje_formato_no_soportado"
},
{
"parameters": {
"chatId": "={{ $('data').first().json.contact_id }}",
"text": "={{ $json.output }}",
"additionalFields": {
"appendAttribution": false,
"parse_mode": "MarkdownV2"
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
4112,
1152
],
"id": "6d2fbdd4-187a-49af-87f8-9f31d4aa9d36",
"name": "respuesta",
"retryOnFail": false,
"waitBetweenTries": 5000
},
{
"parameters": {
"resource": "file",
"fileId": "={{ $json.message.voice.file_id }}",
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
3040,
1296
],
"id": "3fa25ead-77d4-4248-a82d-51e9db34d7af",
"name": "get_audio"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "75da8d7f-60f7-49a6-8cc6-dc935a3d2623",
"name": "contact_id",
"value": "={{ $('trigger_aurelio').first().json.message.from.id }}",
"type": "string"
},
{
"id": "c5b7e5fa-6480-42a2-91cf-32e5c9711672",
"name": "primer_nombre",
"value": "={{ $('trigger_aurelio').first().json.message.from.first_name }}",
"type": "string"
},
{
"id": "a98db422-e2b1-474e-816a-32bb22b23671",
"name": "nombre_usuario",
"value": "={{ $('trigger_aurelio').first().json.message.from.username }}",
"type": "string"
},
{
"id": "874b422a-c7ed-4fc3-84a6-3b6b20cebaae",
"name": "mensaje",
"value": "={{ $('trigger_aurelio').first().json.message.text?.replace(/'/g, \"''\") || $('audio_texto1').first().json.content.parts[0].text || '' }}",
"type": "string"
},
{
"id": "f9db8d83-a199-461c-a47e-c86535d7b7c4",
"name": "fecha_mensaje",
"value": "={{ new Date().toISOString() }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
3456,
1152
],
"id": "abd2cebf-bbb9-4ac4-bc9f-a6ee7641edea",
"name": "data"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"typeVersion": 1.2,
"position": [
3840,
1872
],
"id": "1612b2dd-8b0a-47cc-97df-e88e0f5a104f",
"name": "Embeddings OpenAI"
},
{
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"type": "n8n-nodes-base.telegramTrigger",
"typeVersion": 1.3,
"position": [
2544,
1312
],
"id": "02a1d80a-9a83-4c15-ae13-d925d678514e",
"name": "trigger_aurelio"
},
{
"parameters": {
"resource": "audio",
"operation": "transcribe",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 2.3,
"position": [
3264,
1296
],
"id": "3b50d2a4-4916-44f4-8681-cedd6d338363",
"name": "audio_texto"
},
{
"parameters": {
"dataType": "binary",
"loader": "pdfLoader",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"typeVersion": 1.1,
"position": [
3840,
1696
],
"id": "b0c40230-193a-41ab-853c-45534a6338d5",
"name": "Default Data Loader"
},
{
"parameters": {
"sessionIdType": "customKey",
"sessionKey": "={{ $('data').first().json.contact_id }}",
"tableName": "n8n_chat_histories_aurelio"
},
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"typeVersion": 1.4,
"position": [
3728,
1344
],
"id": "f0d68f32-856e-4e8d-9495-3fa38d1e62d2",
"name": "Postgres Chat Memory"
},
{
"parameters": {
"model": {
"__rl": true,
"value": "gpt-4o-mini",
"mode": "list",
"cachedResultName": "gpt-4o-mini"
},
"builtInTools": {},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [
3568,
1344
],
"id": "7897b761-7c7d-4dc5-ac23-ec6df89d465e",
"name": "OpenAI Chat Model"
},
{
"parameters": {
"mode": "retrieve-as-tool",
"toolDescription": "Usa esta herramienta para buscar información sobre Aurelio: \nprocesos internos, políticas, manual de la empresa, \nprocedimientos operativos y documentación institucional.",
"tableName": {
"__rl": true,
"value": "rpc/match_documents",
"mode": "list",
"cachedResultName": "rpc/match_documents"
},
"topK": 10,
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"typeVersion": 1.3,
"position": [
3984,
1520
],
"id": "a430db20-9d8f-4910-a25a-2b3b6dce15e0",
"name": "knowledge_aurelio"
},
{
"parameters": {
"promptType": "define",
"text": "=Nombre del Usuario: {{ $('data').first().json.primer_nombre }}\nMensaje del Usuario: {{ $('data').first().json.mensaje }}",
"options": {
"systemMessage": "=Eres el asistente interno de Aurelio Agency, una agencia especializada en inteligencia artificial y automatización de procesos.\n\nTu función es responder preguntas de los empleados sobre los procesos internos, servicios, cultura y operaciones de la agencia, basándote EXCLUSIVAMENTE en la información de la base de conocimiento que tenés disponible.\n\nREGLAS:\n- Solo respondés con información que esté en la base de conocimiento. Si no encontrás la respuesta, decís: \"No tengo información sobre eso en la base de conocimiento. Te recomiendo consultarlo con Lucien o Gustavo.\"\n- Respondés siempre en español, de forma clara y concisa.\n- No inventás información, precios, procesos ni nombres que no estén en la base.\n- Si la pregunta es ambigua, pedís clarificación antes de responder.\n- Tu tono es profesional pero cercano, como un compañero de equipo con experiencia.\n\nCONTEXTO:\nEres usado principalmente por empleados nuevos que necesitan orientarse rápidamente sin interrumpir a los fundadores."
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
3632,
1152
],
"id": "7912da4c-1e94-4a34-a68c-4f0ea726db65",
"name": "aurelio_wiki"
}
],
"connections": {
"Upload your file here": {
"main": [
[
{
"node": "Supabase Vector Store",
"type": "main",
"index": 0
}
]
]
},
"formateo": {
"main": [
[
{
"node": "respuesta",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "data",
"type": "main",
"index": 0
}
],
[
{
"node": "get_audio",
"type": "main",
"index": 0
}
],
[
{
"node": "mensaje_formato_no_soportado",
"type": "main",
"index": 0
}
],
[
{
"node": "mensaje_formato_no_soportado",
"type": "main",
"index": 0
}
]
]
},
"respuesta": {
"main": [
[],
[]
]
},
"get_audio": {
"main": [
[
{
"node": "audio_texto",
"type": "main",
"index": 0
}
]
]
},
"data": {
"main": [
[
{
"node": "aurelio_wiki",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI": {
"ai_embedding": [
[
{
"node": "Supabase Vector Store",
"type": "ai_embedding",
"index": 0
},
{
"node": "knowledge_aurelio",
"type": "ai_embedding",
"index": 0
}
]
]
},
"trigger_aurelio": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"audio_texto": {
"main": [
[
{
"node": "data",
"type": "main",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Supabase Vector Store",
"type": "ai_document",
"index": 0
}
]
]
},
"Postgres Chat Memory": {
"ai_memory": [
[
{
"node": "aurelio_wiki",
"type": "ai_memory",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "aurelio_wiki",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"knowledge_aurelio": {
"ai_tool": [
[
{
"node": "aurelio_wiki",
"type": "ai_tool",
"index": 0
}
]
]
},
"aurelio_wiki": {
"main": [
[
{
"node": "formateo",
"type": "main",
"index": 0
}
]
]
}
}
}