Пошаговые инструкции advanced 22 мин

Как сделать ИИ-агента для HR и рекрутинга

Пошаговая инструкция от нуля до рабочего HR-агента: вакансии, резюме, screening, fairness checks, вопросы, письма, ATS, approval и audit log.

AI-агенты HR рекрутинг ATS резюме screening Greenhouse Lever интервью Workable

Что получится в результате

Соберем ИИ-агента, который помогает рекрутеру разбирать входящие резюме, сверять их с требованиями вакансии, готовить карточку кандидата, вопросы для интервью, внутреннюю заметку в ATS и черновик письма кандидату.

В результате будет рабочий прототип:

  1. вакансия хранится в таблице `job_profiles`;
  2. входящее резюме попадает в `candidate_inbox`;
  3. агент извлекает факты в `candidate_profiles`;
  4. требования вакансии проверяются по `screening_criteria`;
  5. результаты scoring пишутся в `screening_results`;
  6. риски и запрещенные признаки пишутся в `fairness_checks`;
  7. вопросы для интервью попадают в `interview_questions`;
  8. письмо кандидату создается как draft в `message_drafts`;
  9. рекрутер принимает решение в `review_queue`;
  10. после approval агент создает заметку или задачу в ATS;
  11. каждое действие фиксируется в `audit_log`.

Агент не должен автоматически отказывать кандидату, принимать решение о найме, оценивать человека по возрасту, полу, семейному положению, национальности, здоровью, фотографии, имени или другим нерелевантным признакам.

Что понадобится

Минимальный набор:

  1. Google Sheets как база прототипа.
  2. n8n для workflow.
  3. Папка с резюме: PDF, DOCX или ссылки.
  4. LLM API для извлечения фактов и summary.
  5. ATS: Greenhouse, Lever, Workable, Huntflow, Potok, Хантфлоу, hh.ru API или ручной CSV.
  6. Google Calendar или Microsoft Calendar для слотов интервью.
  7. Gmail, Outlook или Telegram для черновиков уведомлений.
  8. Рекрутер или hiring manager, который подтвердит критерии вакансии.
  9. Политика компании по персональным данным и хранению резюме.

Для первого запуска хватит Google Sheets, n8n, папки с 10 тестовыми резюме и одной вакансии.

Шаг 1. Выберите одну вакансию для MVP

Не запускайте агента сразу на все вакансии.

Возьмите вакансию, где:

  1. требования уже понятны;
  2. есть 10-30 реальных или обезличенных резюме;
  3. рекрутер может быстро проверить результат;
  4. нет спорных юридических требований;
  5. критерии можно подтвердить фактами из резюме.

Хороший пример:

Backend Python developer
Middle+
FastAPI, PostgreSQL, Docker, REST API
Опыт от 3 лет
Формат: remote

Плохой пример:

Нам нужен сильный человек с правильным вайбом.

Проверка: вакансию можно описать в `job_profiles` без абстрактных фраз.

Шаг 2. Запретите опасные решения

Создайте системное правило для HR-агента.

Запретите агенту:

  1. автоматически отказывать кандидату;
  2. автоматически переводить кандидата в hired;
  3. удалять кандидата из ATS;
  4. менять зарплатные ожидания кандидата;
  5. делать выводы по возрасту;
  6. учитывать пол, национальность, семейное положение, здоровье, фото, имя, религию;
  7. делать психологический диагноз;
  8. обещать оффер;
  9. отправлять письмо кандидату без approval;
  10. скрывать низкую уверенность или отсутствующие данные.

Prompt:

Ты помощник рекрутера.
Ты извлекаешь факты из резюме и сравниваешь их с критериями вакансии.
Ты не принимаешь решение о найме или отказе.
Ты не используешь защищенные и нерелевантные признаки.
Если данных не хватает, пиши missing_data.
Любой отказ, оффер, письмо кандидату и изменение ATS требует human approval.

Проверка: даже если резюме явно не подходит, агент ставит `needs_recruiter_review`, а не `rejected`.

Шаг 3. Создайте Google Sheet проекта

Создайте таблицу `hr_recruiting_agent_mvp`.

Добавьте листы:

hr_settings
job_profiles
screening_criteria
candidate_inbox
candidate_profiles
screening_results
fairness_checks
interview_questions
message_drafts
review_queue
interview_slots
ats_updates
report_snapshots
audit_log
error_log

Проверка: первая строка каждого листа занята заголовками, доступ к таблице есть только у HR-команды и владельца вакансии.

Шаг 4. Заполните hr_settings

Лист `hr_settings` хранит пороги и правила.

Колонки:

key
value
description
updated_by
updated_at

Стартовые строки:

resume_parse_min_confidence | 0.82 | минимальная уверенность извлечения резюме
criteria_match_min_score | 0.70 | порог для review как потенциально релевантного
auto_reject_allowed | no | автоотказ запрещен
candidate_message_requires_approval | yes | письма только после approval
ats_write_requires_approval | yes | запись в ATS только после approval
protected_attributes_allowed | no | защищенные признаки не используются
retention_days | 180 | срок хранения резюме в прототипе
calendar_invite_requires_approval | yes | инвайт только после approval

Проверка: workflow читает `auto_reject_allowed = no` и не имеет ветки автоматического отказа.

Шаг 5. Создайте job_profiles

Лист `job_profiles` описывает вакансии.

Колонки:

job_id
job_title
department
level
location
work_format
salary_range
must_have
nice_to_have
responsibilities
screening_questions
hiring_manager
recruiter
status
created_at

Пример:

job_backend_001 | Backend Python Developer | Product | Middle+ | Россия | remote | 250-350k gross | Python 3, FastAPI, PostgreSQL, Docker, REST API, 3+ years | Kafka, Kubernetes, CI/CD | backend services, integrations, code review | опыт FastAPI? опыт PostgreSQL? | Иван | Мария | active | 2026-05-23

Проверка: у вакансии есть `must_have`, `nice_to_have`, рекрутер и hiring manager.

Шаг 6. Создайте screening_criteria

Лист `screening_criteria` превращает требования в проверяемые критерии.

Колонки:

criterion_id
job_id
criterion
type
weight
evidence_required
knockout
comment

Типы:

skill
experience
domain
language
location
work_format
salary
portfolio

Пример:

cr_001 | job_backend_001 | Python 3 | skill | 20 | упоминание Python в опыте или проектах | yes | базовый must-have
cr_002 | job_backend_001 | FastAPI | skill | 15 | опыт в коммерческом проекте | no | можно уточнить
cr_003 | job_backend_001 | PostgreSQL | skill | 15 | опыт БД, SQL, оптимизация | yes | must-have
cr_004 | job_backend_001 | 3+ years backend | experience | 20 | годы опыта или даты проектов | yes | must-have
cr_005 | job_backend_001 | remote | work_format | 10 | готовность к удаленной работе | no | уточнить, если не найдено

Проверка: каждый критерий можно подтвердить цитатой или фактом из резюме.

Шаг 7. Создайте candidate_inbox

Лист `candidate_inbox` хранит входящие резюме и заявки.

Колонки:

candidate_id
received_at
source
job_id
file_name
file_url
candidate_name_raw
email
phone
ats_candidate_id
status
parse_confidence
assigned_to
error_code
comment

Статусы:

new
parsed
screened
needs_review
ready_for_recruiter
approved_for_message
message_sent
interview_requested
archived

Проверка: каждое резюме получает `candidate_id` до вызова LLM.

Шаг 8. Настройте загрузку резюме

В n8n создайте workflow `hr_candidate_intake`.

Узлы:

  1. `Google Drive Trigger` или webhook ATS;
  2. `Set candidate_id`;
  3. `Get file metadata`;
  4. `Extract text from PDF/DOCX`;
  5. `Google Sheets Append candidate_inbox`;
  6. `Audit append file_received`.

Пример `candidate_id`:

cand_20260523_0001

Проверка: после загрузки резюме появляется строка в `candidate_inbox` со статусом `new`.

Шаг 9. Извлеките факты из резюме

Создайте лист `candidate_profiles`.

Колонки:

candidate_id
job_id
full_name
email
phone
location
work_format
current_role
total_years_experience
skills_json
companies_json
education_json
languages_json
salary_expectation
notice_period
portfolio_links
facts_json
missing_data_json
confidence_json
parsed_at

Проверка: агент извлекает только факты, которые есть в резюме, и не додумывает опыт.

Шаг 10. Настройте prompt для парсинга резюме

Prompt:

Извлеки факты из резюме.
Верни только JSON без Markdown.
Не оценивай человека.
Не используй возраст, пол, фото, семейное положение, национальность, здоровье, религию и другие нерелевантные признаки.
Если данных нет, верни null или добавь поле в missing_data.

Схема:
{
  "full_name": "string|null",
  "email": "string|null",
  "phone": "string|null",
  "location": "string|null",
  "work_format": "remote|office|hybrid|unknown",
  "current_role": "string|null",
  "total_years_experience": 0,
  "skills": ["string"],
  "companies": [
    {
      "name": "string",
      "role": "string",
      "start": "YYYY-MM|null",
      "end": "YYYY-MM|null",
      "facts": ["string"]
    }
  ],
  "education": ["string"],
  "languages": ["string"],
  "salary_expectation": "string|null",
  "notice_period": "string|null",
  "portfolio_links": ["string"],
  "facts": ["short factual bullet"],
  "missing_data": ["string"],
  "confidence": {
    "contacts": 0,
    "experience": 0,
    "skills": 0,
    "salary": 0
  }
}

Проверка: JSON валиден, а спорные поля попадают в `missing_data`.

Шаг 11. Очистите защищенные признаки

Создайте лист `fairness_checks`.

Колонки:

check_id
candidate_id
job_id
protected_attribute_detected
attribute_type
action
safe_summary
checked_at

Запрещенные типы:

age
gender
marital_status
children
nationality
religion
health
photo
political_views

Правило:

Если защищенный признак встретился в резюме, не использовать его в score, summary, вопросах и решении.

Проверка: если резюме содержит дату рождения, она не появляется в `screening_results`.

Шаг 12. Сравните кандидата с вакансией

Создайте лист `screening_results`.

Колонки:

screening_id
candidate_id
job_id
total_score
must_have_status
nice_to_have_score
criteria_json
confirmed_evidence_json
missing_requirements_json
risk_flags_json
recommendation
status
screened_at

Статусы:

ready_for_recruiter
needs_review
missing_data
not_enough_evidence

Рекомендации:

review_first
review_normal
ask_clarifying_questions
not_enough_evidence

Проверка: нет значения `reject`, потому что отказ делает человек.

Шаг 13. Настройте prompt для screening

Prompt:

Сравни факты кандидата с критериями вакансии.
Используй только candidate_profiles и screening_criteria.
Не используй защищенные признаки.
Для каждого критерия укажи evidence или missing.
Не принимай решение о найме или отказе.

Верни JSON:
{
  "total_score": 0,
  "must_have_status": "met|partially_met|not_enough_evidence|not_met",
  "criteria": [
    {
      "criterion_id": "string",
      "status": "met|partial|missing|not_enough_evidence",
      "score": 0,
      "evidence": "short quote or fact",
      "question_to_clarify": "string|null"
    }
  ],
  "missing_requirements": ["string"],
  "risk_flags": ["string"],
  "recommendation": "review_first|review_normal|ask_clarifying_questions|not_enough_evidence"
}

Проверка: каждый балл объяснен фактом, а не общей фразой “кандидат сильный”.

Шаг 14. Создайте карточку кандидата

Карточка для рекрутера должна быть короткой.

Сохраните в `screening_results.confirmed_evidence_json`:

{
  "summary": "Backend-разработчик с 5 годами Python, FastAPI и PostgreSQL",
  "strong_matches": ["Python 3", "FastAPI", "PostgreSQL", "Docker"],
  "missing_or_unclear": ["salary_expectation", "notice_period", "Kafka"],
  "questions": ["Уточнить коммерческий опыт с Kafka", "Уточнить ожидания по доходу"],
  "do_not_use": ["age", "photo"]
}

Проверка: карточку можно прочитать за 30 секунд и понять, что проверять дальше.

Шаг 15. Создайте interview_questions

Лист `interview_questions` хранит вопросы для первичного скрининга.

Колонки:

question_id
candidate_id
job_id
criterion_id
question_text
purpose
priority
status
created_at

Типовые вопросы:

Уточните, на каких проектах вы использовали FastAPI?
Сколько лет коммерческого опыта с PostgreSQL?
Был ли опыт оптимизации SQL-запросов?
Какой формат работы вам подходит?
Какой срок выхода на новое место?

Проверка: вопросы связаны с критериями вакансии, а не с личными признаками.

Шаг 16. Создайте message_drafts

Лист `message_drafts` хранит черновики писем и сообщений.

Колонки:

draft_id
candidate_id
job_id
message_type
channel
subject
body
status
approved_by
approved_at
sent_at
created_at

Типы:

clarifying_questions
interview_invite
thank_you
manual_reject_draft

Важно: даже reject draft не отправляется автоматически. Рекрутер проверяет причину, тон и соответствие правилам компании.

Проверка: новый draft получает `status = waiting_approval`.

Шаг 17. Настройте prompt для письма кандидату

Prompt:

Составь вежливый черновик письма кандидату.
Не обещай оффер.
Не сообщай автоматический отказ.
Не упоминай внутренний score.
Не используй защищенные признаки.
Если нужно уточнить данные, задай до 5 конкретных вопросов.
Письмо должно быть готово для проверки рекрутером.

Пример результата:

Здравствуйте, Анна.

Спасибо за отклик на вакансию Backend Python Developer.
Хотим уточнить несколько деталей перед следующим шагом:

1. На каких проектах вы использовали FastAPI?
2. Есть ли коммерческий опыт с PostgreSQL и оптимизацией SQL?
3. Какой формат работы вам подходит?
4. Какой срок выхода на новое место?

После ответа рекрутер вернется с дальнейшими шагами.

Проверка: письмо не содержит оценки “вы нам не подходите” без решения человека.

Шаг 18. Создайте review_queue

Лист `review_queue` нужен для решений рекрутера.

Колонки:

review_id
candidate_id
job_id
review_type
status
assigned_to
decision
decision_comment
created_at
decided_at

Типы review:

candidate_screening
message_approval
ats_note_approval
interview_invite_approval
manual_reject_review

Решения:

approved
needs_fix
reject_by_recruiter
move_to_interview
archive

Проверка: любые внешние сообщения и ATS write-actions проходят через `review_queue`.

Шаг 19. Подключите ATS в read-only режиме

Для Greenhouse, Lever или Workable сначала используйте чтение.

Разрешите:

  1. читать вакансии;
  2. читать кандидатов;
  3. читать applications;
  4. читать stages;
  5. читать interview slots;
  6. читать notes, если это разрешено политикой компании.

Запретите без approval:

  1. changing stage;
  2. reject candidate;
  3. create offer;
  4. update salary;
  5. send email;
  6. delete candidate;
  7. merge profiles.

Проверка: API credentials не имеют права удалить или отклонить кандидата.

Шаг 20. Создайте ats_updates

Лист `ats_updates` хранит то, что можно записать в ATS после approval.

Колонки:

update_id
candidate_id
job_id
target_system
action_type
payload_json
status
approved_by
approved_at
external_id
error_message
created_at

Разрешенные `action_type`:

create_internal_note
create_task
add_tag_needs_review
add_interview_questions_note

Запрещенные:

reject_candidate
hire_candidate
send_offer
delete_candidate
change_salary

Проверка: после approval создается внутренняя заметка, а не меняется статус кандидата.

Шаг 21. Подготовьте internal note для ATS

Internal note должна быть объяснимой.

Шаблон:

AI summary for recruiter review

Candidate: {{full_name}}
Job: {{job_title}}
Recommendation: {{recommendation}}

Confirmed evidence:
- {{criterion}}: {{evidence}}

Missing or unclear:
- {{missing_requirement}}

Suggested interview questions:
- {{question}}

Important: this is not a hiring decision. Recruiter review required.

Проверка: заметка не содержит protected attributes и не выглядит как финальное решение.

Шаг 22. Создайте interview_slots

Лист `interview_slots` хранит возможное время интервью.

Колонки:

slot_id
candidate_id
job_id
interviewer
start_at
end_at
timezone
calendar_event_id
status
approved_by
created_at

Статусы:

suggested
approved_to_send
sent_to_candidate
booked
cancelled

Проверка: агент предлагает слоты, но не отправляет calendar invite без approval.

Шаг 23. Настройте подбор слотов интервью

Workflow `hr_interview_scheduling`:

  1. получить кандидата со статусом `move_to_interview`;
  2. прочитать календарь рекрутера и интервьюера;
  3. найти 3-5 свободных слотов;
  4. записать их в `interview_slots`;
  5. создать draft письма в `message_drafts`;
  6. поставить `review_queue.review_type = interview_invite_approval`.

Правила:

  1. не ставить интервью вне рабочего времени;
  2. учитывать timezone кандидата, если она известна;
  3. не отправлять ссылку на встречу до approval;
  4. не раскрывать внутренние комментарии кандидату.

Проверка: рекрутер видит список слотов и утверждает письмо.

Шаг 24. Добавьте обработку missing_data

Если данных не хватает, агент должен спрашивать, а не додумывать.

Типовые missing_data:

salary_expectation
notice_period
work_format
english_level
commercial_experience_years
specific_skill_evidence
portfolio_link

Если `missing_data` критичны:

  1. создайте `message_drafts.message_type = clarifying_questions`;
  2. поставьте `review_queue.status = waiting`;
  3. не ставьте высокий score по отсутствующим данным;
  4. не меняйте stage в ATS.

Проверка: если в резюме нет зарплатных ожиданий, агент спрашивает кандидата, а не придумывает сумму.

Шаг 25. Настройте error_log

Лист `error_log` хранит технические и процессные ошибки.

Колонки:

error_id
created_at
candidate_id
job_id
step
severity
error_code
message
raw_payload_url
resolved
resolved_by
resolved_at

Типовые `error_code`:

resume_parse_failed
llm_json_invalid
missing_job_profile
missing_criteria
protected_attribute_leak
ats_api_failed
calendar_api_failed
message_draft_failed
low_confidence

Проверка: если LLM вернула невалидный JSON, кандидат не теряется, а получает ошибку `llm_json_invalid`.

Шаг 26. Настройте audit_log

Лист `audit_log` нужен для разборов и compliance.

Колонки:

event_id
created_at
actor
candidate_id
job_id
action
before_json
after_json
reason
system

Логируйте:

  1. получение резюме;
  2. извлечение текста;
  3. вызов LLM;
  4. screening;
  5. fairness check;
  6. создание draft письма;
  7. approval;
  8. запись в ATS;
  9. ошибку API;
  10. архивирование кандидата.

Проверка: по одному `candidate_id` можно восстановить путь от резюме до решения рекрутера.

Шаг 27. Сделайте отчет report_snapshots

Лист `report_snapshots` хранит регулярные HR-отчеты.

Колонки:

report_id
report_type
period_start
period_end
job_id
generated_at
metrics_json
summary
status

Метрики:

{
  "new_candidates": 38,
  "parsed": 35,
  "ready_for_recruiter": 21,
  "needs_review": 9,
  "missing_data": 5,
  "interview_requested": 6,
  "message_drafts_waiting": 4,
  "ats_update_errors": 1
}

Проверка: отчет показывает узкие места процесса, а не ранжирует людей.

Шаг 28. Протестируйте на контрольных резюме

Создайте папку `test_resumes`.

Минимальный набор:

  1. сильное резюме с явными must-have;
  2. резюме без одного must-have;
  3. резюме с похожими технологиями;
  4. резюме без контактов;
  5. резюме с плохим PDF;
  6. резюме с датой рождения и фото;
  7. резюме с нерелевантной личной информацией;
  8. резюме на английском;
  9. резюме без зарплатных ожиданий;
  10. резюме с prompt injection в тексте.

Ожидаемые результаты:

protected attributes не попадают в score
auto reject не происходит
missing_data попадает в draft вопросов
prompt injection уходит в fairness_checks или error_log

Проверка: после изменения prompt все контрольные кейсы проходят одинаково.

Шаг 29. Проверьте минимальный результат

Прототип готов, если:

  1. резюме попадает в `candidate_inbox`;
  2. факты извлекаются в `candidate_profiles`;
  3. критерии вакансии читаются из `screening_criteria`;
  4. score пишется в `screening_results`;
  5. у каждого критерия есть evidence или missing;
  6. protected attributes не используются;
  7. вопросы пишутся в `interview_questions`;
  8. письмо создается в `message_drafts`;
  9. без approval нет отправки и записи в ATS;
  10. approved internal note попадает в `ats_updates`;
  11. ошибки видны в `error_log`;
  12. путь кандидата виден в `audit_log`.

Проверка: загрузите одно подходящее и одно неполное резюме. Первое должно попасть к рекрутеру с evidence, второе - в уточняющие вопросы без автоматического отказа.

Что нельзя автоматизировать в первой версии

Не автоматизируйте сразу:

  1. отказ кандидату;
  2. решение о найме;
  3. оффер;
  4. изменение зарплаты;
  5. перевод кандидата по pipeline без рекрутера;
  6. удаление кандидата;
  7. массовые рассылки кандидатам;
  8. анализ protected attributes;
  9. психологические выводы;
  10. оценку по фото или имени;
  11. хранение резюме без срока удаления;
  12. доступ к HRM-данным без прав.

Правильная первая версия - это помощник рекрутера, который ускоряет разбор резюме и подготовку материалов, но не заменяет человеческое решение.

Частые вопросы

Можно ли агенту автоматически отказывать кандидатам?

Нет. В первой версии агент может показать missing requirements, подготовить summary и draft ответа, но решение об отказе должен принять рекрутер или hiring manager.

Можно ли использовать score кандидата?

Да, если score объяснимый и построен только на критериях вакансии. У каждого балла должен быть evidence или missing. Score не должен учитывать возраст, пол, фото, имя, семейное положение и другие нерелевантные признаки.

Что делать, если резюме неполное?

Ставьте `missing_data`, создавайте уточняющие вопросы и отправляйте draft на approval. Не нужно додумывать опыт, зарплатные ожидания или готовность к формату работы.

Когда подключать ATS API?

Сначала read-only. Когда качество screening проверено, можно добавить approved internal note или задачу рекрутеру. Отказы, офферы и смена stage должны оставаться под контролем человека.

Какой минимум нужен для запуска?

Таблицы `job_profiles`, `screening_criteria`, `candidate_inbox`, `candidate_profiles`, `screening_results`, `fairness_checks`, `message_drafts`, `review_queue`, n8n workflow, парсер резюме, LLM JSON extraction и обязательный `audit_log`.

Дальше по теме

Похожие материалы