使用AI验证GitHub配置并将问题记录到表格和Slack
高级
这是一个DevOps, AI Summarization领域的自动化工作流,包含 22 个节点。主要使用 Code, Merge, Slack, Github, GoogleSheets 等节点。 使用GPT-4o-mini验证GitHub配置并将问题记录到表格和Slack
前置要求
- •Slack Bot Token 或 Webhook URL
- •GitHub Personal Access Token
- •Google Sheets API 凭证
- •OpenAI API Key
使用的节点 (22)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "NDAfOVpefnu0AO5l",
"meta": {
"instanceId": "8443f10082278c46aa5cf3acf8ff0f70061a2c58bce76efac814b16290845177",
"templateCredsSetupCompleted": true
},
"name": "使用 AI 验证 GitHub 配置并将问题记录到表格和 Slack",
"tags": [],
"nodes": [
{
"id": "00b8e7a5-b837-42dc-af23-9a2d06336a56",
"name": "工作流概览",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1600,
-352
],
"parameters": {
"color": 4,
"width": 420,
"height": 520,
"content": "## 🔍 GitHub 配置验证器"
},
"typeVersion": 1
},
{
"id": "22574d71-89eb-4872-a6ec-17127c7c13ac",
"name": "设置指南",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2000,
-336
],
"parameters": {
"color": 2,
"width": 380,
"height": 540,
"content": "## ⚙️ 设置说明"
},
"typeVersion": 1
},
{
"id": "54dbfff3-2cfb-4e0f-92de-eeb8ad467ef4",
"name": "触发器配置",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1152,
-432
],
"parameters": {
"color": 2,
"width": 320,
"height": 332,
"content": "## 🎯 GitHub Webhook 触发器"
},
"typeVersion": 1
},
{
"id": "eabed35d-8708-4e30-9f50-de35746032b3",
"name": "文件获取逻辑",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
176
],
"parameters": {
"color": 2,
"width": 300,
"height": 320,
"content": "## 📂 文件获取"
},
"typeVersion": 1
},
{
"id": "7a19688d-84bd-4c7c-98bd-6649a0192ed4",
"name": "合并策略",
"type": "n8n-nodes-base.stickyNote",
"position": [
-512,
-480
],
"parameters": {
"color": 2,
"width": 280,
"height": 360,
"content": "## 🔀 数据合并"
},
"typeVersion": 1
},
{
"id": "a446599d-12b9-4438-8795-e2b93b9a026d",
"name": "AI 分析详情",
"type": "n8n-nodes-base.stickyNote",
"position": [
-160,
-480
],
"parameters": {
"color": 2,
"width": 300,
"height": 372,
"content": "## 🤖 AI 配置分析"
},
"typeVersion": 1
},
{
"id": "93354c1a-1de0-44ab-808f-cf9ddbcc1b07",
"name": "数据处理",
"type": "n8n-nodes-base.stickyNote",
"position": [
208,
-448
],
"parameters": {
"color": 2,
"width": 300,
"height": 344,
"content": "## 📊 结果处理"
},
"typeVersion": 1
},
{
"id": "ee3b404c-ee6c-44d7-9123-c90b351f8160",
"name": "表格配置",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
64
],
"parameters": {
"color": 2,
"width": 320,
"height": 388,
"content": "## 📝 Google Sheets 架构"
},
"typeVersion": 1
},
{
"id": "133a9c1b-749f-4114-84ed-a23fd3e77d86",
"name": "Slack 警报",
"type": "n8n-nodes-base.stickyNote",
"position": [
672,
-496
],
"parameters": {
"color": 2,
"width": 300,
"height": 408,
"content": "## 💬 Slack 通知"
},
"typeVersion": 1
},
{
"id": "edf48d61-2eff-4e52-91c8-1ff181c99a4c",
"name": "GitHub 推送或 PR 事件",
"type": "n8n-nodes-base.githubTrigger",
"position": [
-1088,
-96
],
"webhookId": "8269983f-8b5a-4f61-87a7-fb4e58e11b6c",
"parameters": {
"owner": {
"__rl": true,
"mode": "url",
"value": "={{ $json.githubOwner }}"
},
"events": [
"pull_request",
"push"
],
"options": {},
"repository": {
"__rl": true,
"mode": "id",
"value": "={{ $json.githubRepo }}"
},
"authentication": "oAuth2"
},
"credentials": {
"githubOAuth2Api": {
"id": "Ih8web2ia8dlggr6",
"name": "GitHub account vivek"
}
},
"typeVersion": 1
},
{
"id": "88bcabe0-4557-4f16-bba2-8e0523853fa3",
"name": "获取仓库配置",
"type": "n8n-nodes-base.github",
"position": [
-864,
-192
],
"webhookId": "9ad4450b-f494-4026-9ac9-d78c90169881",
"parameters": {
"owner": {
"__rl": true,
"mode": "url",
"value": "={{ $json.repository.owner.login }}"
},
"filePath": "config/app-config.json",
"resource": "file",
"operation": "get",
"repository": {
"__rl": true,
"mode": "id",
"value": "={{ $json.repository.name }}"
},
"authentication": "oAuth2",
"additionalParameters": {}
},
"credentials": {
"githubOAuth2Api": {
"id": "Ih8web2ia8dlggr6",
"name": "GitHub account vivek"
}
},
"typeVersion": 1
},
{
"id": "fe9f94a2-d9c9-4b51-832c-ae018daa821e",
"name": "获取 FAQ 引用配置",
"type": "n8n-nodes-base.github",
"position": [
-864,
0
],
"webhookId": "b63918a7-17bc-4934-9007-3c8aa0b7aee9",
"parameters": {
"owner": {
"__rl": true,
"mode": "url",
"value": "={{ $json.repository.owner.login }}"
},
"filePath": "faq-config.json",
"resource": "file",
"operation": "get",
"repository": {
"__rl": true,
"mode": "id",
"value": "={{ $json.repository.name }}"
},
"authentication": "oAuth2",
"additionalParameters": {}
},
"credentials": {
"githubOAuth2Api": {
"id": "Ih8web2ia8dlggr6",
"name": "GitHub account vivek"
}
},
"typeVersion": 1
},
{
"id": "aaf24ba6-6338-4cd7-8451-b4add12fff46",
"name": "解析仓库配置 JSON",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-640,
-192
],
"parameters": {
"options": {},
"operation": "fromJson"
},
"typeVersion": 1
},
{
"id": "de433781-a62a-41e8-af75-6f659cc0bee6",
"name": "解析 FAQ 配置 JSON",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-640,
0
],
"parameters": {
"options": {},
"operation": "fromJson"
},
"typeVersion": 1
},
{
"id": "136b7b5e-c6c8-42db-ba9f-fea68d9e3db4",
"name": "合并配置文件",
"type": "n8n-nodes-base.merge",
"position": [
-416,
-96
],
"parameters": {
"mode": "combine",
"options": {}
},
"typeVersion": 3
},
{
"id": "1e9f58bd-32a7-4652-a224-08a013ad656e",
"name": "AI 配置比较代理",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-128,
-96
],
"parameters": {
"text": "=You are comparing two configuration files:\n\n**Repository Config (Actual):**\n```json\n{{ JSON.stringify($json[0], null, 2) }}\n```\n\n**FAQ Reference Config (Expected):**\n```json\n{{ JSON.stringify($json[1], null, 2) }}\n```\n\n**Task:**\nCompare both configs and identify all discrepancies. For each issue, provide:\n- Unique ID\n- Config key path\n- Expected value (from FAQ)\n- Actual value (from repo)\n- Issue type (mismatch, missing, deprecated, type_error, security)\n- Severity (critical, high, medium, low)\n- Clear recommendation\n- Confidence score (0.0-1.0)\n\n**Important:**\n- Return ONLY valid JSON (no markdown, no extra text)\n- Use the exact schema provided\n- If no issues found, return empty issues array\n- Focus on actionable discrepancies",
"options": {
"systemMessage": "You are an expert DevOps configuration auditor and automation specialist.\n\n**Your expertise:**\n- Deep knowledge of config file best practices\n- Security-first mindset for credentials and secrets\n- Understanding of environment-specific variations\n- Ability to distinguish critical vs cosmetic differences\n\n**Analysis approach:**\n1. Compare key-by-key between repo config and FAQ reference\n2. Identify missing keys, mismatched values, type changes\n3. Assess security implications (exposed secrets, weak settings)\n4. Determine business impact and urgency\n5. Provide specific, actionable recommendations\n\n**Severity guidelines:**\n- `critical`: Breaking changes, security vulnerabilities, missing required fields\n- `high`: Important mismatches affecting functionality\n- `medium`: Minor inconsistencies, deprecated but working\n- `low`: Cosmetic differences, optional improvements\n\n**Output requirements:**\n- Strict JSON format only\n- No markdown formatting\n- No explanatory text outside JSON\n- Clear, concise recommendations"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.1
},
{
"id": "f1dc1aff-caf8-4a0a-8c64-44fc69af9a22",
"name": "OpenAI GPT-4o-mini",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-192,
128
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "gpt-4o-mini"
},
"options": {
"maxTokens": 4000,
"temperature": 0.3
}
},
"credentials": {
"openAiApi": {
"id": "5Kzt6hGSZ1JHZqWN",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.2
},
{
"id": "460f00a4-afff-4d0d-a922-cf6a865a5cd0",
"name": "JSON 输出架构",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
80,
128
],
"parameters": {
"jsonSchemaExample": "{\n \"result\": \"success or issues_found\",\n \"summary\": \"Brief overview of findings\",\n \"issues\": [\n {\n \"id\": \"unique_issue_id\",\n \"key\": \"config.path.to.field\",\n \"repo_value\": \"actual value in repository\",\n \"faq_value\": \"expected value from FAQ\",\n \"type\": \"mismatch | missing | deprecated | type_error | security\",\n \"severity\": \"critical | high | medium | low\",\n \"recommendation\": \"Specific action to resolve\",\n \"confidence\": 0.95\n }\n ],\n \"metadata\": {\n \"checked_at\": \"ISO timestamp\",\n \"comparison_source\": \"faq-config.json\"\n }\n}"
},
"typeVersion": 1.3
},
{
"id": "f50d6106-4931-46ce-b0ec-c816c1e25c8b",
"name": "对话记忆",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-64,
128
],
"parameters": {
"sessionKey": "=\"config_validation_\" & $('GitHub Push or PR Event').item.json.repository.name",
"sessionIdType": "customKey",
"contextWindowLength": 3
},
"typeVersion": 1.3
},
{
"id": "b40a6c22-c78e-43ba-90c6-2db71c74fe02",
"name": "格式化问题以供记录",
"type": "n8n-nodes-base.code",
"position": [
288,
-96
],
"parameters": {
"jsCode": "// Extract and format AI comparison results for Google Sheets\nconst allItems = $input.all();\nlet issues = [];\n\ntry {\n for (const item of allItems) {\n const aiResponse = item.json;\n \n // Handle different output structures\n let outputData;\n if (aiResponse.output) {\n outputData = [aiResponse.output];\n } else if (Array.isArray(aiResponse)) {\n outputData = aiResponse.map(entry => entry.output || entry);\n } else {\n outputData = [aiResponse];\n }\n\n // Process each output entry\n for (const output of outputData) {\n if (output.issues && Array.isArray(output.issues) && output.issues.length > 0) {\n \n // Map issues to Google Sheets format\n const mappedIssues = output.issues.map(issue => ({\n timestamp: new Date().toISOString(),\n configKey: issue.key || 'N/A',\n faqReference: issue.faq_value || 'N/A',\n actualConfig: issue.repo_value || 'N/A',\n issueType: issue.type || 'unknown',\n severity: issue.severity || 'N/A',\n suggestion: issue.recommendation || 'N/A',\n confidence: issue.confidence ? issue.confidence.toFixed(2) : 'N/A',\n issueId: issue.id || `issue_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n summary: output.summary || 'No summary provided'\n }));\n \n issues.push(...mappedIssues);\n }\n }\n }\n\n // Handle case when no issues found\n if (issues.length === 0) {\n issues = [{\n timestamp: new Date().toISOString(),\n configKey: 'No Issues',\n faqReference: 'N/A',\n actualConfig: 'N/A',\n issueType: 'success',\n severity: 'N/A',\n suggestion: 'All configurations match FAQ reference',\n confidence: '1.00',\n issueId: `success_${Date.now()}`,\n summary: '✅ No discrepancies found - configs are in sync'\n }];\n }\n\n} catch (error) {\n // Error handling\n console.error('Error processing AI output:', error);\n issues = [{\n timestamp: new Date().toISOString(),\n configKey: 'Processing Error',\n faqReference: 'Could not parse AI response',\n actualConfig: error.message,\n issueType: 'error',\n severity: 'high',\n suggestion: `Review AI output manually. Error: ${error.message}`,\n confidence: 'N/A',\n issueId: `error_${Date.now()}`,\n summary: '⚠️ Processing error occurred during validation'\n }];\n}\n\n// Return formatted data for Google Sheets\nreturn issues.map(issue => ({ json: issue }));"
},
"typeVersion": 2
},
{
"id": "be1fa800-8b48-4d21-a953-da7e3fc34eeb",
"name": "记录到Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
512,
-96
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "configKey",
"type": "string",
"display": true,
"required": false,
"displayName": "configKey",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "faqReference",
"type": "string",
"display": true,
"required": false,
"displayName": "faqReference",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "actualConfig",
"type": "string",
"display": true,
"required": false,
"displayName": "actualConfig",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "issueType",
"type": "string",
"display": true,
"required": false,
"displayName": "issueType",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "severity",
"type": "string",
"display": true,
"required": false,
"displayName": "severity",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "suggestion",
"type": "string",
"display": true,
"required": false,
"displayName": "suggestion",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "confidence",
"type": "string",
"display": true,
"required": false,
"displayName": "confidence",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "issueId",
"type": "string",
"display": true,
"required": false,
"displayName": "issueId",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "summary",
"type": "string",
"display": true,
"required": false,
"displayName": "summary",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Config Discrepancies"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Workflow Overview').item.json.googleSheetId }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "kpPEOLCGn963qpoh",
"name": "automations@techdome.ai"
}
},
"typeVersion": 4.7
},
{
"id": "4df1bf84-2753-4472-aef7-4623439bfcf0",
"name": "发送 Slack 警报",
"type": "n8n-nodes-base.slack",
"position": [
736,
-96
],
"webhookId": "ef90cacf-14c2-48cc-905f-b06d2c649b8d",
"parameters": {
"text": "=⚠️ *Config Mismatch Detected!*\n\n*Repository:* {{ $('GitHub Push or PR Event').item.json.repository.full_name }}\n*Branch:* {{ $('GitHub Push or PR Event').item.json.ref }}\n*Commit:* {{ $('GitHub Push or PR Event').item.json.after.substring(0, 7) }}\n\n━━━━━━━━━━━━━━━━━━━━\n\n{{ $('Format Issues for Logging').all().slice(0, 3).map((item, idx) => {\n const severity = item.json.severity;\n const emoji = severity === 'critical' ? '🔴' : severity === 'high' ? '🟠' : severity === 'medium' ? '🟡' : '🟢';\n return `${emoji} *Issue ${idx + 1}: ${item.json.configKey}*\\n• Type: ${item.json.issueType}\\n• Severity: ${item.json.severity}\\n• Expected: \\`${item.json.faqReference}\\`\\n• Actual: \\`${item.json.actualConfig}\\`\\n• Fix: ${item.json.suggestion}\\n`;\n}).join('\\n') }}\n\n*Total Issues:* {{ $('Format Issues for Logging').all().length }}\n\n📊 *Full Report:* <{{ $('Workflow Overview').item.json.sheetsReportUrl }}|View in Google Sheets>\n\n_Scanned: {{ new Date().toLocaleString('en-US', { timeZone: 'UTC' }) }} UTC_",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Workflow Overview').item.json.slackChannel }}"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "rNqvWj9TfChPVRYY",
"name": "Slack account vivek"
}
},
"typeVersion": 2.2
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "f61bd7be-e6be-425b-8929-bc5536255b8f",
"connections": {
"JSON Output Schema": {
"ai_outputParser": [
[
{
"node": "AI Config Comparison Agent",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Merge Config Files": {
"main": [
[
{
"node": "AI Config Comparison Agent",
"type": "main",
"index": 0
}
]
]
},
"OpenAI GPT-4o-mini": {
"ai_languageModel": [
[
{
"node": "AI Config Comparison Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Conversation Memory": {
"ai_memory": [
[
{
"node": "AI Config Comparison Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Log to Google Sheets": {
"main": [
[
{
"node": "Send Slack Alert",
"type": "main",
"index": 0
}
]
]
},
"Parse FAQ Config JSON": {
"main": [
[
{
"node": "Merge Config Files",
"type": "main",
"index": 1
}
]
]
},
"Parse Repo Config JSON": {
"main": [
[
{
"node": "Merge Config Files",
"type": "main",
"index": 0
}
]
]
},
"Fetch Repository Config": {
"main": [
[
{
"node": "Parse Repo Config JSON",
"type": "main",
"index": 0
}
]
]
},
"GitHub Push or PR Event": {
"main": [
[
{
"node": "Fetch Repository Config",
"type": "main",
"index": 0
},
{
"node": "Fetch FAQ Reference Config",
"type": "main",
"index": 0
}
]
]
},
"Format Issues for Logging": {
"main": [
[
{
"node": "Log to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"AI Config Comparison Agent": {
"main": [
[
{
"node": "Format Issues for Logging",
"type": "main",
"index": 0
}
]
]
},
"Fetch FAQ Reference Config": {
"main": [
[
{
"node": "Parse FAQ Config JSON",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 开发运维, AI 摘要总结
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
构建基于AI的API错误目录:从GitHub到Airtable、Notion和Slack
使用GPT-4o自动检测和分类GitHub API错误至Airtable、Notion和Slack
If
Set
Code
+11
30 节点Rahul Joshi
工单管理
使用GPT-4从Figma设计生成QA测试用例到Google Sheets
使用GPT-4o-mini从Figma设计生成QA测试用例到Google Sheets
Code
Http Request
Google Sheets
+6
14 节点Rahul Joshi
工程
[astro/nextjs] 为文章/帖子分配类别/标签
使用OpenAI GPT-4、GitHub和Google Sheets为Astro/Next.js博客文章自动分类
Code
Form
Merge
+11
29 节点Piotr Sikora
内容创作
TalentFlow AI - 批量简历筛选与职位描述匹配
使用GPT-4为HR团队进行批量简历筛选与职位描述匹配
If
Code
Merge
+12
30 节点Trung Tran
人力资源
自动化依赖更新跟踪
使用 GPT-4o、Slack、Jira 和 Google Sheets 进行依赖更新风险分析
If
Set
Code
+8
23 节点Rahul Joshi
开发运维
HireMind – AI驱动的简历智能处理流程
HR AI简历筛选与评估:GPT-4和Google Workspace
If
Code
Slack
+10
26 节点Trung Tran
人力资源
工作流信息
难度等级
高级
节点数量22
分类2
节点类型12
作者
Rahul Joshi
@rahul08Rahul Joshi is a seasoned technology leader specializing in the n8n automation tool and AI-driven workflow automation. With deep expertise in building open-source workflow automation and self-hosted automation platforms, he helps organizations eliminate manual processes through intelligent n8n ai agent automation solutions.
外部链接
在 n8n.io 查看 →
分享此工作流