8
n8n 中文网amn8n.com

智能Telegram助手

高级

这是一个AI Chatbot, Multimodal AI领域的自动化工作流,包含 36 个节点。主要使用 Set, Code, Switch, Postgres, Telegram 等节点。 使用Gemini AI、PostgreSQL记忆和动态路由构建智能Telegram助手

前置要求
  • PostgreSQL 数据库连接信息
  • Telegram Bot Token
  • Google Gemini API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 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)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量36
分类2
节点类型15
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
John Alejandro SIlva

John Alejandro SIlva

@alejandro-silva

Detail-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 查看

分享此工作流