AutomationFlowsAI & RAG › Employee Attrition Risk Detection & Hr Alerts Using Azure Openai Gpt-4o-mini…

Employee Attrition Risk Detection & Hr Alerts Using Azure Openai Gpt-4o-mini…

Original n8n title: Employee Attrition Risk Detection & Hr Alerts Using Azure Openai Gpt-4o-mini & Gmail

ByRahul Joshi @rahul08 on n8n.io

Automatically ingests new employee data, extracts relevant signals, scores attrition risk, and notifies HR/managers with structured insights and recommended actions. Built on Azure OpenAI Chat with Structured Output Parser and true/false routing for escalation. Trigger for new…

Event trigger★★★★☆ complexityAI-powered16 nodesLm Chat Azure Open AiOutput Parser StructuredGoogle Drive TriggerGoogle DriveAgentGmail
AI & RAG Trigger: Event Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #9309 — we link there as the canonical source.

This workflow follows the Agent → Gmail recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "ONqZuWnwkE64Mm4F",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Attrition Risk Alert Workflow (Azure OpenAI + n8n)",
  "tags": [],
  "nodes": [
    {
      "id": "c48bef67-a0d0-4a4b-a374-3df1a7ed4c19",
      "name": "Azure OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        688,
        128
      ],
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a44062d6-1e37-443b-b146-cf32a9ac74cc",
      "name": "Structured Output Parser",
      "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": "Trigger for new resume",
      "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": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dabfc101-cfa3-43e6-b568-320c1c2d3e92",
      "name": "Download resume",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        224,
        -96
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $json.webViewLink }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "821c7e31-be41-4e6c-b58b-19a2cf880648",
      "name": "Extract text",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        448,
        -96
      ],
      "parameters": {
        "options": {},
        "operation": "pdf"
      },
      "typeVersion": 1
    },
    {
      "id": "78f8966f-dbeb-4773-b198-9dfb13defd35",
      "name": "Calculate avg span",
      "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 -, \u2013, \u2014.\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": "Logic",
      "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\u2011in within the next 3\u20135 days\",\n    \"Offer growth or role\u2011clarity 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\" ? `\u2013 ${riskLevel} Risk (${riskScore}%)` : \"\u2013 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\u2011up that ${headerLine} may be at risk of leaving soon. ${riskLine}.\n\nKey signals observed:\n${signalsBlock}\n\nLast engagement/check\u2011in: ${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
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "={{ $json.emailBody }}",
        "options": {},
        "subject": "={{ $json.emailSubject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "860057d2-af64-4ea5-8df5-1945f27b52d2",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        -128
      ],
      "parameters": {
        "content": "## Trigger for new resume\u00a0 \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": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        -304
      ],
      "parameters": {
        "content": "## Download resume\u00a0 \nFetches the resume file from the source and makes it available for processing."
      },
      "typeVersion": 1
    },
    {
      "id": "dcf63ce0-b0f0-4ede-9c95-c7c37814b028",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        80
      ],
      "parameters": {
        "content": "## Extract text\u00a0 \nPulls readable text from the downloaded resume using a PDF extraction step."
      },
      "typeVersion": 1
    },
    {
      "id": "114d70ee-1e49-41f4-937b-6b8e183d787b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -304
      ],
      "parameters": {
        "content": "## Chat Model\u00a0 \nUses Azure OpenAI Chat to analyze or summarize the extracted resume content."
      },
      "typeVersion": 1
    },
    {
      "id": "b5ee6f06-3ac8-402a-9051-f5ee0aaae094",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        96
      ],
      "parameters": {
        "content": "## Logic\u00a0 \nApplies conditional checks and routing (true/false) based on parsed results."
      },
      "typeVersion": 1
    },
    {
      "id": "e7fcd240-e008-419f-ac1b-e45593f3c037",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        -320
      ],
      "parameters": {
        "content": "## Create email\u00a0 \nGenerates a tailored email draft to the candidate or HR using the parsed data."
      },
      "typeVersion": 1
    },
    {
      "id": "e8aae9bd-426b-4020-8b47-f48bc35b1ae3",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1408,
        96
      ],
      "parameters": {
        "content": "## Send email to hr\u00a0 \nSends the composed message to HR via the configured email service."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "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
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Automatically ingests new employee data, extracts relevant signals, scores attrition risk, and notifies HR/managers with structured insights and recommended actions. Built on Azure OpenAI Chat with Structured Output Parser and true/false routing for escalation. Trigger for new…

Source: https://n8n.io/workflows/9309/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow is designed to evaluate newly added CVs for Diversity, Equity, and Inclusion (DEI) eligibility. It automatically ingests CVs from Google Drive, extracts key fields, analyzes them with Az

Lm Chat Azure Open Ai, Output Parser Structured, Google Sheets Tool +5
AI & RAG

Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.

Tool Think, Tool Calculator, Agent Tool +18
AI & RAG

Transcript Evalu8r V2 is a robust browser-based transcript analysis tool powered by Deepgram’s speech-to-text API and built into an n8n workflow template. This release introduces full in-browser audio

Google Drive Trigger, HTTP Request, Agent +5
AI & RAG

Transcript Evalu8r is an AI-powered transcript analysis workflow that automates the processing, visualization, and evaluation of transcribed conversations. This n8n workflow template is designed to he

Google Drive Trigger, HTTP Request, Agent +5
AI & RAG

This workflow automates end-to-end validation, assessment, and reporting of n8n workflow JSON templates using Google Drive, Azure OpenAI GPT-4o, Gmail, and Slack. It retrieves workflows from a Drive f

Memory Buffer Window, Lm Chat Azure Open Ai, Output Parser Structured +5