多代理对话
高级
这是一个Building Blocks, AI领域的自动化工作流,包含 18 个节点。主要使用 If, Set, Code, SplitInBatches, Agent 等节点,结合人工智能技术实现智能自动化。 使用 @提及 的可扩展多代理聊天
前置要求
- •AI 服务 API Key(如 OpenAI、Anthropic 等)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "0QQxgdQABUbbDJ0G",
"meta": {
"instanceId": "c98909b50b05c4069bd93ee5a4753d07322c9680e81da8568e96de2c713adb5c"
},
"name": "多代理对话",
"tags": [],
"nodes": [
{
"id": "218308e2-dc68-43ee-ae84-d931ad7a4ac5",
"name": "当收到聊天消息时",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
-1880,
-3280
],
"webhookId": "a74752f3-419a-4510-856f-3efeaceec019",
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "a519fe1e-8739-46e0-9770-deb256ab96cf",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-340,
-3280
],
"parameters": {
"text": "={{ $json.chatInput }}",
"options": {
"systemMessage": "=Current date is {{ $now.format('yyyy-MM-dd') }}. The current time is {{ $now.format('HH:MM:ss') }}.\n\nThe user is {{ $('Define Global Settings').item.json.user.name }}, based in {{ $('Define Global Settings').item.json.user.location }}. {{ $('Define Global Settings').item.json.user.notes }}\n\nYou are part of a conversation with a user and multiple AI Assistants: {{ $('Define Agent Settings').item.json.keys() }}\n\nYou are {{ $('First loop?').item.json.name }}.\n\n{{ $('Loop Over Items').item.json.systemMessage }}\n\n{{ $('Define Global Settings').item.json.global.systemMessage }}"
},
"promptType": "define"
},
"typeVersion": 1.8
},
{
"id": "2e00f0ff-e7af-45d5-99bc-23031b5d7892",
"name": "遍历项目",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1000,
-3280
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "1c979a20-46a5-4591-92da-82c1c96277c6",
"name": "提取提及",
"type": "n8n-nodes-base.code",
"position": [
-1220,
-3280
],
"parameters": {
"jsCode": "// Analyzes the user message and extracts @mentions in the order they appear. If there are none, all Assistants will be called in random order.\n// --- Configuration: Adjust these lines ---\nconst chatMessageNodeName = 'When chat message received'; // <-- Replace with your Chat Message node name\nconst agentSetupNodeName = 'Define Agent Settings'; // <-- Replace with your Agent Setup node name\nconst chatTextPath = 'json.chatInput'; // <-- Replace with path to text in Chat node output (e.g., 'json.message')\n// --- End Configuration ---\n\n// Helper function for safe nested property access (alternative to _.get)\nfunction getSafe(obj, path, defaultValue = undefined) {\n const pathParts = path.split('.');\n let current = obj;\n for (const part of pathParts) {\n if (current === null || current === undefined || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, part)) {\n return defaultValue;\n }\n current = current[part];\n }\n return current ?? defaultValue;\n}\n\n// 1. Get Chat Text\nconst chatMessageNode = $(chatMessageNodeName);\nconst chatText = getSafe(chatMessageNode.item, chatTextPath, '');\n\n// 2. Get Agent Data and Names\nconst agentSetupNode = $(agentSetupNodeName);\nconst agentData = getSafe(agentSetupNode.item, 'json', {}); // e.g., { Chad: {...}, Gemma: {...}, Claude: {...} }\nconst agentNames = Object.keys(agentData);\n\n// 3. Find all mentions, their names, and their positions in the text\nconst foundMentions = [];\nif (chatText && agentNames.length > 0) {\n const escapeRegex = (s) => s.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n const agentPatternPart = agentNames.map(escapeRegex).join('|');\n\n if (agentPatternPart) {\n const mentionPattern = new RegExp(`\\\\B@(${agentPatternPart})\\\\b`, 'gi');\n const matches = chatText.matchAll(mentionPattern);\n\n for (const match of matches) {\n const matchedNameCaseInsensitive = match[1];\n const matchIndex = match.index;\n const canonicalName = agentNames.find(name => name.toLowerCase() === matchedNameCaseInsensitive.toLowerCase());\n if (canonicalName) {\n foundMentions.push({ name: canonicalName, index: matchIndex });\n }\n }\n }\n}\n\n// 4. Sort the found mentions by their index (order of appearance)\nfoundMentions.sort((a, b) => a.index - b.index);\n\n// 5. Map the sorted mentions to the desired output format (array of agent detail objects)\nlet outputArray = foundMentions.map(mention => {\n const agentDetails = agentData[mention.name];\n if (!agentDetails) {\n console.warn(`Could not find details for agent: ${mention.name}`);\n return null;\n }\n return {\n name: agentDetails.name,\n model: agentDetails.model,\n systemMessage: agentDetails.systemMessage\n };\n}).filter(item => item !== null);\n\n// 6. Check if any mentions were specifically found. If not, populate outputArray with ALL agents in RANDOM order.\nif (outputArray.length === 0 && foundMentions.length === 0) { // Check if NO mentions were found initially\n // --- NO MENTIONS FOUND ---\n // Populate outputArray with ALL agents from agentData\n const allAgentDetailsArray = Object.values(agentData);\n\n // --- Simple Randomization ---\n // Shuffle the array in place using sort with a random comparator\n allAgentDetailsArray.sort(() => 0.5 - Math.random());\n // --- End Randomization ---\n\n // Map all agents (now in random order) to the output structure\n outputArray = allAgentDetailsArray.map(agentObject => ({\n name: agentObject.name,\n model: agentObject.model,\n systemMessage: agentObject.systemMessage\n }));\n} // Intentionally no 'else' here, if outputArray already had items from mentions, we use that.\n\n// 7. Final Output Formatting (Handles both cases: specific mentions OR all agents)\n// Check if, after everything, the outputArray is *still* empty (e.g., if agentData was empty initially)\nif (outputArray.length === 0) {\n // If still empty, return a status or error as a fallback\n return [{ json: { status: \"no_agents_available\", message: \"No mentions found and no agents defined.\" } }];\n} else {\n // Return the array of agent objects formatted for n8n (multiple items)\n return outputArray.map(agentObject => ({ json: agentObject }));\n}"
},
"typeVersion": 2
},
{
"id": "45f635ca-f4fa-4f6c-a32a-9722906255fd",
"name": "简单记忆",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-192,
-3060
],
"parameters": {
"sessionKey": "={{ $('When chat message received').first().json.sessionId }}",
"sessionIdType": "customKey",
"contextWindowLength": 99
},
"typeVersion": 1.3
},
{
"id": "5c903044-bce2-4aa8-b168-a460a4999c54",
"name": "将最后一条助手消息设置为输入",
"type": "n8n-nodes-base.set",
"position": [
-560,
-3180
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "38aa959a-e1e5-4c84-a7bd-ff5e0f61b62d",
"name": "=chatInput",
"type": "string",
"value": "={{ $('Set lastAssistantMessage').first().json.lastAssistantMessage }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "7b389b9f-1751-4bc1-9c6f-bf6a04a1e09f",
"name": "将用户消息设置为输入",
"type": "n8n-nodes-base.set",
"position": [
-560,
-3380
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "75b61275-7526-4431-b624-f8e098aa812d",
"name": "chatInput",
"type": "string",
"value": "={{ $('When chat message received').item.json.chatInput }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a238817f-0d10-4cd4-9760-53f69bb179f7",
"name": "首次循环?",
"type": "n8n-nodes-base.if",
"position": [
-780,
-3280
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "51c41fdf-f4d3-4c7a-ac18-06815a59a958",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $runIndex}}",
"rightValue": 0
}
]
}
},
"typeVersion": 2.2
},
{
"id": "415927d7-b1a4-42b2-9607-c6ff707a528b",
"name": "设置最后助手消息",
"type": "n8n-nodes-base.set",
"position": [
36,
-3155
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b93025b2-f5a7-476b-bd09-b5b4af050e73",
"name": "lastAssistantMessage",
"type": "string",
"value": "=**{{ $('Loop Over Items').item.json.name }}**:\n\n{{ $json.output }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "77861e4b-a1d2-4c35-bf50-15914602a8b5",
"name": "合并并格式化响应",
"type": "n8n-nodes-base.code",
"position": [
-780,
-3480
],
"parameters": {
"jsCode": "// Get the array of items from the input (output of the loop)\nconst inputItems = items;\n\n// Extract the 'lastAssistantMessage' from each item's JSON data.\n// If the field is missing or not a string, use an empty string to avoid errors.\nconst messages = inputItems.map(item => {\n const message = item.json.lastAssistantMessage;\n return typeof message === 'string' ? message : '';\n});\n\n// Join the extracted messages together with a horizontal rule separator\nconst combinedText = messages.join('\\n\\n---\\n\\n');\n\n// Return a new single item containing the combined text.\n// You can rename 'output' if you like.\nreturn [{ json: { output: combinedText } }];"
},
"typeVersion": 2
},
{
"id": "4da2f95d-bce4-4844-a23c-63ca777efbfd",
"name": "定义全局设置",
"type": "n8n-nodes-base.code",
"position": [
-1660,
-3280
],
"parameters": {
"jsCode": "// Configure Global settings. This includes information about you - the user - and a section of the System Message that all Assistants will see. (Assistant-specific System Message sections can be set in the 'Define Agent Settings' node.)\nreturn [\n {\n json: {\n \"user\": {\n \"name\": \"Jon\",\n \"location\": \"Melbourne, Australia\",\n \"notes\": \"Jon likes a casual, informal conversation style.\"\n },\n \"global\": {\n \"systemMessage\": \"Don't overdo the helpful, agreeable approach.\"\n }\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "6639a554-9e5f-40ac-b68e-b8eaa777252d",
"name": "定义代理设置",
"type": "n8n-nodes-base.code",
"position": [
-1440,
-3280
],
"parameters": {
"jsCode": "// Configure Assistants. The number of Assistants can be changed by adding or removing JSON objects. Use the OpenRouter model naming convention.\nreturn [\n {\n json: {\n \"Chad\": {\n \"name\": \"Chad\",\n \"model\": \"openai/gpt-4o\",\n \"systemMessage\": \"You are a helpful Assistant. You are eccentric and creative, and try to take discussions into unexpected territory.\"\n },\n \"Claude\": {\n \"name\": \"Claude\",\n \"model\": \"anthropic/claude-3.7-sonnet\",\n \"systemMessage\": \"You are logical and practical.\"\n },\n \"Gemma\": {\n \"name\": \"Gemma\",\n \"model\": \"google/gemini-2.0-flash-lite-001\",\n \"systemMessage\": \"You are super friendly and love to debate.\"\n }\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "d55a7e02-3574-4d78-a141-db8d3657857b",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1750,
-3620
],
"parameters": {
"color": 4,
"width": 500,
"height": 500,
"content": "## 步骤 1:配置设置节点"
},
"typeVersion": 1
},
{
"id": "d3eb2797-4008-4bdb-a588-b2412ed5ffa7",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
-3620
],
"parameters": {
"color": 4,
"width": 360,
"height": 720,
"content": "## 步骤 2:将代理连接到 OpenRouter"
},
"typeVersion": 1
},
{
"id": "a6085a55-db36-42d8-8c57-c9123490581f",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1940,
-3900
],
"parameters": {
"color": 5,
"width": 2180,
"height": 1100,
"content": "# 可扩展的多代理对话"
},
"typeVersion": 1
},
{
"id": "d2ee6317-3a9c-4df8-8fce-87daa3530233",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1200,
-3860
],
"parameters": {
"width": 380,
"height": 360,
"content": "## 关于此工作流"
},
"typeVersion": 1
},
{
"id": "a190a268-7f90-4c4e-aceb-482545d0b72b",
"name": "便签4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-820,
-3860
],
"parameters": {
"width": 380,
"height": 360,
"content": "**它是如何工作的?**"
},
"typeVersion": 1
},
{
"id": "30d8c207-9a7a-46c5-be89-0deafc6c183f",
"name": "OpenRouter 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
-312,
-3060
],
"parameters": {
"model": "={{ $('Extract mentions').item.json.model }}",
"options": {}
},
"credentials": {
"openRouterApi": {
"id": "jB56IT6KRdHSBbkw",
"name": "OpenRouter account"
}
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "6c0312e7-7a81-41cd-9403-8ad947100b80",
"connections": {
"AI Agent": {
"main": [
[
{
"node": "Set lastAssistantMessage",
"type": "main",
"index": 0
}
]
]
},
"First loop?": {
"main": [
[
{
"node": "Set user message as input",
"type": "main",
"index": 0
}
],
[
{
"node": "Set last Assistant message as input",
"type": "main",
"index": 0
}
]
]
},
"Simple Memory": {
"ai_memory": [
[
{
"node": "AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Combine and format responses",
"type": "main",
"index": 0
}
],
[
{
"node": "First loop?",
"type": "main",
"index": 0
}
]
]
},
"Extract mentions": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Define Agent Settings": {
"main": [
[
{
"node": "Extract mentions",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Define Global Settings": {
"main": [
[
{
"node": "Define Agent Settings",
"type": "main",
"index": 0
}
]
]
},
"Set lastAssistantMessage": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Set user message as input": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Define Global Settings",
"type": "main",
"index": 0
}
]
]
},
"Combine and format responses": {
"main": [
[]
]
},
"Set last Assistant message as input": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 构建模块, 人工智能
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
代理构建器
使用GPT-4o、RAG和网络搜索自动构建自定义工作流
If
Set
Code
+14
33 节点Franz
构建模块
完成YouTube
基于细分领域的AI YouTube趋势发现器
If
Set
Code
+10
18 节点Leonardo Grigorio
人工智能
基于AI的MIS代理
基于AI的管理信息系统代理
If
Set
Code
+29
129 节点Kumar Shivam
客户支持
基于语义和结构化RAG的电子邮件聊天机器人,使用Telegram和Pgvector
使用Telegram、Mistral和Pgvector的RAG技术与您的邮件历史对话
If
Set
Code
+12
20 节点Alfonso Corretti
客户支持
LinkedIn人才管道:AI驱动的候选人搜索与排名(GPT-4o)
LinkedIn人才管道:AI驱动的候选人搜索与排名(GPT-4o)
If
Set
Code
+14
24 节点Badr
人力资源
高级AI演示(在AI开发者第14次聚会中展示)
高级AI演示(在AI开发者第14次聚会中展示)
If
Code
Gmail
+19
39 节点Max Tkacz
构建模块