多源采集

高级

这是一个Miscellaneous、AI RAG、Multimodal AI领域的自动化工作流,包含 23 个节点。主要使用 Set、Code、HttpRequest、GoogleSheets、McpClientTool 等节点。 网络研究助手:基于Gemini AI的自动化搜索和抓取,生成电子表格报告

前置要求
  • 可能需要目标 API 的认证凭证
  • Google Sheets API 凭证
  • Google Gemini API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "SjiPE2lVXmmyh7Ca",
  "meta": {
    "instanceId": "7578372eeadee5ee5414cdf5a06141eebec63e21f295454563ddce7b1217363f",
    "templateCredsSetupCompleted": true
  },
  "name": "多源采集",
  "tags": [],
  "nodes": [
    {
      "id": "bf0013da-2066-45de-8833-fa2927728f00",
      "name": "当收到聊天消息时",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -288,
        0
      ],
      "webhookId": "18e5e55a-53be-4afb-adc5-bdc4dabfa067",
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "9fe3e0e0-f5ac-4018-90b7-f2e4fc7b207d",
      "name": "简单记忆",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        224,
        144
      ],
      "parameters": {
        "contextWindowLength": 30
      },
      "typeVersion": 1.3
    },
    {
      "id": "c9e95768-ea7c-43f0-b6fd-a824fc64d60d",
      "name": "Google Gemini聊天模型",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        80,
        144
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "89mVPG21GxPFECbN",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "cd7be0c8-f708-42f8-8411-a3622c25a0bf",
      "name": "Firecrawl列表",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        672,
        352
      ],
      "parameters": {},
      "credentials": {
        "mcpClientApi": {
          "id": "aFCnpjjzHv0KPnei",
          "name": "MCP: Firecrawl"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4cdda777-345c-4129-9ada-1a9c01b9a104",
      "name": "Firecrawl执行",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        672,
        464
      ],
      "parameters": {
        "toolName": "={{ \n$fromAI(\"tool\", \"the selected tool to use\")\n}}",
        "operation": "executeTool",
        "toolParameters": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"
      },
      "credentials": {
        "mcpClientApi": {
          "id": "aFCnpjjzHv0KPnei",
          "name": "MCP: Firecrawl"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "35a550c1-8fb7-40c3-af16-bb059c6d1947",
      "name": "Brave列表",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        768,
        352
      ],
      "parameters": {},
      "credentials": {
        "mcpClientApi": {
          "id": "wzdpQy5uTbYZQiko",
          "name": "MCP: Brave"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ecd7944c-0de2-4447-b640-7a7caaa30705",
      "name": "Brave执行",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        768,
        464
      ],
      "parameters": {
        "toolName": "={{\n$fromAI(\"tool\", \"the selected tool to use\")\n}}",
        "operation": "executeTool",
        "toolParameters": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"
      },
      "credentials": {
        "mcpClientApi": {
          "id": "wzdpQy5uTbYZQiko",
          "name": "MCP: Brave"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3041cd71-2131-4cf5-b21b-7b7decc0a4bb",
      "name": "Apify列表",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        864,
        464
      ],
      "parameters": {},
      "credentials": {
        "mcpClientApi": {
          "id": "0HMXUEhEUFLuWqlS",
          "name": "MCP : Apify"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "1ba3c633-998b-4ab2-83c1-c6dd0e7c6679",
      "name": "Apify执行",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        864,
        352
      ],
      "parameters": {
        "toolName": "={{ $fromAI(\"tool\", \"the selected tool to use\") }}",
        "operation": "executeTool",
        "toolParameters": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"
      },
      "credentials": {
        "mcpClientApi": {
          "id": "aFCnpjjzHv0KPnei",
          "name": "MCP: Firecrawl"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "73031a7a-6338-4683-a6e3-efee3819f89e",
      "name": "数据增强请求",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1296,
        0
      ],
      "parameters": {
        "url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $json.spreadsheetId }}/values:batchUpdate",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"valueInputOption\": \"USER_ENTERED\",\n  \"data\": {{ JSON.stringify($json.valueRanges) }}\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "9a7f6cbe-a132-4fef-9af8-b9851227faf6",
      "name": "Gemini研究编排器",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        208,
        0
      ],
      "parameters": {
        "options": {
          "systemMessage": "You are a helpful assistant\n\nUse Brave to search into the web\nUse Firecrawl to scrape websites\nUse Apify to scrape websites\n\nthe process is to use the tool node first then the execute node.\n\nAlways refer to the list of tools before attempting to access or use the execute tools"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "acf4a537-627a-4d20-8b02-215f8075900b",
      "name": "创建研究报告",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        704,
        0
      ],
      "parameters": {
        "title": "scrapped ",
        "options": {},
        "resource": "spreadsheet"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "FglkISb2md6llLsJ",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "13e00e06-9b7e-4fb2-bbbd-9e7211de9e96",
      "name": "格式化研究数据",
      "type": "n8n-nodes-base.code",
      "position": [
        880,
        0
      ],
      "parameters": {
        "jsCode": "// Version sécurisée qui gère les feuilles existantes\nconst agentOutput = $('Gemini Research Orchestrator').item.json.output;\nconst spreadsheetId = $('Create Research Report').item.json.spreadsheetId;\n\n// Fonction pour parser le markdown (identique)\nfunction parseAgentOutput(output) {\n  const lines = output.split('\\n').filter(line => line.trim() !== '');\n  const data = {\n    title: '',\n    categories: [],\n    jobs: []\n  };\n  \n  let currentSection = '';\n  let inTable = false;\n  let tableHeaders = [];\n  \n  for (let i = 0; i < lines.length; i++) {\n    const line = lines[i].trim();\n    \n    if (line.startsWith('Voici les données extraites')) {\n      data.title = line.replace(/\\*\\*/g, '').replace('Voici les données extraites du site ', '').replace(/[`:`]/g, '');\n    }\n    \n    if (line.startsWith('**') && line.endsWith(':**')) {\n      currentSection = line.replace(/\\*\\*/g, '').replace(':', '');\n      inTable = false;\n    }\n    \n    if (currentSection === 'Catégories d\\'emploi' && line.startsWith('*   ')) {\n      data.categories.push(line.replace('*   ', ''));\n    }\n    \n    if (line.startsWith('|') && !inTable) {\n      const headers = line.split('|').map(h => h.trim()).filter(h => h !== '');\n      if (headers.length > 0) {\n        tableHeaders = headers;\n        inTable = true;\n        i++;\n        continue;\n      }\n    }\n    \n    if (inTable && line.startsWith('|')) {\n      const cells = line.split('|').map(c => c.trim()).filter(c => c !== '');\n      if (cells.length === tableHeaders.length) {\n        const job = {};\n        tableHeaders.forEach((header, index) => {\n          job[header] = cells[index] || '';\n        });\n        data.jobs.push(job);\n      }\n    }\n  }\n  \n  return data;\n}\n\n// Fonction pour créer ou mettre à jour une feuille\nfunction createOrUpdateSheet(sheetName, sheetId, properties = {}) {\n  if (sheetId === 0) {\n    // Pour la feuille par défaut (ID 0), on la met à jour\n    return {\n      updateSheetProperties: {\n        properties: {\n          sheetId: sheetId,\n          title: sheetName,\n          gridProperties: {\n            rowCount: 1000,\n            columnCount: 26\n          },\n          ...properties\n        },\n        fields: 'title,tabColor,gridProperties'\n      }\n    };\n  } else {\n    // Pour les nouvelles feuilles, on les crée\n    return {\n      addSheet: {\n        properties: {\n          sheetId: sheetId,\n          title: sheetName,\n          gridProperties: {\n            rowCount: 1000,\n            columnCount: 26\n          },\n          ...properties\n        }\n      }\n    };\n  }\n}\n\n// Fonction pour ajouter des données dans une feuille\nfunction addSheetData(sheetName, range, values, majorDimension = 'ROWS') {\n  return {\n    range: `'${sheetName}'!${range}`,\n    majorDimension: majorDimension,\n    values: values\n  };\n}\n\n// Fonction pour formater les cellules\nfunction formatCells(sheetId, range, format) {\n  return {\n    repeatCell: {\n      range: {\n        sheetId: sheetId,\n        startRowIndex: range.startRow,\n        endRowIndex: range.endRow,\n        startColumnIndex: range.startCol,\n        endColumnIndex: range.endCol\n      },\n      cell: {\n        userEnteredFormat: format\n      },\n      fields: 'userEnteredFormat'\n    }\n  };\n}\n\n// Fonction pour obtenir les styles de formatage\nfunction getTextFormat(style) {\n  const formats = {\n    'TITLE': {\n      textFormat: {\n        bold: true,\n        fontSize: 16,\n        foregroundColor: { red: 0.1, green: 0.1, blue: 0.1 }\n      },\n      horizontalAlignment: 'CENTER',\n      backgroundColor: { red: 0.85, green: 0.85, blue: 0.95 }\n    },\n    'SECTION_HEADER': {\n      textFormat: {\n        bold: true,\n        fontSize: 14,\n        foregroundColor: { red: 0.2, green: 0.2, blue: 0.2 }\n      },\n      backgroundColor: { red: 0.9, green: 0.9, blue: 0.9 }\n    },\n    'TABLE_HEADER': {\n      textFormat: {\n        bold: true,\n        fontSize: 11,\n        foregroundColor: { red: 1, green: 1, blue: 1 }\n      },\n      backgroundColor: { red: 0.2, green: 0.4, blue: 0.8 },\n      horizontalAlignment: 'CENTER',\n      borders: {\n        top: { style: 'SOLID', width: 2 },\n        bottom: { style: 'SOLID', width: 2 },\n        left: { style: 'SOLID', width: 1 },\n        right: { style: 'SOLID', width: 1 }\n      }\n    },\n    'TABLE_CELL': {\n      textFormat: {\n        fontSize: 10,\n        foregroundColor: { red: 0.1, green: 0.1, blue: 0.1 }\n      },\n      borders: {\n        top: { style: 'SOLID', width: 1 },\n        bottom: { style: 'SOLID', width: 1 },\n        left: { style: 'SOLID', width: 1 },\n        right: { style: 'SOLID', width: 1 }\n      },\n      verticalAlignment: 'TOP'\n    },\n    'CATEGORY': {\n      textFormat: {\n        fontSize: 11,\n        foregroundColor: { red: 0.3, green: 0.3, blue: 0.3 }\n      },\n      backgroundColor: { red: 0.95, green: 0.98, blue: 0.95 }\n    }\n  };\n  return formats[style] || formats['TABLE_CELL'];\n}\n\n// Parsing des données\nlet parsedData;\ntry {\n  parsedData = parseAgentOutput(agentOutput);\n} catch (error) {\n  throw new Error(`Erreur lors du parsing des données: ${error.message}`);\n}\n\n// Construction des requêtes et données\nconst requests = [];\nconst valueRanges = [];\n\ntry {\n  // D'abord, effacer le contenu de la feuille par défaut\n  requests.push({\n    updateCells: {\n      range: {\n        sheetId: 0\n      },\n      fields: '*'\n    }\n  });\n\n  // 1. Mise à jour de la feuille par défaut (ID 0) -> \"Résumé\"\n  requests.push(createOrUpdateSheet('Resume', 0, {\n    tabColor: { red: 0.2, green: 0.5, blue: 0.8 }\n  }));\n\n  // Données de la feuille Résumé\n  const summaryData = [\n    [parsedData.title || 'Données extraites'],\n    [''],\n    ['Résumé des données:'],\n    [`Nombre de catégories: ${parsedData.categories.length}`],\n    [`Nombre d'emplois: ${parsedData.jobs.length}`],\n    [''],\n    ['Catégories d\\'emploi:']\n  ];\n\n  parsedData.categories.forEach(category => {\n    summaryData.push([`• ${category}`]);\n  });\n\n  valueRanges.push(addSheetData('Resume', 'A1', summaryData));\n\n  // Formatage de la feuille Résumé\n  requests.push(formatCells(0, { startRow: 0, endRow: 1, startCol: 0, endCol: 3 }, getTextFormat('TITLE')));\n  requests.push(formatCells(0, { startRow: 2, endRow: 3, startCol: 0, endCol: 3 }, getTextFormat('SECTION_HEADER')));\n  requests.push(formatCells(0, { startRow: 6, endRow: 7, startCol: 0, endCol: 3 }, getTextFormat('SECTION_HEADER')));\n  \n  const categoryStartRow = 7;\n  const categoryEndRow = categoryStartRow + parsedData.categories.length;\n  requests.push(formatCells(0, { \n    startRow: categoryStartRow, \n    endRow: categoryEndRow, \n    startCol: 0, \n    endCol: 2 \n  }, getTextFormat('CATEGORY')));\n\n  // 2. Création de la feuille \"Catégories\"\n  requests.push(createOrUpdateSheet('Categories', 1, {\n    tabColor: { red: 0.8, green: 0.9, blue: 0.7 }\n  }));\n\n  const categoriesData = [\n    ['Catégories d\\'emploi'],\n    [''],\n    ['Catégorie', 'Numéro']\n  ];\n\n  parsedData.categories.forEach((category, index) => {\n    categoriesData.push([category, index + 1]);\n  });\n\n  valueRanges.push(addSheetData('Categories', 'A1', categoriesData));\n\n  requests.push(formatCells(1, { startRow: 0, endRow: 1, startCol: 0, endCol: 2 }, getTextFormat('TITLE')));\n  requests.push(formatCells(1, { startRow: 2, endRow: 3, startCol: 0, endCol: 2 }, getTextFormat('TABLE_HEADER')));\n  \n  if (parsedData.categories.length > 0) {\n    requests.push(formatCells(1, { \n      startRow: 3, \n      endRow: 3 + parsedData.categories.length, \n      startCol: 0, \n      endCol: 2 \n    }, getTextFormat('TABLE_CELL')));\n  }\n\n  // 3. Création de la feuille \"Emplois\"\n  requests.push(createOrUpdateSheet('Emplois', 2, {\n    tabColor: { red: 0.9, green: 0.7, blue: 0.8 }\n  }));\n\n  if (parsedData.jobs.length > 0) {\n    const jobHeaders = Object.keys(parsedData.jobs[0]);\n    const jobsData = [\n      ['Liste des emplois disponibles'],\n      [''],\n      jobHeaders\n    ];\n\n    parsedData.jobs.forEach(job => {\n      const jobRow = jobHeaders.map(header => job[header] || '');\n      jobsData.push(jobRow);\n    });\n\n    valueRanges.push(addSheetData('Emplois', 'A1', jobsData));\n\n    requests.push(formatCells(2, { startRow: 0, endRow: 1, startCol: 0, endCol: jobHeaders.length }, getTextFormat('TITLE')));\n    requests.push(formatCells(2, { startRow: 2, endRow: 3, startCol: 0, endCol: jobHeaders.length }, getTextFormat('TABLE_HEADER')));\n    \n    if (parsedData.jobs.length > 0) {\n      requests.push(formatCells(2, { \n        startRow: 3, \n        endRow: 3 + parsedData.jobs.length, \n        startCol: 0, \n        endCol: jobHeaders.length \n      }, getTextFormat('TABLE_CELL')));\n    }\n  }\n\n  // 4. Création de la feuille \"Statistiques\"\n  requests.push(createOrUpdateSheet('Statistiques', 3, {\n    tabColor: { red: 0.95, green: 0.8, blue: 0.6 }\n  }));\n\n  const companyCount = [...new Set(parsedData.jobs.map(job => job.Entreprise || job.Company || ''))].length;\n  const roleTypes = {};\n  \n  parsedData.jobs.forEach(job => {\n    const role = job.Rôle || job.Role || '';\n    const roleType = role.split(' ')[0];\n    roleTypes[roleType] = (roleTypes[roleType] || 0) + 1;\n  });\n\n  const statsData = [\n    ['Statistiques des données'],\n    [''],\n    ['Métrique', 'Valeur'],\n    ['Nombre total d\\'emplois', parsedData.jobs.length],\n    ['Nombre d\\'entreprises uniques', companyCount],\n    ['Nombre de catégories', parsedData.categories.length],\n    [''],\n    ['Types de rôles les plus fréquents:'],\n    ['Type de rôle', 'Occurrences']\n  ];\n\n  const sortedRoleTypes = Object.entries(roleTypes)\n    .sort(([,a], [,b]) => b - a)\n    .slice(0, 10);\n\n  sortedRoleTypes.forEach(([role, count]) => {\n    statsData.push([role, count]);\n  });\n\n  valueRanges.push(addSheetData('Statistiques', 'A1', statsData));\n\n  requests.push(formatCells(3, { startRow: 0, endRow: 1, startCol: 0, endCol: 2 }, getTextFormat('TITLE')));\n  requests.push(formatCells(3, { startRow: 2, endRow: 3, startCol: 0, endCol: 2 }, getTextFormat('TABLE_HEADER')));\n  requests.push(formatCells(3, { startRow: 7, endRow: 8, startCol: 0, endCol: 2 }, getTextFormat('SECTION_HEADER')));\n  requests.push(formatCells(3, { startRow: 8, endRow: 9, startCol: 0, endCol: 2 }, getTextFormat('TABLE_HEADER')));\n\n  // Auto-redimensionnement des colonnes\n  for (let i = 0; i <= 3; i++) {\n    requests.push({\n      autoResizeDimensions: {\n        dimensions: {\n          sheetId: i,\n          dimension: 'COLUMNS',\n          startIndex: 0,\n          endIndex: 10\n        }\n      }\n    });\n  }\n\n} catch (error) {\n  console.error('Erreur lors de la génération du contenu:', error);\n  throw new Error(`Erreur lors de la génération du contenu: ${error.message}`);\n}\n\n// Validation finale des données\nif (!requests || requests.length === 0) {\n  throw new Error('Aucune requête générée - vérifiez les données d\\'entrée');\n}\n\nif (!valueRanges || valueRanges.length === 0) {\n  throw new Error('Aucune donnée générée - vérifiez les données d\\'entrée');\n}\n\n// Retour des données pour l'API Google Sheets\nreturn {\n  json: {\n    spreadsheetId: spreadsheetId,\n    requests: requests,\n    valueRanges: valueRanges,\n    totalRequests: requests.length,\n    totalValueRanges: valueRanges.length,\n    sheetsCreated: 4,\n    dataProcessed: {\n      title: parsedData.title,\n      categoriesCount: parsedData.categories.length,\n      jobsCount: parsedData.jobs.length,\n      companiesCount: [...new Set(parsedData.jobs.map(job => job.Entreprise || job.Company || ''))].length\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "eccede4d-c790-4b60-a3cd-5e9f29ac8f0e",
      "name": "填充研究报告",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1072,
        0
      ],
      "parameters": {
        "url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $json.spreadsheetId }}:batchUpdate",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"requests\": {{ JSON.stringify($json.requests) }}\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSheetsOAuth2Api"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "id": "osBJI4KIPRu07ngs",
          "name": "Google Docs account"
        },
        "googleSheetsOAuth2Api": {
          "id": "bkpmM7RgsOJtIBT5",
          "name": "Google Sheets account 2"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "c9603254-752b-4f86-8d77-e6231699094b",
      "name": "最终输出数据",
      "type": "n8n-nodes-base.set",
      "position": [
        1488,
        0
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"error_message\": \"{{ $json.error.message }}\",\n  \"error_code\": \"{{ $json.error.code }}\",\n  \"spreadsheet_id\": \"{{ $('Code').item.json.spreadsheetId }}\",\n  \"timestamp\": \"{{ new Date().toISOString() }}\"\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "0c07aba4-88c4-4ddd-93e8-26057f6104f8",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        -96
      ],
      "parameters": {
        "color": 4,
        "width": 400,
        "height": 256,
        "content": "## 入口点:"
      },
      "typeVersion": 1
    },
    {
      "id": "4a113616-2e51-4bb7-8995-1c657f12fa9b",
      "name": "便签 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -320
      ],
      "parameters": {
        "color": 4,
        "width": 256,
        "height": 128,
        "content": "## ⚙️ 前提条件"
      },
      "typeVersion": 1
    },
    {
      "id": "fadd1418-2831-4856-9913-de61ec11d418",
      "name": "便签 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -320
      ],
      "parameters": {
        "color": 4,
        "height": 128,
        "content": "## 📊 数据流"
      },
      "typeVersion": 1
    },
    {
      "id": "6afc44f5-db99-46a8-96ca-5e788e48bfff",
      "name": "便签 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        528,
        -320
      ],
      "parameters": {
        "color": 4,
        "width": 272,
        "height": 112,
        "content": "## ⚠️ 错误处理"
      },
      "typeVersion": 1
    },
    {
      "id": "104c3b3a-ae84-4ef5-99fb-b84cf599975a",
      "name": "便签 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -112
      ],
      "parameters": {
        "color": 5,
        "width": 544,
        "height": 384,
        "content": "## 编排"
      },
      "typeVersion": 1
    },
    {
      "id": "4bdd58e3-eddd-4fa3-82f4-bc84ec5498fc",
      "name": "便签 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        288
      ],
      "parameters": {
        "width": 752,
        "height": 304,
        "content": "## 数据采集工具"
      },
      "typeVersion": 1
    },
    {
      "id": "509c0f30-e634-46d5-83d2-b4aafd8090b8",
      "name": "便签6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -160
      ],
      "parameters": {
        "color": 3,
        "width": 544,
        "height": 304,
        "content": "## 报告生成"
      },
      "typeVersion": 1
    },
    {
      "id": "7dd445d7-2785-4f0a-a938-e9e9e962e929",
      "name": "便签7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 304,
        "content": "## 后处理"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "94fda3e6-3671-42e8-9f8a-d9d7688722eb",
  "connections": {
    "Apify list": {
      "ai_tool": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Brave list": {
      "ai_tool": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Apify execute": {
      "ai_tool": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Brave execute": {
      "ai_tool": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Firecrawl list": {
      "ai_tool": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Firecrawl execute": {
      "ai_tool": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Finalize Output Data": {
      "main": [
        []
      ]
    },
    "Format Research Data": {
      "main": [
        [
          {
            "node": "Populate Research Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Research Report": {
      "main": [
        [
          {
            "node": "Format Research Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Enrichment Request": {
      "main": [
        [
          {
            "node": "Finalize Output Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Populate Research Report": {
      "main": [
        [
          {
            "node": "Data Enrichment Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Gemini Research Orchestrator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini Research Orchestrator": {
      "main": [
        [
          {
            "node": "Create Research Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

这是一个高级难度的工作流,适用于Miscellaneous、AI RAG、Multimodal AI等场景。适合高级用户,包含 16+ 个节点的复杂工作流

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量23
分类3
节点类型10
难度说明

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

作者
franck fambou

franck fambou

@franck-f

As a student in Data Science & Artificial Intelligence, I design intelligent automations that combine no-code and AI to optimize business processes. I share innovative workflows to democratize automation.

外部链接
在 n8n.io 上查看 →

分享此工作流