人员流失风险预警工作流(Azure OpenAI + n8n)
高级
这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 16 个节点。主要使用 If, Code, Gmail, GoogleDrive, Agent 等节点。 员工流失风险检测与HR提醒,使用Azure OpenAI GPT-4o-mini和Gmail
前置要求
- •Google 账号和 Gmail API 凭证
- •Google Drive API 凭证
- •OpenAI API Key
使用的节点 (16)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "ONqZuWnwkE64Mm4F",
"meta": {
"instanceId": "8443f10082278c46aa5cf3acf8ff0f70061a2c58bce76efac814b16290845177",
"templateCredsSetupCompleted": true
},
"name": "人员流失风险预警工作流 (Azure OpenAI + n8n)",
"tags": [],
"nodes": [
{
"id": "c48bef67-a0d0-4a4b-a374-3df1a7ed4c19",
"name": "Azure OpenAI聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
688,
128
],
"parameters": {
"model": "gpt-4o-mini",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"id": "C3WzT18XqF8OdVM6",
"name": "Azure Open AI account"
}
},
"typeVersion": 1
},
{
"id": "a44062d6-1e37-443b-b146-cf32a9ac74cc",
"name": "结构化输出解析器",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
816,
128
],
"parameters": {
"jsonSchemaExample": "{\n\t\"average\": \"18\"\n}"
},
"typeVersion": 1.3
},
{
"id": "2ab2bd76-1809-4015-9d99-a278561287da",
"name": "新简历触发器",
"type": "n8n-nodes-base.googleDriveTrigger",
"position": [
0,
-96
],
"parameters": {
"event": "fileCreated",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "1KyX5RGqeF7v0sAvvaoBnJPTQoq4aOHLz",
"cachedResultUrl": "https://drive.google.com/drive/folders/1KyX5RGqeF7v0sAvvaoBnJPTQoq4aOHLz",
"cachedResultName": "HR auto"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "gPmEPTuQP4KLm1KD",
"name": "jyothi"
}
},
"typeVersion": 1
},
{
"id": "dabfc101-cfa3-43e6-b568-320c1c2d3e92",
"name": "下载简历",
"type": "n8n-nodes-base.googleDrive",
"position": [
224,
-96
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "url",
"value": "={{ $json.webViewLink }}"
},
"options": {},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "gPmEPTuQP4KLm1KD",
"name": "jyothi"
}
},
"typeVersion": 3
},
{
"id": "821c7e31-be41-4e6c-b58b-19a2cf880648",
"name": "提取文本",
"type": "n8n-nodes-base.extractFromFile",
"position": [
448,
-96
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "78f8966f-dbeb-4773-b198-9dfb13defd35",
"name": "计算平均跨度",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
672,
-96
],
"parameters": {
"text": "={{ $json.text }}",
"options": {
"systemMessage": "You are given resume text as input. Your task is to extract employment experiences and return ONLY the average tenure (in months) across those experiences as a single number.\n\nInstructions:\n- Scope: Consider only professional employment entries under Experience (exclude Education, Projects, Achievements, Certifications, Skills, Languages).\n- Grouping: Treat each distinct job/employer entry as one experience. If multiple roles at the same employer have separate date ranges, treat each as separate experiences.\n- Dates:\n - Parse start and end dates in formats like \"MMM YYYY\", \"Month YYYY\", \"YYYY\", or date ranges using -, –, —.\n - If the end date is \"Present\"/current, use today's date.\n - If a date has only a year, assume the month as January.\n - If a start or end month/day is missing, default to the first day of that month.\n- Duration Calculation:\n - Compute the difference in full months for each experience (start inclusive, end exclusive).\n - Do not deduct overlaps; each listed experience is counted independently.\n - Exclude entries without any valid start date.\n- Averaging:\n - Compute the arithmetic mean of the months across all valid experiences.\n - Round to the nearest whole month (standard rounding).\n\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "5e697388-e418-495e-b91f-5eba9deb0427",
"name": "",
"type": "n8n-nodes-base.if",
"position": [
1024,
-96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "21c98617-ba35-4906-afd0-38a82211dbe7",
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.output.average.toNumber() }}",
"rightValue": 12
}
]
}
},
"typeVersion": 2.2
},
{
"id": "93b32316-47a7-4769-8a82-289a4c66c73f",
"name": "Create email",
"type": "n8n-nodes-base.code",
"position": [
1248,
-96
],
"parameters": {
"jsCode": "// filename: n8n-code-node-attrition-email.js\n// This Code node builds an email for each item indicating high attrition risk.\n// Output fields:\n// - emailSubject\n// - emailBody\n// - emailTo (optional if you want to set here)\n// - emailCc (optional)\n// - emailMetadata (structured data for downstream logging)\n\nfunction formatDate(dateStr) {\n if (!dateStr) return \"N/A\";\n const d = new Date(dateStr);\n if (isNaN(d.getTime())) return dateStr;\n // Format as YYYY-MM-DD for clarity\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nfunction clampScore(score) {\n const n = Number(score);\n if (Number.isNaN(n)) return null;\n return Math.max(0, Math.min(100, n));\n}\n\nfunction classifyRisk(score) {\n if (score == null) return \"Unknown\";\n if (score >= 80) return \"High\";\n if (score >= 50) return \"Medium\";\n return \"Low\";\n}\n\nfunction bulletList(items) {\n if (!Array.isArray(items) || items.length === 0) return \"- None\";\n return items.map(s => `- ${String(s).trim() || \"N/A\"}`).join(\"\\n\");\n}\n\nconst outputs = [];\n\nfor (const item of $input.all()) {\n const j = item.json || {};\n\n const personName = j.personName || j.name || \"The employee\";\n const role = j.role || \"N/A\";\n const department = j.department || null;\n const managerName = j.managerName || \"HR/People Ops\";\n const riskScoreRaw = j.riskScore ?? j.attritionRiskScore;\n const riskScore = clampScore(riskScoreRaw);\n const riskLevel = classifyRisk(riskScore);\n const signals = Array.isArray(j.signals) ? j.signals : [];\n const lastEngagementDate = formatDate(j.lastEngagementDate || j.lastCheckInDate);\n const recommendedActions = Array.isArray(j.recommendedActions) ? j.recommendedActions : [\n \"Schedule a 1:1 check‑in within the next 3–5 days\",\n \"Offer growth or role‑clarity conversation\",\n \"Review workload and compensation alignment\",\n ];\n\n // Email routing (optional; you can also set these in the Email node)\n const emailTo = j.emailTo || j.managerEmail || j.hrEmail || \"\";\n const emailCc = j.emailCc || \"\";\n\n // Compose subject\n const subjectParts = [\n \"[Attrition Alert]\",\n personName !== \"The employee\" ? personName : \"Employee\",\n riskLevel !== \"Unknown\" ? `– ${riskLevel} Risk (${riskScore}%)` : \"– Risk Review\",\n ];\n const emailSubject = subjectParts.filter(Boolean).join(\" \");\n\n // Compose body (plain text; you can convert to HTML if preferred)\n const headerLine = `${personName} ${role !== \"N/A\" ? `(${role})` : \"\"}${department ? `, ${department}` : \"\"}`;\n const riskLine = `Attrition Risk: ${riskLevel}${riskScore != null ? ` (${riskScore}%)` : \"\"}`;\n const signalsBlock = bulletList(signals);\n const actionsBlock = bulletList(recommendedActions);\n\n const emailBody =\n`Hi ${managerName},\n\nThis is a heads‑up that ${headerLine} may be at risk of leaving soon. ${riskLine}.\n\nKey signals observed:\n${signalsBlock}\n\nLast engagement/check‑in: ${lastEngagementDate}\n\nSuggested next steps:\n${actionsBlock}\n\nPlease prioritize a supportive outreach. If helpful, we can prepare a retention plan (growth discussion, workload review, recognition, and role clarity).\n\nThanks,\nPeople Analytics\n`;\n\n outputs.push({\n json: {\n ...j,\n emailSubject,\n emailBody,\n emailTo,\n emailCc,\n emailMetadata: {\n personName,\n role,\n department,\n managerName,\n riskScore,\n riskLevel,\n signals,\n lastEngagementDate,\n recommendedActions,\n generatedAt: new Date().toISOString(),\n },\n },\n });\n}\n\nreturn outputs;\n"
},
"typeVersion": 2
},
{
"id": "cc3e9d3e-4a29-4125-83bd-c43770219fca",
"name": "Send email to hr",
"type": "n8n-nodes-base.gmail",
"position": [
1472,
-96
],
"webhookId": "15c04fae-06e4-41c8-860d-020d07ca31f6",
"parameters": {
"sendTo": "jyothi.swarup@techdome.net.in",
"message": "={{ $json.emailBody }}",
"options": {},
"subject": "={{ $json.emailSubject }}"
},
"credentials": {
"gmailOAuth2": {
"id": "70f5n8rPahCANHs7",
"name": "jyothi"
}
},
"typeVersion": 2.1
},
{
"id": "860057d2-af64-4ea5-8df5-1945f27b52d2",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
-128
],
"parameters": {
"content": "## Trigger for new resume \nStarts the workflow when a new resume file is added (e.g., to storage or inbox)."
},
"typeVersion": 1
},
{
"id": "ce4d511d-b14d-4a13-ac97-a319e90b2d2a",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
128,
-304
],
"parameters": {
"content": "## Download resume \nFetches the resume file from the source and makes it available for processing."
},
"typeVersion": 1
},
{
"id": "dcf63ce0-b0f0-4ede-9c95-c7c37814b028",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
80
],
"parameters": {
"content": "## Extract text \nPulls readable text from the downloaded resume using a PDF extraction step."
},
"typeVersion": 1
},
{
"id": "114d70ee-1e49-41f4-937b-6b8e183d787b",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
656,
-304
],
"parameters": {
"content": "## Chat Model \nUses Azure OpenAI Chat to analyze or summarize the extracted resume content."
},
"typeVersion": 1
},
{
"id": "b5ee6f06-3ac8-402a-9051-f5ee0aaae094",
"name": "便签4",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
96
],
"parameters": {
"content": "## Logic \nApplies conditional checks and routing (true/false) based on parsed results."
},
"typeVersion": 1
},
{
"id": "e7fcd240-e008-419f-ac1b-e45593f3c037",
"name": "便利贴5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1168,
-320
],
"parameters": {
"content": "## Create email \nGenerates a tailored email draft to the candidate or HR using the parsed data."
},
"typeVersion": 1
},
{
"id": "e8aae9bd-426b-4020-8b47-f48bc35b1ae3",
"name": "便签 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1408,
96
],
"parameters": {
"content": "## Send email to hr \nSends the composed message to HR via the configured email service."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "a93f6021-cc9d-4249-b529-62a19a79292a",
"connections": {
"Logic": {
"main": [
[
{
"node": "Create email",
"type": "main",
"index": 0
}
]
]
},
"Create email": {
"main": [
[
{
"node": "Send email to hr",
"type": "main",
"index": 0
}
]
]
},
"Extract text": {
"main": [
[
{
"node": "Calculate avg span",
"type": "main",
"index": 0
}
]
]
},
"Download resume": {
"main": [
[
{
"node": "Extract text",
"type": "main",
"index": 0
}
]
]
},
"Calculate avg span": {
"main": [
[
{
"node": "Logic",
"type": "main",
"index": 0
}
]
]
},
"Trigger for new resume": {
"main": [
[
{
"node": "Download resume",
"type": "main",
"index": 0
}
]
]
},
"Azure OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Calculate avg span",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Calculate avg span",
"type": "ai_outputParser",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 内容创作, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用 Azure OpenAI 和 Google Workspace 自动化 DEI 资格筛选
使用Azure GPT-4o、Google云端硬盘和表格自动进行DEI资格筛选
If
Code
Gmail
+9
19 节点Rahul Joshi
内容创作
从Google Drive生成n8n模板描述
使用Azure GPT-4从Google Drive生成模板描述
Code
Gmail
Google Drive
+9
27 节点Rahul Joshi
内容创作
客户入职帮助请求(Typeform 到 Gmail 和 Sheets)
客户入职帮助请求(Typeform 到 Gmail 和 Sheets)
If
Code
Gmail
+10
28 节点Rahul Joshi
内容创作
技能差距 → 培训推荐
为 HR 团队使用 GPT-4o、Google Sheets 和 Gmail 个性化候选人反馈
If
Code
Gmail
+7
27 节点Rahul Joshi
内容创作
将服装图片上传到Cloudinary并使用Azure OpenAI (GPT-4o) 记录到工作表
使用GPT-4o、Cloudinary和Google Sheets处理和编目服装图片
Set
Code
Merge
+9
26 节点Rahul Joshi
内容创作
从 Stripe 支付自动交付模板给客户
使用Stripe、GPT-4o和Gmail的自动化模板交付系统
If
Code
Gmail
+12
44 节点Rahul Joshi
客户关系管理
工作流信息
难度等级
高级
节点数量16
分类2
节点类型10
作者
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 查看 →
分享此工作流