La Casa de Aurelio / Recursos
Recursos del video: Como crear un Agente de IA con n8n + Telegram + Supabase (10 min)
Recursos del tutorial para crear un bot de Telegram conectado a un LLM, desplegado en Railway, usando Supabase como base vectorial para consultar documentos.
Bienvenidos a La Casa de Aurelio.
Aca les dejo los recursos del tutorial para crear un bot de Telegram conectado a un LLM, desplegado en Railway, usando Supabase como base vectorial para consultar documentos.
La idea del sistema
- Subes archivos o texto.
- El contenido se vectoriza y se guarda en Supabase.
- El agente usa esa informacion como memoria.
- Le escribes por Telegram.
- El bot responde usando el contexto de tus propios documentos.
Recursos incluidos en este post
- Workflow JSON para importar en n8n.
- SQL para crear la tabla en Supabase.
- Estructura base para conectar Telegram, LLM, Railway y Supabase.
Como usarlo
- En Supabase, abre SQL Editor.
- Pega el SQL de abajo y ejecutalo.
- En n8n, importa el workflow JSON.
- Conecta tus credenciales: Telegram, Supabase, LLM/API y Railway.
- Haz una prueba con un documento pequeno antes de cargar mas informacion.
Importante
No compartas tus API keys, tokens de Telegram ni service role keys en publico. El workflow descargable esta sanitizado: no incluye credenciales ni webhook IDs del entorno original.
SQL para Supabase
-- 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;
$$;
JSON del workflow de n8n
Importa este JSON en n8n y vuelve a conectar cada credencial antes de activar el flujo.
{
"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
}
]
]
}
}
}