构建用于Slack候选人评估deAI驱动chatbot

Avancé

Ceci est unAI Chatbot, Multimodal AIworkflow d'automatisation du domainecontenant 29 nœuds.Utilise principalement des nœuds comme If, Code, Slack, Webhook, GoogleDrive. AI简历analyse与候选人评估:SlacketGoogle表格intégration

Prérequis
  • Token Bot Slack ou URL Webhook
  • Point de terminaison HTTP Webhook (généré automatiquement par n8n)
  • Informations d'identification Google Drive API
  • Peut nécessiter les informations d'identification d'authentification de l'API cible
  • Informations d'identification Google Sheets API
  • Clé API OpenAI
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "id": "u6seZCMlUCt4sZqF",
  "meta": {
    "instanceId": "4a2e6764ba7a6bc9890d9225f4b21d570ce88fc9bd57549c89057fcee58fed0f",
    "templateId": "1961",
    "templateCredsSetupCompleted": true
  },
  "name": "Building an AI-Powered Chatbot for Candidate Evaluation on Slack",
  "tags": [],
  "nodes": [
    {
      "id": "97989831-3fc6-4954-ac55-8e0950081b7a",
      "name": "Est-ce un message utilisateur ?",
      "type": "n8n-nodes-base.if",
      "position": [
        -3312,
        880
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1def7344-ce55-450d-a85a-468f746fe31f",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.event.type }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "afa6b192-1e25-46b6-8fdc-81dff9a37e74",
      "name": "Aucune opération, ne rien faire",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -3088,
        976
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "4a7ec607-1706-4357-aa89-4c44faa98fb8",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -3536,
        880
      ],
      "webhookId": "db3bf3da-b9b7-4823-8c5d-14f5de0272da",
      "parameters": {
        "path": "slack-gilfoyle",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2
    },
    {
      "id": "04301600-3371-4fba-b2a6-509bfd3809f9",
      "name": "Extraire depuis un fichier",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -2640,
        688
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "=data"
      },
      "typeVersion": 1
    },
    {
      "id": "1f49b4bf-5a06-42cc-8566-440639d15aeb",
      "name": "Télécharger le profil candidat depuis Slack",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2864,
        688
      ],
      "parameters": {
        "url": "={{ $json.body.event.files[0].url_private_download }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "slackOAuth2Api"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "4JSKt9sIRV1KGswQ",
          "name": "Slack account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "04940f53-05e2-4dbb-8bbe-2c6104cf978b",
      "name": "Analyseur json",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -2160,
        912
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"AppliedPosition\": \"Position Name\",\n  \"JobDescription\": \"Job Description URL\",\n  \"Profile\": {\n    \"full_name\": \"\",\n    \"job_title\": \"\",\n    \"summary\": \"\",\n    \"contact\": {\n      \"email\": \"\",\n      \"phone\": \"\",\n      \"address\": \"\",\n      \"linkedin\": \"\",\n      \"website\": \"\"\n    },\n    \"education\": [\n      {\n        \"degree\": \"\",\n        \"field_of_study\": \"\",\n        \"institution\": \"\",\n        \"location\": \"\",\n        \"start_year\": \"\",\n        \"end_year\": \"\"\n      }\n    ],\n    \"certifications\": [\n      {\n        \"name\": \"\",\n        \"issuer\": \"\",\n        \"date_obtained\": \"\",\n        \"expiration_date\": \"\"\n      }\n    ],\n    \"work_experience\": [\n      {\n        \"company\": \"\",\n        \"position\": \"\",\n        \"location\": \"\",\n        \"start_date\": \"\",\n        \"end_date\": \"\",\n        \"responsibilities\": [\n          \"\"\n        ],\n        \"achievements\": [\n          \"\"\n        ]\n      }\n    ],\n    \"skills\": {\n      \"technical_skills\": [\n        \"\"\n      ],\n      \"soft_skills\": [\n        \"\"\n      ],\n      \"languages\": [\n        {\n          \"language\": \"\",\n          \"proficiency\": \"\"\n        }\n      ],\n      \"tools_and_technologies\": [\n        \"\"\n      ]\n    },\n    \"projects\": [\n      {\n        \"name\": \"\",\n        \"description\": \"\",\n        \"technologies_used\": [\n          \"\"\n        ],\n        \"role\": \"\",\n        \"duration\": \"\"\n      }\n    ],\n    \"awards\": [\n      {\n        \"title\": \"\",\n        \"issuer\": \"\",\n        \"date\": \"\",\n        \"description\": \"\"\n      }\n    ],\n    \"volunteer_experience\": [\n      {\n        \"organization\": \"\",\n        \"role\": \"\",\n        \"description\": \"\",\n        \"start_date\": \"\",\n        \"end_date\": \"\"\n      }\n    ],\n    \"additional_information\": {\n      \"availability\": \"\",\n      \"preferred_location\": \"\",\n      \"salary_expectation\": \"\",\n      \"work_authorization\": \"\",\n      \"other_notes\": \"\"\n    }\n  }\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "0609ac69-6003-4948-a847-d6e3fcb326da",
      "name": "Modèle gpt4-1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -2416,
        912
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "PPSwAKeLQYgAPobT",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7091e495-668b-4fed-a5f9-de2333908a3d",
      "name": "Télécharger le fichier",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -1952,
        688
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $json.output.JobDescription }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "fC471es5gk5Mm900",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "d3067e57-7b79-4dff-bbdd-31ae43228a34",
      "name": "Extraire la description de poste",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -1728,
        688
      ],
      "parameters": {
        "options": {},
        "operation": "pdf"
      },
      "typeVersion": 1
    },
    {
      "id": "cc30fbc4-c777-4556-a89c-3d782bedc7cf",
      "name": "Agent Expert RH",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -1504,
        688
      ],
      "parameters": {
        "text": "=Evaluate the candidate for the following job:\n\n--- Job Description ---\nPosition: {{ $('Profile Analyzer Agent').item.json.output.AppliedPosition }}\nJob Description: {{ $('Extract Job Description').item.json.text }}\n------------------------\n\nBelow is the extracted candidate profile:\n{{ $('Profile Analyzer Agent').item.json.output.Profile.toJsonString() }}",
        "messages": {
          "messageValues": [
            {
              "message": "You are a professional AI hiring assistant tasked with evaluating job candidates based on their structured resume data and a provided job description. Your goal is to assess the candidate’s suitability for the role, identifying key matches and gaps in skills, experience, and qualifications.  You will receive: - `candidate_profile`: a JSON object containing extracted information from the candidate's resume. - `job_description`: a plain text description of the role.  Your job is to: 1. Parse and understand the key job requirements (e.g., required skills, years of experience, qualifications). 2. Match the candidate's profile to the job requirements. 3. Provide a structured evaluation with ratings and reasoning.  Always be objective, use professional language, and format your output clearly using markdown."
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.5
    },
    {
      "id": "9e39fb8d-e66b-4767-a04b-c35a5cbd37f7",
      "name": "Agent Analyseur de Profil",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -2384,
        688
      ],
      "parameters": {
        "text": "=Please extract all relevant information from this candiadte:\nCV Content:\n===\n{{ $json[\"text\"] }}\n===\nAnd extract applied position from message below:\n{{ $('Webhook').item.json.body.event.text }}\nGiven the tool to get postions from google sheet, conclude final applied position name follw name in the sheet and the job description URL",
        "options": {
          "systemMessage": "You are a smart and reliable assistant for the HR team. Your job is to help evaluate job applicants by processing two main inputs:\n\n1. The candidate’s **user profile** (provided as a block of plain text).\n2. The **request message** (typically a short Slack or email message from a recruiter asking for evaluation).\n\nYou also have access to a **Google Sheets tool** containing a table that maps position names (e.g., \"AI Engineer\") to job details such as:\n- Job title\n- Job description URL\n\n---\n\nYour task is to:\n1. Parse and extract the **candidate’s name, email (if any), and core skills or summary** from the user profile.\n2. From the request message, identify the **applied position**.\n3. Use the Sheets tool to look up and return:\n   - The **applied position** (standardized from the sheet)\n   - The corresponding **Job Description URL**\n\n---\n\nOutput Format:\n- **Candidate Profile**: [Parsed name, email, and summary from resume]\n- **Applied Position**: [From sheet, matched using request message]\n- **Job Description URL**: [From sheet, based on position]\n\nIf the job title from the request is unclear or not found, return a helpful clarification message instead of making assumptions.\n\n---\n\nBe concise, structured, and ensure accurate matching when referencing job titles from the sheet."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "executeOnce": true,
      "typeVersion": 2.1
    },
    {
      "id": "3b996554-5e83-4ffe-9142-f52883e15573",
      "name": "Mettre à jour la feuille d'évaluation",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -880,
        784
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "overall_fit_score",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "overall_fit_score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "recommendation",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "recommendation",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "required_experience",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "required_experience",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "skill_match",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "skill_match",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "education_certifications",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "education_certifications",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "soft_skills_traits",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "soft_skills_traits",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "strengths",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "strengths",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "concerns_or_gaps",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "concerns_or_gaps",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "final_notes",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "final_notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "output"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/1gpuTL7iK2LoDJAdHE-LBFiBEU6hLqSTxWjThMJyi7SY/edit?usp=drive_link"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "L670Nly6gZGo71br",
          "name": "Google Sheets account 2"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "2f406e89-d1d9-458a-839a-f9c612184714",
      "name": "Mapper les colonnes",
      "type": "n8n-nodes-base.code",
      "position": [
        -1104,
        688
      ],
      "parameters": {
        "jsCode": "const evalResult = $input.first().json.output\nreturn [\n  {\n    json: {\n      full_name: $('Profile Analyzer Agent').first().json.output.Profile.full_name,\n      email: $('Profile Analyzer Agent').first().json.output.Profile.contact.email || \"Email not available\",\n      phone: $('Profile Analyzer Agent').first().json.output.Profile.contact.phone ||  \"Phone not available\",\n      position: $('Profile Analyzer Agent').first().json.output.AppliedPosition,\n      overall_fit_score: evalResult.overall_fit_score,\n      recommendation: evalResult.recommendation,\n      strengths: evalResult.strengths.join(', '),\n      concerns_or_gaps: evalResult.concerns_or_gaps.join(', '),\n      final_notes: evalResult.final_notes,\n      submitted_date: $now.toFormat(\"yyyyLLdd-HHmmss\")\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "14ddc37b-9286-46a8-bdeb-d333db447d24",
      "name": "Modèle gpt-4-1 2",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -1472,
        912
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "PPSwAKeLQYgAPobT",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "74430118-e4d3-4966-8703-c2ffa483b895",
      "name": "Analyseur json 2",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -1344,
        912
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"overall_fit_score\": 0,\n  \"recommendation\": \"\", \n  \"job_match_summary\": {\n    \"required_experience\": \"\",\n    \"skill_match\": \"\",\n    \"education_certifications\": \"\",\n    \"soft_skills_traits\": \"\"\n  },\n  \"strengths\": [\n    \"\"\n  ],\n  \"concerns_or_gaps\": [\n    \"\"\n  ],\n  \"final_notes\": \"\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "83a9bea2-1012-4ad6-a6db-145c74086b30",
      "name": "Si",
      "type": "n8n-nodes-base.if",
      "position": [
        -3088,
        784
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "aa58b881-6e48-488b-a96c-9a85b1504a6e",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.event.files[0].id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "d8a4b76d-1bbd-4fee-b024-ffa824829558",
      "name": "Envoyer le résultat dans le canal mentionné",
      "type": "n8n-nodes-base.slack",
      "position": [
        -656,
        592
      ],
      "webhookId": "6d1ea29f-86ba-42df-ae9f-3dd510510dae",
      "parameters": {
        "text": "=🎯 *Candidate Evaluation Update*\n\nHi <@{{ $json.id }}>,  \nWe've completed the initial screening and have a qualified candidate for the {{ $('Map Columns').item.json.position }} position:\n\n👤 *Candidate:* {{ $('Map Columns').item.json.full_name }}\n📝 *Summary:*  \n• *Fit Score:* {{ $('Map Columns').item.json.overall_fit_score }}/10  \n• *Recommendation:* {{ $('Map Columns').item.json.recommendation }}\n• *Key Strengths:* {{ $('Map Columns').item.json.strengths }}\n👉 Please advise on next steps (e.g., schedule technical interview, team round, etc.).",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Webhook').item.json.body.event.channel }}"
        },
        "otherOptions": {
          "mrkdwn": true
        }
      },
      "credentials": {
        "slackApi": {
          "id": "Yi3LKjrxH5dH4v1r",
          "name": "BOT Token"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "e41b4a81-7feb-45df-bbe8-ad006e6ebdb8",
      "name": "Informer l'utilisateur de l'absence de profil",
      "type": "n8n-nodes-base.slack",
      "position": [
        -2864,
        880
      ],
      "webhookId": "6d1ea29f-86ba-42df-ae9f-3dd510510dae",
      "parameters": {
        "text": "=🗂️ Got it — just one more thing!\nI can help read the candidate profile you mentioned, but it looks like I didn’t catch the file in your last message.\n👉 Please upload the file first, wait for it to finish uploading, and then press Enter to send your message.\nThat way, I can grab the profile and help you out right away! 😊",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Webhook').item.json.body.event.channel }}"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "id": "Yi3LKjrxH5dH4v1r",
          "name": "BOT Token"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "64818e9c-f6d3-4b05-8297-b7b9089044ca",
      "name": "Interroger les postes disponibles",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        -2288,
        912
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/15CZPMbxmz-RVYji1fev_6vYeEwpPa3MjewGEPf6aSoA/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "15CZPMbxmz-RVYji1fev_6vYeEwpPa3MjewGEPf6aSoA",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/15CZPMbxmz-RVYji1fev_6vYeEwpPa3MjewGEPf6aSoA/edit?usp=drivesdk",
          "cachedResultName": "Positions"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "L670Nly6gZGo71br",
          "name": "Google Sheets account 2"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "64560334-5db8-4d2d-b5e7-ad4b865cb0bd",
      "name": "Obtenir les informations sur un utilisateur",
      "type": "n8n-nodes-base.slack",
      "position": [
        -880,
        592
      ],
      "webhookId": "5299729f-620c-4984-80be-001f1d7e9740",
      "parameters": {
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Webhook').item.json.body.event.files[0].user }}"
        },
        "resource": "user",
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "4JSKt9sIRV1KGswQ",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "7e1f48d9-ae9c-43e2-ae89-09d207e3a33f",
      "name": "Note adhésive",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4672,
        -224
      ],
      "parameters": {
        "color": 4,
        "width": 1056,
        "height": 2432,
        "content": "# Building an AI-Powered Chatbot for Candidate Evaluation on Slack\n[![Watch the video](https://wisestackai.s3.ap-southeast-1.amazonaws.com/building-an-ai-powered-chatbot-for-candidate-evaluation-on-slack.jpg)](https://www.youtube.com/watch?v=NAn5BSr15Ks)\n> This workflow connects a Slack chatbot with AI agents and Google Sheets to automate candidate resume evaluation. It extracts resume details, identifies the applied job from the message, fetches the correct job description, and provides a summarized evaluation via Slack and tracking sheet. Perfect for HR teams using Slack.\n\n## **Who’s it for**\nThis workflow is designed for:\n- **HR Teams**, **Recruiters**, and **Hiring Managers**  \n- Working in software or tech companies using **Slack**, **Google Sheets**, and **n8n**\n- Who want to **automate candidate evaluation** based on uploaded profiles and applied job positions\n\n## **How it works / What it does**\nThis workflow is triggered when a **Slack user mentions the HR bot** and attaches a **candidate profile PDF**.\nThe workflow performs the following steps:\n1. **Trigger from Slack Mention**  \n   - A user mentions the bot in Slack with a message like:  \n     `@HRBot Please evaluate this candidate for the AI Engineer role.`  \n     (with PDF attached)\n2. **Input Validation**  \n   - If no file is attached, the bot replies:  \n     _\"Please upload the candidate profile file before sending the message.\"_\n3. **Extract Candidate Profile**  \n   - Downloads the attached PDF from Slack  \n   - Uses `Extract from File` to parse the resume into text\n4. **Profile Analysis (AI Agent)**  \n   - Sends the resume text and message to the `Profile Analyzer Agent`\n   - Identifies:\n     - Candidate name, email, and summary\n     - Applied position (from message)\n   - Looks up the **Job Description PDF URL** using Google Sheets\n5. **Job Description Retrieval**  \n   - Downloads and parses the matching JD PDF\n6. **HR Evaluation (AI Agent)**  \n   - Sends both the **candidate profile** and **job description** to `HR Expert Agent`\n   - Receives a summarized **fit evaluation** and insights\n7. **Output and Logging**  \n   - Sends evaluation result back to Slack in the original thread  \n   - Updates a **Google Sheet** with evaluation data for tracking\n\n## **How to set up**\n1. **Slack Setup**\n   - Create a Slack bot and install it into your workspace\n   - Enable the `app_mention` event and generate a **bot token**\n   - Connect Slack to n8n using **Slack Bot credentials**\n2. **Google Sheets Setup**\n   - Create a sheet mapping `Position Title → Job Description URL`\n   - Create another sheet for logging evaluation results\n3. **n8n Setup**\n   - Add a **Webhook Trigger** for Slack mentions\n   - Connect Slack, Google Sheets, and GPT-4 credentials\n   - Set up agents (`Profile Analyzer Agent`, `HR Expert Agent`) with appropriate prompts\n4. **Deploy & Test**\n   - Mention your bot in Slack with a message and file\n   - Confirm the reply and entry in the evaluation tracking sheet\n\n## **Requirements**\n\n- n8n (self-hosted or cloud)\n- Slack App with Bot Token\n- OpenAI or Azure OpenAI account (for GPT-4)\n- Google Sheets (2 sheets: job mapping + evaluation log)\n- Candidate profiles in PDF format\n- Defined job titles and descriptions\n\n## **How to customize the workflow**\n\nYou can easily adapt this workflow to your team’s needs:\n| Customization Area       | How to Customize                                                                 |\n|--------------------------|----------------------------------------------------------------------------------|\n| Job Mapping Source       | Replace Google Sheet with Airtable or Notion DB                                 |\n| JD Format                | Use Markdown or inline descriptions instead of PDF                              |\n| Evaluation Output Format | Change from Slack message to Email or Notion update                             |\n| HR Agent Prompt          | Customize to match your company tone or include scoring rubrics                 |\n| Language Support         | Add support for bilingual input/output (e.g., Vietnamese & English)             |\n| Workflow Trigger         | Trigger from slash command or form instead of `@mention`                        |"
      },
      "typeVersion": 1
    },
    {
      "id": "9f5d8dfa-905b-4593-b75d-82d4cb826106",
      "name": "Note adhésive1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3616,
        1040
      ],
      "parameters": {
        "width": 272,
        "height": 192,
        "content": "### 1. 🚀 Trigger on Slack Mention\nWhen a Slack user mentions the HR bot and includes a message (e.g. “Please evaluate this candidate for the AI Engineer role”) along with an attached PDF resume, the workflow is triggered via webhook."
      },
      "typeVersion": 1
    },
    {
      "id": "69148cf4-dff4-417d-acf6-a506deadee53",
      "name": "Note adhésive2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3296,
        1136
      ],
      "parameters": {
        "width": 384,
        "height": 128,
        "content": "### 2. 🧾 Validate Input\nThe workflow checks if a file (PDF) is attached. If not, it sends a friendly message back to the user, asking them to upload the resume before sending the request."
      },
      "typeVersion": 1
    },
    {
      "id": "9aba6130-c3b5-4045-8ec1-09ae606f2263",
      "name": "Note adhésive3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2880,
        528
      ],
      "parameters": {
        "width": 352,
        "height": 128,
        "content": "### 3. 📥 Download and Extract Resume\nThe bot downloads the attached PDF resume and uses the `Extract from File` module to convert the document into readable plain text.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "22361750-c673-49e7-927e-e9551724abc1",
      "name": "Note adhésive4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2432,
        416
      ],
      "parameters": {
        "width": 336,
        "height": 240,
        "content": "### 4. 🧠 Analyze Profile (AI Agent)\nThe extracted resume text and user request message are sent to the **Profile Analyzer Agent**, which:\n- Extracts candidate details (name, email, skills, summary)\n- Identifies the **applied job position** from the message\n- Queries a Google Sheet to retrieve the corresponding **Job Description URL**"
      },
      "typeVersion": 1
    },
    {
      "id": "f47d2b7d-00fb-409a-93e6-3d16c65ad918",
      "name": "Note adhésive5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1952,
        880
      ],
      "parameters": {
        "width": 336,
        "height": 128,
        "content": "### 5. 📄 Fetch and Extract Job Description\nUsing the matched Job Description URL from the Google Sheet, the workflow downloads and parses the JD PDF into plain text."
      },
      "typeVersion": 1
    },
    {
      "id": "81d73e30-1b8b-48dc-9fd8-495c2b8a6cee",
      "name": "Note adhésive6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1552,
        480
      ],
      "parameters": {
        "width": 368,
        "content": "### 6. 👩‍💼 Evaluate Candidate (HR Expert Agent)\nThe candidate profile and job description are passed to the **HR Expert Agent**, which:\n- Assesses the fit between the resume and job description\n- Outputs a summary evaluation and insights"
      },
      "typeVersion": 1
    },
    {
      "id": "b1443b1d-e175-4e01-ba34-2002ae23b740",
      "name": "Note adhésive7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        416
      ],
      "parameters": {
        "width": 272,
        "height": 144,
        "content": "### 7. 📤 Send Results via Slack\nThe evaluation result is posted back to the **Slack thread** where the request originated, notifying the original user with a clean and readable summary."
      },
      "typeVersion": 1
    },
    {
      "id": "5c9af46b-bcf2-403f-a67b-bdf4b3ce9f2d",
      "name": "Note adhésive8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        960
      ],
      "parameters": {
        "width": 288,
        "height": 128,
        "content": "### 8. 📊 Log to Google Sheet\nThe evaluation result, along with candidate and job data, is saved into a **Google Sheet** for internal tracking, auditing, or reporting purposes."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {},
  "versionId": "862307b9-766b-4c14-bd23-46de364fff6c",
  "connections": {
    "83a9bea2-1012-4ad6-a6db-145c74086b30": {
      "main": [
        [
          {
            "node": "1f49b4bf-5a06-42cc-8566-440639d15aeb",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "e41b4a81-7feb-45df-bbe8-ad006e6ebdb8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4a7ec607-1706-4357-aa89-4c44faa98fb8": {
      "main": [
        [
          {
            "node": "97989831-3fc6-4954-ac55-8e0950081b7a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2f406e89-d1d9-458a-839a-f9c612184714": {
      "main": [
        [
          {
            "node": "3b996554-5e83-4ffe-9142-f52883e15573",
            "type": "main",
            "index": 0
          },
          {
            "node": "64560334-5db8-4d2d-b5e7-ad4b865cb0bd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04940f53-05e2-4dbb-8bbe-2c6104cf978b": {
      "ai_outputParser": [
        [
          {
            "node": "9e39fb8d-e66b-4767-a04b-c35a5cbd37f7",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "0609ac69-6003-4948-a847-d6e3fcb326da": {
      "ai_languageModel": [
        [
          {
            "node": "9e39fb8d-e66b-4767-a04b-c35a5cbd37f7",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "7091e495-668b-4fed-a5f9-de2333908a3d": {
      "main": [
        [
          {
            "node": "d3067e57-7b79-4dff-bbdd-31ae43228a34",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "74430118-e4d3-4966-8703-c2ffa483b895": {
      "ai_outputParser": [
        [
          {
            "node": "cc30fbc4-c777-4556-a89c-3d782bedc7cf",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "cc30fbc4-c777-4556-a89c-3d782bedc7cf": {
      "main": [
        [
          {
            "node": "2f406e89-d1d9-458a-839a-f9c612184714",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "14ddc37b-9286-46a8-bdeb-d333db447d24": {
      "ai_languageModel": [
        [
          {
            "node": "cc30fbc4-c777-4556-a89c-3d782bedc7cf",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "97989831-3fc6-4954-ac55-8e0950081b7a": {
      "main": [
        [
          {
            "node": "83a9bea2-1012-4ad6-a6db-145c74086b30",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "afa6b192-1e25-46b6-8fdc-81dff9a37e74",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04301600-3371-4fba-b2a6-509bfd3809f9": {
      "main": [
        [
          {
            "node": "9e39fb8d-e66b-4767-a04b-c35a5cbd37f7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9e39fb8d-e66b-4767-a04b-c35a5cbd37f7": {
      "main": [
        [
          {
            "node": "7091e495-668b-4fed-a5f9-de2333908a3d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d3067e57-7b79-4dff-bbdd-31ae43228a34": {
      "main": [
        [
          {
            "node": "cc30fbc4-c777-4556-a89c-3d782bedc7cf",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "64818e9c-f6d3-4b05-8297-b7b9089044ca": {
      "ai_tool": [
        [
          {
            "node": "9e39fb8d-e66b-4767-a04b-c35a5cbd37f7",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "64560334-5db8-4d2d-b5e7-ad4b865cb0bd": {
      "main": [
        [
          {
            "node": "d8a4b76d-1bbd-4fee-b024-ffa824829558",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d8a4b76d-1bbd-4fee-b024-ffa824829558": {
      "main": [
        []
      ]
    },
    "1f49b4bf-5a06-42cc-8566-440639d15aeb": {
      "main": [
        [
          {
            "node": "04301600-3371-4fba-b2a6-509bfd3809f9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Avancé - Chatbot IA, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Avancé
Nombre de nœuds29
Catégorie2
Types de nœuds15
Description de la difficulté

Adapté aux utilisateurs avancés, avec des workflows complexes contenant 16+ nœuds

Auteur
Trung Tran

Trung Tran

@trungtran

Empowering small and medium businesses with smart automation and practical AI, no big tech team required.

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34