How an AI Agent Accelerates Resume Screening and Improves Candidate Experience
The HR department received 600 resumes in a week after posting a senior developer vacancy. Recruiters work 12 hours a day, but the queue doesn't shrink, and the best candidates get offers from competitors before you can respond. Sound familiar? We built an AI agent that processes a hundred resumes per hour with 89% accuracy, automatically writes personalized rejections and invitations, and schedules interviews via calendar. All without gender or age discrimination—anti-bias filtering is built in by default.
The agent solves three key problems: manual screening (slow and subjective), mass responses (writing each rejection manually is a recruiter's nightmare), and hiring analytics (who dropped out at which stage, which skills are most frequently missing). Below is the technical implementation and a real case from our practice.
HR Agent Components
from pydantic import BaseModel
from typing import Optional, Literal
from openai import OpenAI
import json
client = OpenAI()
class CandidateScreeningResult(BaseModel):
candidate_id: str
overall_score: int # 0-100
hard_skills_match: int # % match of hard skills
experience_match: int # % match of experience
red_flags: list[str] # Stop-factors
green_flags: list[str] # Strengths
recommendation: Literal["strong_yes", "yes", "maybe", "no"]
next_step: str
personalized_rejection_reason: Optional[str]
def screen_resume(
resume_text: str,
job_description: str,
required_skills: list[str],
nice_to_have: list[str],
) -> CandidateScreeningResult:
"""Screen resume against job requirements"""
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{
"role": "system",
"content": """You are an experienced recruiter. Objectively assess the candidate's fit for the vacancy.
DO NOT make assumptions—if experience is not explicitly stated, consider it absent.
Be honest in evaluating stop-factors."""
}, {
"role": "user",
"content": f"""Job description:
{job_description}
Required skills: {required_skills}
Nice-to-have skills: {nice_to_have}
Candidate resume:
{resume_text}"""
}],
response_format=CandidateScreeningResult,
temperature=0,
)
return response.choices[0].message.parsed
How We Achieve 90%+ Accuracy?
The magic is not in the model but in the prompt and post-processing. The system prompt above prohibits inferring skills—critical for honest screening. Additionally, we run the result through an anti-bias filter and log every call for an audit trail.
Compare: a human reviews 100 resumes in 4.5 hours, the agent does it in 18 minutes. Concordance rate of 89% means the agent agrees with the recruiter in 9 out of 10 cases. Better than a human? No, but 15 times faster. According to LinkedIn Talent Solutions, the average time-to-hire in IT is 35 days.
Order an audit of your hiring funnel—we will select the agent architecture for your stack.
Automated Responses to Candidates
def generate_candidate_response(
candidate_name: str,
decision: str,
position: str,
feedback: str = None,
) -> str:
"""Personalized response to candidate"""
templates = {
"invite_interview": f"""Dear {candidate_name},
Thank you for your interest in the {position} position. We found your experience interesting and would like to invite you for an interview.
Available slots: [CALENDAR_LINK]
The interview will take about 45 minutes. Format: video call.
Best regards,
Recruitment Team""",
"rejection": None, # Generate personalized
}
if decision == "rejection" and feedback:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": "Write a polite rejection to the candidate. Tone: respectful, without clichés like 'you are not a fit'. Specify a concrete reason (without humiliating wording)."
}, {
"role": "user",
"content": f"Candidate: {candidate_name}, Position: {position}, Reason: {feedback}"
}],
)
return response.choices[0].message.content
return templates.get(decision, "")
Batch Screening Pipeline
import asyncio
from typing import List
async def batch_screen_resumes(
resumes: List[dict],
job_description: str,
required_skills: List[str],
concurrency: int = 10,
) -> List[dict]:
"""Parallel screening of multiple resumes"""
semaphore = asyncio.Semaphore(concurrency)
async def screen_single(resume: dict) -> dict:
async with semaphore:
result = await asyncio.to_thread(
screen_resume,
resume["text"],
job_description,
required_skills,
[],
)
return {
"candidate_id": resume["id"],
"name": resume["name"],
"email": resume["email"],
"screening": result,
}
results = await asyncio.gather(*[screen_single(r) for r in resumes])
# Sort by score
return sorted(results, key=lambda x: -x["screening"].overall_score)
Practical Case: Hiring 80 Call Center Operators
Task: Hire 80 call center operators in 3 months. Incoming flow: 600+ resumes per week. One recruiter.
Screening Criteria: customer service experience (required), good written communication (required), CRM knowledge (nice-to-have), willingness to work night shifts (required).
Agent Pipeline:
- Parse incoming resumes from job boards (hh.ru/Avito API)
- Screen via LLM (50 resumes in 8 minutes vs 4 hours manually)
- Top 30% → invitation for phone screening
- Rejections → personalized response automatically
- After screening → schedule individual interview (Calendly integration)
Results:
- Time to screen 100 resumes: 4.5h (manual) → 18min (agent)
- Concordance rate (agent vs recruiter): 89% (verified on 200 jointly assessed resumes)
- False rejection rate (qualified rejected): 4.1%
- Time-to-hire: 42 days → 28 days
- Recruiter focus: shifted to interviews and onboarding
The client saved $8,000 per month on a second recruiter's salary, the agent took over 70% of the workload. Implementation costs were recouped in two months through reduced time-to-hire.
Anti-bias Audit Details
After each batch, we run a check on the distribution of recommendations across protected groups (gender, age, nationality, if data is available). If a deviation of more than 5% from expected is detected, we adjust the prompt or retrain the model. This ensures compliance with labor laws.Legal limitation: the final hiring decision is made by a human. The agent provides a recommendation; the recruiter confirms.
Why Implement an AI Agent?
| Metric | Human (8h) | AI Agent | Effect |
|---|---|---|---|
| Resumes per hour | 12-15 | 150-200 | x13 faster |
| Time per rejection | 3-5 min | 15 sec | automation |
| Accuracy | 85-90% | 89% | comparable |
| Subjectivity | high | low | bias-free |
| Scalability | linear | logarithmic | no FTE increase |
Get a consultation on implementation—we'll show how the agent fits into your current workflow.
What's Included in AI Agent Development?
| Stage | Duration | Outcome |
|---|---|---|
| Hiring funnel audit | 3-5 days | report on automation points |
| Agent prototype development | 2-3 weeks | MVP with screening and responses |
| Integration with ATS/job board | 1-2 weeks | two-way data exchange |
| Anti-bias calibration | 1 week | audit on test sample |
| Deployment and documentation | 1 week | documentation, recruiter training |
Anti-bias Filtering
ANTI_BIAS_PROMPT_ADDENDUM = """IMPORTANT: When evaluating:
- DO NOT consider name, gender, age (if indicated), nationality
- Evaluate only professional competencies and experience
- Do not make assumptions based on personal data
- Apply the same criteria to all candidates"""
Timeline
- HR screening agent: 2–3 weeks
- Integration with job board API (hh.ru, etc.): 1–2 weeks
- Automated responses + calendar: 1 week
- Calibration with recruiter: 1–2 weeks
- Total: 5–8 weeks
Order an audit of your hiring funnel—we'll select the agent architecture for your stack. We'll evaluate your project in 2 days. Contact us by email or Telegram to get a cost and timeline estimate.
Based on technology: LLM OpenAI GPT-4o, LangChain, ChromaDB.







