Hybrid AI ranking system that matches candidates to the Senior AI Engineer role at Redrob AI. Combines sentence-transformer semantic embeddings with multi-dimensional rule-based scoring and behavioral signal analysis — going far beyond keyword matching to understand who genuinely fits the role.
Team: TEAM GG | Leader: GOWTHAM MP
pip install -r requirements.txt
# Step 1: Pre-compute semantic embeddings (runs once, ~10-15 min on CPU)
python precompute.py --candidates ./candidates.jsonl
# Step 2: Produce the ranked submission CSV (~30s on CPU)
python rank.py --candidates ./candidates.jsonl --out ./submission.csv
# Validate
python validate_submission.py submission.csvRuntime: ~30 seconds for the ranking step (100K candidates). No GPU, no network, no API calls during ranking.
candidates.jsonl (100K profiles)
|
+-----------------------------------+
| |
v v
+----------------------+ +------------------------------+
| SEMANTIC SCORING | | RULE-BASED SCORING |
| (35% of final) | | (65% of final) |
| | | |
| all-MiniLM-L6-v2 | | Title Relevance (25%) |
| 384-dim embeddings | | Core Skills Match (20%) |
| | | Career Trajectory (20%) |
| JD -> embedding | | Broad Skills (10%) |
| Candidate -> embed | | Experience Band (10%) |
| Cosine similarity | | Location + Edu + Assess (15%)|
+------+---------------+ +----------+-------------------+
| |
+-----------+-------------------+
|
v
+---------------------+
| HYBRID FUSION |
| 0.35*sem + 0.65*rule|
+----------+----------+
|
v
+---------------------+
| BEHAVIORAL |
| MULTIPLIER |
| (0.3x - 1.2x) |
| 12 engagement |
| signals |
+----------+----------+
|
v
+---------------------+
| HONEYPOT FILTER |
| + RANK TOP 100 |
| + GENERATE REASONING|
+----------+----------+
|
v
submission.csv
| Approach | What it catches | What it misses |
|---|---|---|
| Pure semantic (embeddings only) | Latent role similarity from free-text summaries | Structured disqualifiers, exact experience bands, honeypots |
| Pure rule-based (features only) | Explicit JD requirements, consulting penalties, date validation | Nuanced descriptions that indicate fit without using exact keywords |
| Hybrid (ours) | Both -- embeddings surface candidates whose descriptions match even if keywords don't; rules enforce hard constraints the JD explicitly states | -- |
- Model:
all-MiniLM-L6-v2(22M params, 384 dimensions) - Pre-computed offline by
precompute.py-- encodes each candidate's headline, summary, career descriptions, skills, and education into a 384-dimensional vector - JD encoded as a dense semantic query capturing role intent
- Cosine similarity between JD and each candidate, normalized to [0, 1]
- Catches candidates whose career descriptions signal fit (e.g., "built a recommendation engine at scale") even if they don't list specific keywords
| Component | Weight | What it measures |
|---|---|---|
| Title relevance | 25% | Current + historical job titles vs AI/ML engineering roles |
| Core skills | 20% | Must-have skills (embeddings, vector DBs, Python, eval frameworks) |
| Career trajectory | 20% | Product vs consulting, production ML signals, job stability |
| Broad skills | 10% | Wider AI/ML skill coverage |
| Experience band | 10% | Proximity to 5-9 year sweet spot |
| Location | 5% | India preferred, specific cities best |
| Education | 5% | Field relevance, institution tier, degree level |
| Assessments | 5% | Platform skill assessment scores |
12 engagement signals: last-active recency, open-to-work flag, recruiter response rate, response time, profile completeness, interview completion rate, notice period, GitHub activity, verification status, saved-by-recruiters, offer acceptance rate, work mode preference.
Catches ~42 impossible profiles:
- Impossible tenure (claimed months >> actual date range)
- Expert skills with 0 months of use
- 10+ expert skills with near-zero endorsements
- Career months wildly exceeding stated YOE
rank.py Hybrid ranker (semantic + rule-based + behavioral)
precompute.py Generates sentence-transformer embeddings
artifacts/ Pre-computed embeddings (generated by precompute.py)
jd_embedding.npy JD vector (1 x 384)
candidate_embeddings.npy All candidates (100K x 384)
candidate_ids.json Ordered candidate ID list
submission.csv Generated output (top 100 candidates)
requirements.txt Dependencies (numpy, sentence-transformers)
submission_metadata.yaml Hackathon metadata
TEAM_GG_Presentation.pptx Presentation deck
TEAM_GG_Presentation.pdf PDF version
Hybrid over pure-semantic or pure-rule-based. The JD explicitly warns that keyword matching is a trap -- but pure embeddings also fail because they can't enforce structured constraints (experience years, consulting-only penalty, honeypot detection). The hybrid approach lets each method cover the other's blind spots.
35/65 semantic/rule split. Rules are weighted higher because the JD is unusually specific about disqualifiers and requirements. In a more generic matching system, semantic weight would be higher.
Multiplicative behavioral scoring. A technically perfect but unresponsive candidate gets properly down-weighted (0.95 x 0.3 = 0.28). This matches the JD's explicit guidance about availability signals.
Pre-computed embeddings. Encoding 100K candidates takes ~10-15 minutes on CPU. This runs once offline. The ranking step loads the vectors and computes cosine similarity in seconds -- well within the 5-minute budget.
# Full pipeline (including pre-computation)
pip install -r requirements.txt
python precompute.py --candidates ./candidates.jsonl
python rank.py --candidates ./candidates.jsonl --out ./submission.csv
# Ranking step only (if artifacts/ already exists)
python rank.py --candidates ./candidates.jsonl --out ./submission.csv