AI Рекрутер — цифровой сотрудник для найма
AI Рекрутер автоматизирует полный цикл подбора персонала: парсинг вакансий в job description, публикация на платформах, скрининг входящих резюме, scheduling интервью, персонализированная коммуникация с кандидатами, ведение воронки в ATS. Позволяет одному рекрутеру управлять значительно большим объёмом вакансий без потери качества.
Генератор Job Description
from openai import AsyncOpenAI
from pydantic import BaseModel
client = AsyncOpenAI()
class JobDescription(BaseModel):
title: str
department: str
level: str
responsibilities: list[str]
required_skills: list[str]
preferred_skills: list[str]
about_team: str
compensation_range: str
async def generate_job_description(
hiring_manager_brief: str,
similar_jd_examples: list[str] = None,
) -> str:
"""Генерирует JD из краткого брифинга от нанимающего менеджера"""
examples_context = ""
if similar_jd_examples:
examples_context = f"\nПримеры похожих вакансий для стиля:\n{similar_jd_examples[0][:500]}"
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Ты — опытный HR. Пиши job descriptions, которые привлекают сильных кандидатов.
Избегай: требований-списков из 20 пунктов, нереалистичных требований, корпоративного новояза.
Фокус: что будет делать человек, почему это интересно, кто нам нужен.{examples_context}"""
}, {
"role": "user",
"content": f"Бриф от нанимающего менеджера:\n{hiring_manager_brief}",
}],
temperature=0.4,
)
return response.choices[0].message.content
Мульти-платформенная публикация
class JobBoardPublisher:
async def publish_to_all_boards(self, jd: JobDescription) -> dict:
"""Публикует вакансию на всех платформах одновременно"""
results = await asyncio.gather(
self.publish_hh(jd),
self.publish_avito_rabota(jd),
self.publish_linkedin(jd),
self.publish_superjob(jd),
return_exceptions=True,
)
return {
"hh.ru": results[0] if not isinstance(results[0], Exception) else str(results[0]),
"avito": results[1] if not isinstance(results[1], Exception) else str(results[1]),
"linkedin": results[2] if not isinstance(results[2], Exception) else str(results[2]),
"superjob": results[3] if not isinstance(results[3], Exception) else str(results[3]),
}
async def publish_hh(self, jd: JobDescription) -> str:
response = await hh_api.post(
endpoint="/vacancies",
data={
"name": jd.title,
"area": {"id": "1"}, # Москва
"description": format_for_hh(jd),
"key_skills": [{"name": s} for s in jd.required_skills[:10]],
"employment": {"id": "full"},
"schedule": {"id": "fullDay"},
}
)
return response["id"]
Скрининг и ранжирование кандидатов
class CandidateScreener:
async def screen_batch(
self,
candidates: list[dict],
job_description: JobDescription,
required_skills: list[str],
) -> list[dict]:
"""Параллельный скрининг кандидатов"""
semaphore = asyncio.Semaphore(10)
async def screen_one(candidate: dict) -> dict:
async with semaphore:
return await self._screen_single(
candidate, job_description, required_skills
)
results = await asyncio.gather(*[screen_one(c) for c in candidates])
return sorted(results, key=lambda x: -x["score"])
async def _screen_single(
self,
candidate: dict,
jd: JobDescription,
required_skills: list[str],
) -> dict:
from pydantic import BaseModel
from typing import Literal
class ScreeningResult(BaseModel):
score: int # 0-100
recommendation: Literal["strong_yes", "yes", "maybe", "no"]
required_skills_match: int # процент совпадения
experience_match: str
red_flags: list[str]
green_flags: list[str]
personalized_question: str # Вопрос для интервью
result = await client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Оцени кандидата объективно. Требуемые навыки: {required_skills}.
НЕ делай предположений о скрытых навыках. Учитывай ТОЛЬКО явно указанный опыт."""
}, {
"role": "user",
"content": f"Вакансия:\n{jd.title}\n\nРезюме:\n{candidate['resume_text']}"
}],
response_format=ScreeningResult,
temperature=0,
)
return {
"candidate_id": candidate["id"],
"name": candidate["name"],
"email": candidate["email"],
**result.choices[0].message.parsed.model_dump(),
}
Автоматизация коммуникации
class CandidateCommunicator:
async def send_invite(self, candidate: dict, vacancy: dict) -> None:
invite_text = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": "Напиши приглашение на интервью. Тон: уважительный, конкретный. 3-4 предложения."
}, {
"role": "user",
"content": f"Кандидат: {candidate['name']}, вакансия: {vacancy['title']}, компания: {vacancy['company']}"
}],
)
await email_service.send(
to=candidate["email"],
subject=f"Приглашение на интервью — {vacancy['title']} в {vacancy['company']}",
body=invite_text.choices[0].message.content + f"\n\nДля записи: {CALENDLY_URL}",
)
async def send_rejection(self, candidate: dict, reason: str) -> None:
"""Персонализированный отказ с конкретной причиной"""
rejection = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": "Напиши вежливый отказ. Без клише. Укажи конкретную причину (уважительно). 2-3 предложения."
}, {
"role": "user",
"content": f"Кандидат: {candidate['name']}, причина отказа: {reason}"
}],
)
await email_service.send(
to=candidate["email"],
subject="Статус вашей заявки",
body=rejection.choices[0].message.content,
)
Практический кейс: IT-компания, 30 открытых вакансий
Ситуация: 3 рекрутера, 30 активных вакансий, 200+ резюме/день, time-to-hire 52 дня.
Автоматизировано AI Рекрутером:
- Парсинг резюме с hh.ru каждые 2 часа
- Скрининг и скоринг (первичная фильтрация 70%)
- Автоматические отказы нерелевантным кандидатам
- Приглашения топ-30% с Calendly-ссылкой
- Напоминания кандидатам не ответившим на интервью-запрос
Результаты:
- Time-to-hire: 52 → 31 день
- Скорость ответа кандидату: 3.2 дня → 40 минут
- Рекрутеры тратят время на: интервью, оффер, онбординг
- Concordance (AI vs рекрутер на 300 совместно оцененных): 87%
Сроки
- JD-генератор и публикация: 1–2 недели
- Скрининг и ранжирование: 2–3 недели
- Коммуникационные шаблоны и интеграция с email: 1 неделя
- ATS-интеграция (HH, Huntflow и пр.): 1–2 недели
- Итого: 5–8 недель







