How Hiring Agent Extracts Key Strengths and Areas for Improvement from Resumes
The system identifies key strengths and areas for improvement through a three-stage pipeline: parsing raw resumes into structured JSON, prompting an LLM with a specific evaluation template to grade candidate attributes, and flattening the results into semicolon-separated CSV columns.
The interviewstreet/hiring-agent repository automates candidate screening by extracting actionable insights directly from resume content. This open-source tool uses a structured evaluation pipeline to surface both competitive advantages and development gaps in applicant profiles. Understanding this workflow reveals how generative AI transforms unstructured resume text into standardized recruitment data.
The Resume Evaluation Pipeline
The identification of key strengths and areas for improvement occurs through a coordinated sequence involving data modeling, LLM orchestration, and data transformation.
Step 1: Structured Resume Parsing
Raw resume files (PDF, DOCX) first undergo normalization into a strongly-typed JSONResume object defined in main/models.py. This parser standardizes sections including basics, work, education, skills, and projects into a consistent schema that downstream components can consume.
Step 2: LLM-Driven Attribute Extraction
The ResumeEvaluator class in main/evaluator.py orchestrates the core intelligence layer. It loads a prompt template named resume_evaluation_criteria via the TemplateManager:
criteria_template = self.template_manager.render_template(
"resume_evaluation_criteria", text_content=resume_text
)
This prompt explicitly instructs the LLM to return two JSON arrays:
key_strengths: A list of the candidate’s strongest professional attributesareas_for_improvement: A list of skills or experiences requiring development
The LLM response is forced into the EvaluationData schema (defined in main/models.py) using the provider’s format argument, guaranteeing that both fields appear as lists of strings regardless of input variability.
Step 3: CSV Transformation
The transform_evaluation_response function in main/transform.py (lines 731–738) handles the final data shaping. It extracts the two lists from the EvaluationData instance and joins them into semicolon-separated strings suitable for tabular export:
# Lines 731-738 in transform.py
if evaluation and hasattr(evaluation, "key_strengths"):
csv_row["key_strengths"] = "; ".join(evaluation.key_strengths)
else:
csv_row["key_strengths"] = ""
if evaluation and hasattr(evaluation, "areas_for_improvement"):
csv_row["areas_for_improvement"] = "; ".join(evaluation.areas_for_improvement)
else:
csv_row["areas_for_improvement"] = ""
This transformation ensures the final CSV contains human-readable columns populated directly from the LLM’s semantic analysis of the resume.
Implementation Example
The following workflow demonstrates how to process a resume and extract the evaluation fields:
from evaluator import ResumeEvaluator
from transform import transform_evaluation_response, convert_json_resume_to_text
# 1. Load raw résumé text (e.g. from a PDF)
with open("candidate_resume.pdf", "rb") as f:
resume_text = extract_text_from_pdf(f) # helper in pdf.py
# 2. Ask the LLM to evaluate the résumé
evaluator = ResumeEvaluator()
evaluation = evaluator.evaluate_resume(resume_text) # returns EvaluationData
# 3. Convert the raw JSONResume (already parsed elsewhere) to a CSV row
csv_row = transform_evaluation_response(
file_name="candidate_resume.pdf",
resume_data=parsed_resume, # instance of JSONResume
github_data=None, # optional GitHub enrichment
evaluation=evaluation
)
print(csv_row["key_strengths"])
print(csv_row["areas_for_improvement"])
Example Output:
key_strengths: "Strong backend engineering, Excellent problem-solving, Proven open-source contributions"
areas_for_improvement: "Limited front-end experience, No formal leadership roles"
Core Source Files
The following modules implement the strength and weakness identification logic:
main/models.py– DefinesJSONResumeandEvaluationDataPydantic models, including thekey_strengthsandareas_for_improvementlist fieldsmain/evaluator.py– ContainsResumeEvaluator.evaluate_resume(), which orchestrates the LLM call and schema validationmain/prompts/template_manager.py– Loads theresume_evaluation_criteriaprompt template used to solicit structured feedbackmain/prompts/resume_evaluation_criteria.txt– The raw prompt text explicitly requesting JSON arrays for strengths and improvement areasmain/transform.py– Lines 731–738 contain the extraction logic that flattensEvaluationDatainto CSV-compatible strings
Summary
- Structured Input: Raw resumes convert to
JSONResumeobjects before evaluation, normalizing variable document formats - Schema Enforcement: The
EvaluationDatamodel guaranteeskey_strengthsandareas_for_improvementfields exist as string lists via Pydantic validation - Prompt Engineering: The
resume_evaluation_criteriatemplate explicitly directs the LLM to return the two specific JSON arrays required for downstream processing - CSV Integration: The
transform_evaluation_responsefunction inmain/transform.pysafely extracts and joins these lists with semicolon delimiters for spreadsheet compatibility
Frequently Asked Questions
What prompt template generates the key strengths and areas for improvement?
The system uses resume_evaluation_criteria.txt (loaded via TemplateManager in main/prompts/template_manager.py) to instruct the LLM. This template explicitly requests two JSON arrays named key_strengths and areas_for_improvement containing concise string evaluations of the candidate’s profile.
How does the system ensure both evaluation fields are always present?
The ResumeEvaluator forces LLM responses into the EvaluationData Pydantic model defined in main/models.py. This schema validation requires both key_strengths and areas_for_improvement to exist as lists of strings, preventing malformed or partial responses from propagating through the pipeline.
Where does the semicolon-separated formatting occur?
The transformation happens in main/transform.py at lines 731–738. The transform_evaluation_response function checks for the attributes using hasattr(), then applies "; ".join() to convert the Python lists into strings suitable for CSV export columns.
Can the evaluation pipeline process resumes without supplementary GitHub data?
Yes. The transform_evaluation_response function accepts github_data=None as a valid parameter. The strength and improvement extraction depends solely on the EvaluationData instance and the parsed JSONResume object, making GitHub enrichment optional for basic resume evaluation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →