智能Telegram助手
高级
这是一个AI Chatbot, Multimodal AI领域的自动化工作流,包含 36 个节点。主要使用 Set, Code, Switch, Postgres, Telegram 等节点。 使用Gemini AI、PostgreSQL记忆和动态路由构建智能Telegram助手
前置要求
- •PostgreSQL 数据库连接信息
- •Telegram Bot Token
- •Google Gemini API Key
使用的节点 (36)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "50be75eaab016244f302e16f06394e6613d664bfc61e8cd41452474a0de6a3ee",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "fccc9f50-71fa-4e25-9b15-8fd540ddc2fa",
"name": "模型选择器",
"type": "@n8n/n8n-nodes-langchain.modelSelector",
"position": [
800,
1536
],
"parameters": {
"rules": {
"rule": [
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "976d83bb-7e9e-4aab-9722-25a9e238164f",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.output.difficulty }}",
"rightValue": 1
}
]
}
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1e68688d-73fe-47c1-9b35-a1e226220bcd",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.output.difficulty }}",
"rightValue": 2
}
]
},
"modelIndex": 2
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "61d58197-db59-4cd7-bc41-bbeaf5e7b069",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.output.difficulty }}",
"rightValue": 3
}
]
},
"modelIndex": 3
}
]
},
"numberInputs": 3
},
"typeVersion": 1
},
{
"id": "cf5b2ea0-78c5-47bf-a3c1-4c59c9a32f76",
"name": "结构化输出解析器",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
336,
1504
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"difficulty\": {\n \"type\": \"integer\",\n \"enum\": [1, 2, 3]\n },\n \"context\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"difficulty\", \"context\"]\n}\n"
},
"typeVersion": 1.3
},
{
"id": "3a60caa7-eb1a-4bbd-88fc-55d7a3ffae29",
"name": "Gemini 2.5 Flash Lite",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
720,
1728
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.5-flash-lite"
},
"credentials": {
"googlePalmApi": {
"id": "to92mdfNe3L6sBae",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "412d35ed-cd49-4d20-b425-2f556ef175b1",
"name": "Gemini 2.5 Flash",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
880,
1728
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"id": "to92mdfNe3L6sBae",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "2cc40e2c-a2be-435e-8540-9235efc41e08",
"name": "Gemini 2.5 Pro",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1024,
1728
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.5-pro"
},
"credentials": {
"googlePalmApi": {
"id": "to92mdfNe3L6sBae",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "35f56404-6998-4952-a7f3-8716712bf96a",
"name": "获取聊天记忆",
"type": "n8n-nodes-base.postgres",
"onError": "continueRegularOutput",
"position": [
-256,
1328
],
"parameters": {
"limit": 25,
"table": {
"__rl": true,
"mode": "list",
"value": "chat_memory",
"cachedResultName": "chat_memory"
},
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"options": {},
"operation": "select"
},
"credentials": {
"postgres": {
"id": "eQR2NFRag48wov9g",
"name": "Postgres account"
}
},
"typeVersion": 2.6,
"alwaysOutputData": true
},
{
"id": "5e6058bc-a3b8-4827-954e-85e3a000a986",
"name": "MarkdownV2",
"type": "n8n-nodes-base.code",
"position": [
1136,
1264
],
"parameters": {
"jsCode": "/**\n * MarkdownV2-safe formatter + auto-chunker for Telegram (n8n Code node)\n * --------------------------------------------------------------------\n * - Allows: *bold*, _italic_, ||spoiler||, [label](url)\n * - Escapes everything else for Telegram MarkdownV2\n * - Validates/normalizes URLs\n * - Converts \"# Heading\" lines to bold titles\n * - Splits long messages into <= 4096-char chunks (uses a 4000-char budget)\n * - Outputs one item per chunk so the Telegram node sends all parts\n *\n * Recommended: Run this node in \"Run Once for All Items\".\n */\n\nconst MAX_TELEGRAM = 4096;\nconst SAFE_BUDGET = 4000; // small margin to avoid edge overflows\n\n// ============ MarkdownV2 helpers ============\nfunction escapeMarkdownV2(text) {\n if (!text) return '';\n return String(text).replace(/([\\\\_*[\\]()~`>#+\\-=|{}.!])/g, '\\\\$1');\n}\n\nfunction escapeForUrl(url) {\n return String(url).replace(/[)\\\\]/g, '\\\\$&');\n}\n\nfunction normalizeAndValidateUrl(url) {\n let raw = String(url || '').trim();\n try {\n const u = new URL(raw);\n return u.toString();\n } catch {}\n // Try https:// for bare domains\n const domainLike = /^[a-z0-9.-]+\\.[a-z]{2,}([/:?#].*)?$/i.test(raw);\n if (domainLike) {\n try {\n const u2 = new URL('https://' + raw);\n return u2.toString();\n } catch {}\n }\n return null;\n}\n\nfunction normalizeHeadings(text) {\n // Turn \"# Title\" → \"*Title*\"\n return text.replace(/^(#{1,6})\\s+(.*)$/gm, (m, hashes, title) => `*${title.trim()}*`);\n}\n\nfunction normalizeCommonMd(text) {\n return String(text)\n .replace(/\\*\\*([\\s\\S]*?)\\*\\*/g, '*$1*') // **bold** → *bold*\n .replace(/__([\\s\\S]*?)__/g, '_$1_'); // __italic__ → _italic_\n}\n\n/**\n * Convert incoming text to Telegram-safe MarkdownV2.\n */\nfunction processMarkdownV2Safe(inputText) {\n if (!inputText) return '';\n\n let text = normalizeCommonMd(String(inputText));\n text = normalizeHeadings(text);\n\n const placeholders = { links: [], bolds: [], italics: [], spoilers: [] };\n\n // Links: keep safe via placeholders during escaping\n text = text.replace(/\\[([^\\]\\n]+)\\]\\(([^)]+)\\)/g, (m, label, url) => {\n const normalizedUrl = normalizeAndValidateUrl(url);\n if (!normalizedUrl) return escapeMarkdownV2(label);\n const idx = placeholders.links.length;\n const ph = `⟬L${idx}⟭`;\n const safeLabel = escapeMarkdownV2(label);\n const safeUrl = escapeForUrl(normalizedUrl);\n placeholders.links.push(`[${safeLabel}](${safeUrl})`);\n return ph;\n });\n\n // Bold\n text = text.replace(/\\*([\\s\\S]+?)\\*/g, (m, inner) => {\n const idx = placeholders.bolds.length;\n const ph = `⟬B${idx}⟭`;\n placeholders.bolds.push(`*${escapeMarkdownV2(inner)}*`);\n return ph;\n });\n\n // Italic\n text = text.replace(/_([\\s\\S]+?)_/g, (m, inner) => {\n const idx = placeholders.italics.length;\n const ph = `⟬I${idx}⟭`;\n placeholders.italics.push(`_${escapeMarkdownV2(inner)}_`);\n return ph;\n });\n\n // Spoilers\n text = text.replace(/\\|\\|([\\s\\S]+?)\\|\\|/g, (m, inner) => {\n const idx = placeholders.spoilers.length;\n const ph = `⟬S${idx}⟭`;\n placeholders.spoilers.push(`||${escapeMarkdownV2(inner)}||`);\n return ph;\n });\n\n // Escape everything else\n text = escapeMarkdownV2(text);\n\n // Restore placeholders\n placeholders.links.forEach((md, i) => { text = text.replace(`⟬L${i}⟭`, md); });\n placeholders.bolds.forEach((md, i) => { text = text.replace(`⟬B${i}⟭`, md); });\n placeholders.italics.forEach((md, i) => { text = text.replace(`⟬I${i}⟭`, md); });\n placeholders.spoilers.forEach((md, i) => { text = text.replace(`⟬S${i}⟭`, md); });\n\n return text;\n}\n\n// ============ Chunking helpers ============\n/**\n * Split text into Telegram-safe chunks <= maxLen.\n * Prefers paragraph boundaries, then sentence boundaries, then words.\n * Falls back to hard cuts only when unavoidable (e.g., extremely long URL).\n */\nfunction chunkForTelegram(text, maxLen = SAFE_BUDGET) {\n if (!text || text.length <= maxLen) return [text || ''];\n\n const parts = [];\n let buffer = '';\n\n const flush = () => {\n if (buffer) {\n parts.push(buffer);\n buffer = '';\n }\n };\n\n // 1) Paragraph-level packing\n const paragraphs = text.split(/\\n{2,}/);\n for (const pRaw of paragraphs) {\n const p = pRaw; // keep paragraph as-is\n const candidate = buffer ? buffer + '\\n\\n' + p : p;\n if (candidate.length <= maxLen) {\n buffer = candidate;\n continue;\n }\n if (p.length <= maxLen) {\n flush();\n buffer = p;\n continue;\n }\n\n // 2) Sentence-level packing (paragraph is still too big)\n flush();\n const sentences = p.split(/(?<=[.!?…])\\s+(?=[^\\s])/u);\n let sBuf = '';\n for (const s of sentences) {\n const sCandidate = sBuf ? sBuf + ' ' + s : s;\n if (sCandidate.length <= maxLen) {\n sBuf = sCandidate;\n continue;\n }\n if (s.length <= maxLen) {\n if (sBuf) parts.push(sBuf);\n sBuf = s;\n continue;\n }\n\n // 3) Word-level packing (sentence is still too big)\n if (sBuf) { parts.push(sBuf); sBuf = ''; }\n let wBuf = '';\n const words = s.split(/\\s+/);\n for (const w of words) {\n const wCandidate = wBuf ? wBuf + ' ' + w : w;\n if (wCandidate.length <= maxLen) {\n wBuf = wCandidate;\n continue;\n }\n if (w.length <= maxLen) {\n if (wBuf) parts.push(wBuf);\n wBuf = w;\n continue;\n }\n // 4) Hard split (extremely long token, e.g., massive URL)\n if (wBuf) { parts.push(wBuf); wBuf = ''; }\n const re = new RegExp(`.{1,${maxLen}}`, 'g');\n const hardPieces = w.match(re) || [];\n parts.push(...hardPieces);\n }\n if (wBuf) parts.push(wBuf);\n }\n if (sBuf) parts.push(sBuf);\n }\n if (buffer) parts.push(buffer);\n\n // Final safety pass: trim chunks that might still exceed MAX_TELEGRAM\n return parts.flatMap(part => {\n if (part.length <= MAX_TELEGRAM) return [part];\n const re = new RegExp(`.{1,${SAFE_BUDGET}}`, 'g');\n return part.match(re) || [];\n });\n}\n\n// ============ Main ============\nconst inputItems = $input.all();\nconst out = [];\n\nfor (const item of inputItems) {\n const j = item.json || {};\n const raw =\n j.message ?? j.output ?? j.text ?? j.content ?? '';\n\n const formatted = processMarkdownV2Safe(raw);\n const chunks = chunkForTelegram(formatted, SAFE_BUDGET);\n\n chunks.forEach((chunk, idx) => {\n out.push({\n json: {\n ...j,\n message: chunk,\n message_part_index: idx + 1,\n message_parts_total: chunks.length,\n },\n binary: item.binary,\n });\n });\n}\n\nreturn out;\n"
},
"typeVersion": 2
},
{
"id": "6ce0f61c-03d1-4bef-827f-ac3c80f48939",
"name": "发送短信",
"type": "n8n-nodes-base.telegram",
"position": [
1312,
1264
],
"webhookId": "1ad49e91-7894-4fb1-ba93-73ba3ec4e666",
"parameters": {
"text": "={{ $json.message }}",
"chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
"additionalFields": {
"parse_mode": "MarkdownV2",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"id": "rzhkYoexl5hHvqnv",
"name": "Telegram account"
}
},
"typeVersion": 1.2
},
{
"id": "662e6beb-7498-42c2-ba0c-6530c100bf97",
"name": "修复MIME类型",
"type": "n8n-nodes-base.code",
"position": [
-1184,
1328
],
"parameters": {
"jsCode": "// --- Mapa Extendido de Tipos MIME ---\n// Una lista completa para cubrir la mayoría de los formatos de archivo comunes.\nconst mimeMap = {\n // --- Formatos de Documentos ---\n 'pdf': 'application/pdf',\n 'txt': 'text/plain',\n 'rtf': 'application/rtf',\n 'csv': 'text/csv',\n 'html': 'text/html',\n 'htm': 'text/html',\n 'json': 'application/json',\n 'xml': 'application/xml', // 'text/xml' también es válido pero 'application/xml' es más común\n 'yaml': 'application/x-yaml',\n 'yml': 'application/x-yaml',\n\n // --- Formatos de Microsoft Office ---\n 'doc': 'application/msword',\n 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'xls': 'application/vnd.ms-excel',\n 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'ppt': 'application/vnd.ms-powerpoint',\n 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n 'pub': 'application/vnd.ms-publisher',\n\n // --- Formatos de OpenOffice / LibreOffice ---\n 'odt': 'application/vnd.oasis.opendocument.text',\n 'ods': 'application/vnd.oasis.opendocument.spreadsheet',\n 'odp': 'application/vnd.oasis.opendocument.presentation',\n 'odg': 'application/vnd.oasis.opendocument.graphics',\n\n // --- Formatos de Apple iWork ---\n 'pages': 'application/vnd.apple.pages',\n 'numbers': 'application/vnd.apple.numbers',\n 'key': 'application/vnd.apple.keynote',\n\n // --- Formatos de Imagen ---\n 'png': 'image/png',\n 'jpg': 'image/jpeg',\n 'jpeg': 'image/jpeg',\n 'gif': 'image/gif',\n 'webp': 'image/webp',\n 'svg': 'image/svg+xml',\n 'bmp': 'image/bmp',\n 'ico': 'image/vnd.microsoft.icon',\n 'tif': 'image/tiff',\n 'tiff': 'image/tiff',\n 'heic': 'image/heic',\n 'heif': 'image/heif',\n\n // --- Formatos de Audio ---\n 'mp3': 'audio/mpeg',\n 'wav': 'audio/wav',\n 'oga': 'audio/ogg',\n 'ogg': 'audio/ogg',\n 'flac': 'audio/flac',\n 'm4a': 'audio/mp4',\n 'aac': 'audio/aac',\n 'opus': 'audio/opus',\n 'wma': 'audio/x-ms-wma',\n 'mid': 'audio/midi',\n 'midi': 'audio/midi',\n\n // --- Formatos de Video ---\n 'mp4': 'video/mp4',\n 'mov': 'video/quicktime',\n 'webm': 'video/webm',\n 'mpeg': 'video/mpeg',\n 'mpg': 'video/mpeg',\n 'avi': 'video/x-msvideo',\n 'wmv': 'video/x-ms-wmv',\n 'flv': 'video/x-flv',\n 'mkv': 'video/x-matroska',\n\n // --- Formatos de Archivos y Compresión ---\n 'zip': 'application/zip',\n 'rar': 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n 'tar': 'application/x-tar',\n 'gz': 'application/gzip',\n 'bz2': 'application/x-bzip2',\n\n // --- Otros Formatos ---\n 'epub': 'application/epub+zip',\n 'ics': 'text/calendar',\n 'vcf': 'text/vcard',\n 'js': 'text/javascript',\n 'css': 'text/css',\n 'sh': 'application/x-sh',\n 'py': 'text/x-python',\n};\n\n// --- Lógica de Procesamiento (sin cambios) ---\n\n// Obtenemos todos los items que llegan al nodo\nconst items = $input.all();\n\n// Iteramos sobre cada item para procesarlo\nfor (const item of items) {\n // Verificamos que el item tenga datos binarios para procesar\n if (item.binary && item.binary['data']) {\n // Obtenemos el nombre del archivo de forma segura\n const fileName = item.binary['data'].fileName || '';\n if (!fileName) {\n continue; // Si no hay nombre de archivo, pasamos al siguiente item\n }\n\n // Extraemos la extensión del archivo de forma robusta\n const extension = fileName.slice((fileName.lastIndexOf(\".\") - 1 >>> 0) + 2).toLowerCase();\n\n // Buscamos la extensión en nuestro mapa\n const newMimeType = mimeMap[extension];\n\n // Si encontramos una coincidencia en el mapa, actualizamos el mimeType\n if (newMimeType) {\n if(item.binary['data'].mimeType !== newMimeType) {\n console.log(`Cambiando mimeType para '${fileName}' de '${item.binary['data'].mimeType}' a '${newMimeType}'.`);\n item.binary['data'].mimeType = newMimeType;\n }\n }\n }\n}\n\n// Devolvemos todos los items, modificados o no\nreturn items;"
},
"typeVersion": 2
},
{
"id": "07281d83-6c94-4952-819e-288a4435da24",
"name": "正在输入...",
"type": "n8n-nodes-base.telegram",
"position": [
-1744,
1184
],
"webhookId": "b768e407-5f22-4b80-a8a9-2d255b9bf815",
"parameters": {
"chatId": "={{ $json.message.chat.id }}",
"operation": "sendChatAction"
},
"credentials": {
"telegramApi": {
"id": "rzhkYoexl5hHvqnv",
"name": "Telegram account"
}
},
"typeVersion": 1.2
},
{
"id": "e211d4af-9ebd-4524-84ef-934349b6b155",
"name": "get_message(音频/视频消息)",
"type": "n8n-nodes-base.set",
"position": [
-848,
1328
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "d8935452-fe20-469d-a68d-1aad056cb8dd",
"name": "message",
"type": "string",
"value": "=Voice message description:{{ $json.candidates?.[0]?.content?.parts?.[0]?.text || $json.content?.parts?.[0]?.text }}"
},
{
"id": "93f1bba1-1180-404a-93ca-c34cf1d1b7ac",
"name": "chat_id",
"type": "string",
"value": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9c28c37b-1d37-4f23-90a3-872f5e3870a7",
"name": "分析语音消息",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"position": [
-1024,
1328
],
"parameters": {
"text": "What's in this audio message from telegram user?",
"modelId": {
"__rl": true,
"mode": "list",
"value": "models/gemini-2.5-pro",
"cachedResultName": "models/gemini-2.5-pro"
},
"options": {},
"resource": "audio",
"inputType": "binary",
"operation": "analyze"
},
"credentials": {
"googlePalmApi": {
"id": "to92mdfNe3L6sBae",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "ea646e8c-e6d0-47ea-8743-45eade4c1c4d",
"name": "get_message(文本)",
"type": "n8n-nodes-base.set",
"position": [
-1184,
1152
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "801ec600-22ad-4a94-a2b4-ae72eb271df0",
"name": "message",
"type": "string",
"value": "={{ $('Telegram Trigger').item.json.message.text }}"
},
{
"id": "263071fb-bcdf-42b0-bb46-71b75fa0bf2a",
"name": "chat_id",
"type": "string",
"value": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "1ca88076-5c56-4561-bb8a-fdf1db080d2a",
"name": "输入消息路由器1",
"type": "n8n-nodes-base.switch",
"position": [
-1600,
1312
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Text",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "fcb767ee-565e-4b56-a54e-6f97f739fc24",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "Voice Message",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c1016c40-f8f2-4e08-8ec8-5cdb88f5c87a",
"operator": {
"type": "object",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Telegram Trigger').item.json.message.voice }}",
"rightValue": ""
}
]
},
"renameOutput": true
}
]
},
"options": {
"ignoreCase": false,
"fallbackOutput": "extra",
"allMatchingOutputs": true
}
},
"typeVersion": 3.2
},
{
"id": "298fa06c-d3fc-4d20-a2d4-fe879a01527c",
"name": "下载语音消息",
"type": "n8n-nodes-base.telegram",
"position": [
-1360,
1328
],
"webhookId": "d28e2f59-d662-4e75-8bac-11fdc3fbb295",
"parameters": {
"fileId": "={{ $('Telegram Trigger').item.json.message.voice.file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"id": "rzhkYoexl5hHvqnv",
"name": "Telegram account"
}
},
"typeVersion": 1.2
},
{
"id": "5a1dc986-6bfe-4400-bdbf-d4f5817e0f7e",
"name": "Telegram触发器",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-1888,
1328
],
"webhookId": "1aecee74-ba0f-4fe2-a302-578312187154",
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"id": "rzhkYoexl5hHvqnv",
"name": "Telegram account"
}
},
"typeVersion": 1.2
},
{
"id": "0188bc12-4fc1-4149-8c80-edf8e80009ec",
"name": "标准化输入",
"type": "n8n-nodes-base.set",
"position": [
-464,
1328
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "3c2fa4f9-079c-4729-9737-66ce8f42029f",
"name": "message",
"type": "string",
"value": "={{ $json.message }}"
},
{
"id": "b6e57068-8ece-4725-b07d-1b00069943b0",
"name": "chat_id",
"type": "string",
"value": "={{ $json.chat_id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "4db66ea5-0817-4326-9991-ab6a905ec0ee",
"name": "聚合",
"type": "n8n-nodes-base.aggregate",
"position": [
-48,
1328
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "message"
}
]
}
},
"typeVersion": 1
},
{
"id": "a4ce42c2-d1cc-4233-9ee7-2aac9a5f0c45",
"name": "Google Gemini 2.5 Flash Lite",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
192,
1504
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.5-flash-lite"
},
"credentials": {
"googlePalmApi": {
"id": "to92mdfNe3L6sBae",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "5c2cd387-3b15-4869-87da-6873437a0d33",
"name": "get_error_message",
"type": "n8n-nodes-base.set",
"position": [
-1184,
1504
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "d8935452-fe20-469d-a68d-1aad056cb8dd",
"name": "message",
"type": "string",
"value": "=It was not possible to process the file.File type not supported."
},
{
"id": "38ba2498-2141-4a04-a22a-64563fe2ee6f",
"name": "chat_id",
"type": "string",
"value": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "d31898fc-4d10-43ea-bc5d-402ac29f3f4b",
"name": "代理",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
800,
1328
],
"parameters": {
"text": "=Context: {{ $json.output.context }}\nUser request: {{ $('Normalize input').item.json.message }}",
"options": {
"returnIntermediateSteps": true
},
"promptType": "define"
},
"typeVersion": 2.1
},
{
"id": "ee146b55-17b6-414c-be6b-f8416ece7075",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1984,
1104
],
"parameters": {
"color": 5,
"width": 1312,
"height": 624,
"content": ""
},
"typeVersion": 1
},
{
"id": "e677f7d7-2cfc-476d-bdc0-08b4cf17cb4d",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-576,
1248
],
"parameters": {
"color": 3,
"width": 1216,
"height": 400,
"content": ""
},
"typeVersion": 1
},
{
"id": "d36b2018-ca63-4c1f-a40e-46d1452753e2",
"name": "当点击\"执行工作流\"时",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1888,
880
],
"parameters": {},
"typeVersion": 1
},
{
"id": "451eb06f-5b47-44c5-86fa-20587cf89870",
"name": "创建聊天记忆表",
"type": "n8n-nodes-base.postgres",
"position": [
-1696,
880
],
"parameters": {
"query": "CREATE TABLE IF NOT EXISTS public.chat_memory (\n id SERIAL PRIMARY KEY,\n session_id VARCHAR(255) NOT NULL,\n message TEXT DEFAULT 'Could not get data'\n) TABLESPACE pg_default;\n\nCREATE INDEX IF NOT EXISTS chat_memory_session_id_idx \nON public.chat_memory USING btree (session_id) \nTABLESPACE pg_default;\n",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "eQR2NFRag48wov9g",
"name": "Postgres account"
}
},
"typeVersion": 2.6
},
{
"id": "fb4c1415-dd98-4944-8c12-e69f8d445be7",
"name": "便签 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1984,
848
],
"parameters": {
"color": 7,
"width": 512,
"height": 208,
"content": ""
},
"typeVersion": 1
},
{
"id": "50ac5adc-ce42-4f35-84ac-cf8e2bea5d38",
"name": "便签 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
672,
1248
],
"parameters": {
"color": 6,
"width": 880,
"height": 624,
"content": ""
},
"typeVersion": 1
},
{
"id": "97859eb8-951f-4abf-8b89-63299b456304",
"name": "更新聊天记忆(用户和代理)",
"type": "n8n-nodes-base.postgres",
"position": [
1136,
1424
],
"parameters": {
"table": {
"__rl": true,
"mode": "list",
"value": "chat_memory",
"cachedResultName": "chat_memory"
},
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"columns": {
"value": {
"message": "=User: {{ $('Normalize input').item.json.message }}\nAgent: {{ $json.output }}\n",
"session_id": "={{ $('Normalize input').item.json.chat_id }}"
},
"schema": [
{
"id": "id",
"type": "number",
"display": true,
"removed": true,
"required": false,
"displayName": "id",
"defaultMatch": true,
"canBeUsedToMatch": true
},
{
"id": "session_id",
"type": "string",
"display": true,
"required": true,
"displayName": "session_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "message",
"type": "string",
"display": true,
"required": false,
"displayName": "message",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"credentials": {
"postgres": {
"id": "eQR2NFRag48wov9g",
"name": "Postgres account"
}
},
"typeVersion": 2.6
},
{
"id": "632c9d0c-5ab3-46a6-bb4d-0d4bd3341fde",
"name": "总结与分类",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
192,
1328
],
"parameters": {
"text": "=Chat Memory: {{ $('Aggregate').item.json.message.join('\\n') }}\n\nUser Request: {{ $('Normalize input').item.json.message }}",
"batching": {},
"messages": {
"messageValues": [
{
"message": "=You are a system that analyzes a user request and its chat history.\n\n## Your goals:\n1. Summarize the chat history into only the relevant context for the current user request.\n2. Determine the difficulty of the request:\n - 1: Very simple (short answers, reminders, basic actions).\n - 2: Medium (some reasoning, structured outputs, combining info).\n - 3: Complex (multi-step reasoning, ambiguous queries, coding-level reasoning).\n\n## Output Format:\nYou must return JSON strictly following this schema:\n\n{\n \"difficulty\": 1 | 2 | 3,\n \"context\": \"string - summary of the relevant history\"\n}\n"
}
]
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "8979f56c-2809-426d-acda-9d455df8836e",
"name": "便签 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1984,
576
],
"parameters": {
"color": 7,
"width": 512,
"height": 256,
"content": "## ⚙️ 数据库初始化(聊天记忆表)"
},
"typeVersion": 1
},
{
"id": "cf047f39-85cd-41a6-8d2a-76ecec83b6f2",
"name": "便签 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1392,
432
],
"parameters": {
"color": 5,
"width": 704,
"height": 640,
"content": "## 🔵 输入处理(Telegram触发器与预处理)"
},
"typeVersion": 1
},
{
"id": "3557d1c3-c155-430a-a11b-5bc901111d46",
"name": "便签6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-352,
496
],
"parameters": {
"color": 3,
"width": 784,
"height": 720,
"content": "## 🔴 聊天记忆检索与上下文优化"
},
"typeVersion": 1
},
{
"id": "42fdc20f-2c28-4826-8704-20ffb8792bd7",
"name": "便签7",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
384
],
"parameters": {
"color": 6,
"width": 784,
"height": 832,
"content": "## 🟣 代理处理与响应传递"
},
"typeVersion": 1
},
{
"id": "1c29f5cf-c95e-40fc-9dc0-362dcda71574",
"name": "便签8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2560,
1104
],
"parameters": {
"color": 4,
"width": 544,
"height": 592,
"content": "## ✅ 此架构的主要优势"
},
"typeVersion": 1
},
{
"id": "84019987-a071-44d0-8e4b-d80c838007dc",
"name": "### 替换 Airtable 连接",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2496,
848
],
"parameters": {
"color": 2,
"width": 368,
"height": 192,
"content": "## 致谢"
},
"typeVersion": 1
},
{
"id": "0c425ab2-41d3-43c9-86bb-9c7cbfe968a4",
"name": "便签10",
"type": "n8n-nodes-base.stickyNote",
"position": [
1584,
1648
],
"parameters": {
"color": 2,
"width": 368,
"height": 192,
"content": "## 💡 需要帮助?"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Agent": {
"main": [
[
{
"node": "MarkdownV2",
"type": "main",
"index": 0
},
{
"node": "Update Chat Memory (User and Agent)",
"type": "main",
"index": 0
}
]
]
},
"Fix mime": {
"main": [
[
{
"node": "Analyze voice message",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "Summarize & Categorize",
"type": "main",
"index": 0
}
]
]
},
"MarkdownV2": {
"main": [
[
{
"node": "Send a text message",
"type": "main",
"index": 0
}
]
]
},
"Gemini 2.5 Pro": {
"ai_languageModel": [
[
{
"node": "Model Selector",
"type": "ai_languageModel",
"index": 2
}
]
]
},
"Model Selector": {
"ai_languageModel": [
[
{
"node": "Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Get Chat Memory": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"Normalize input": {
"main": [
[
{
"node": "Get Chat Memory",
"type": "main",
"index": 0
}
]
]
},
"Gemini 2.5 Flash": {
"ai_languageModel": [
[
{
"node": "Model Selector",
"type": "ai_languageModel",
"index": 1
}
]
]
},
"Telegram Trigger": {
"main": [
[
{
"node": "Input Message Router1",
"type": "main",
"index": 0
},
{
"node": "Typing…",
"type": "main",
"index": 0
}
]
]
},
"get_error_message": {
"main": [
[
{
"node": "Normalize input",
"type": "main",
"index": 0
}
]
]
},
"get_message (text)": {
"main": [
[
{
"node": "Normalize input",
"type": "main",
"index": 0
}
]
]
},
"Analyze voice message": {
"main": [
[
{
"node": "get_message (Audio/Video message)",
"type": "main",
"index": 0
}
]
]
},
"Gemini 2.5 Flash Lite": {
"ai_languageModel": [
[
{
"node": "Model Selector",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Input Message Router1": {
"main": [
[
{
"node": "get_message (text)",
"type": "main",
"index": 0
}
],
[
{
"node": "Download Voice Message",
"type": "main",
"index": 0
}
],
[
{
"node": "get_error_message",
"type": "main",
"index": 0
}
]
]
},
"Download Voice Message": {
"main": [
[
{
"node": "Fix mime",
"type": "main",
"index": 0
}
]
]
},
"Summarize & Categorize": {
"main": [
[
{
"node": "Agent",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Summarize & Categorize",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Google Gemini 2.5 Flash Lite": {
"ai_languageModel": [
[
{
"node": "Summarize & Categorize",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"get_message (Audio/Video message)": {
"main": [
[
{
"node": "Normalize input",
"type": "main",
"index": 0
}
]
]
},
"Update Chat Memory (User and Agent)": {
"main": [
[]
]
},
"When clicking ‘Execute workflow’": {
"main": [
[
{
"node": "Create Chat Memory Table",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - AI 聊天机器人, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用Gemini AI和PostgreSQL数据库处理Telegram中的多个媒体文件
使用Gemini AI和PostgreSQL数据库处理Telegram中的多个媒体文件
If
Set
Code
+16
100 节点John Alejandro SIlva
客服机器人
营养追踪与饮食记录(Telegram、Gemini AI和Google Sheets)
营养追踪与饮食记录(Telegram、Gemini AI和Google Sheets)
If
Set
Code
+13
55 节点John Alejandro SIlva
AI 聊天机器人
LinkedIn和X病毒内容自动引擎
使用AI生成和发布自动创建LinkedIn和X的病毒内容
If
Set
Wait
+26
156 节点Diptamoy Barman
内容创作
宠物美容发布与预约自动化
使用AI、Facebook和Telegram机器人自动化宠物美容发布与预约
If
Set
Switch
+17
36 节点Christian Moises
AI 聊天机器人
Telegram论坛脉搏:使用Gemini和Groq AI模型的社区监控
Telegram论坛脉搏:使用Gemini和Groq AI模型的社区监控
If
Set
Code
+13
59 节点Nguyen Thieu Toan
杂项
多智能体Telegram机器人
使用Telegram和Google Gemini的多智能体个人助手机器人
Set
Code
Merge
+18
85 节点Akil A
杂项
工作流信息
难度等级
高级
节点数量36
分类2
节点类型15
作者
John Alejandro SIlva
@alejandro-silvaDetail-oriented professional with a dual degree in Systems Engineering and Business Administration and international experience in technology and process improvement. I specialize in workflow automation with n8n, API integration, programming, and data analysis. Known for strong analytical skills and clear technical documentation.
外部链接
在 n8n.io 查看 →
分享此工作流