Back to projectsGenerative AI 
AI-Powered Talent Scouting Agent — concept visual 
Shortlist dashboard featuring Match & Interest scores with feature contribution tables
AI-Powered Talent Scouting Agent
An intelligent recruiting agent that ingests Job Descriptions, discovers matching candidates from a synthetic pool, simulates recruiter outreach, and returns a recruiter-ready shortlist with Match Score, Interest Score, and auditable rationale for every ranking decision.
FastAPIStreamlitPostgreSQL/pgvectorRRF FusionCross-EncoderGemini 2.5 FlashExplainability
View source94%
Top-10 Precision
120 candidates
Synthetic Pool
MiniLM-L6
Reranker Model
Gemini 2.5 Flash
LLM Model
The problem
Recruiters face low precision with keyword filters, manual candidate outreach overhead, and black-box AI scores that lack transparent rationale. Existing screening tools fail to evaluate candidate engagement or calibrate fit scores accurately across technical and logistical constraints.
Key features
- Hybrid Retrieval: Dense vector search (pgvector ANN), Sparse full-text search (BM25), and rules-based scoring
- Reciprocal Rank Fusion (RRF): Blends multi-channel retrieval signals into a unified candidate ranking
- Cross-Encoder Reranker: ms-marco-MiniLM-L6-v2 model for fine-grained semantic precision reranking
- Calibrated Scoring Engine: DPR-defined multi-axis formulas with Sigmoid & Platt calibration
- LLM Outreach Simulator: Gemini 2.5 Flash conversation engine for candidate interest & availability assessment
- Auditable Explainability: Dynamic feature contribution tables providing transparent score breakdowns rather than black-box LLM opinions
- Synthetic Candidate Pool: Pre-populated with 120 synthetic candidate profiles and 10 benchmark Job Descriptions
- Decoupled Architecture: FastAPI + Uvicorn backend with an interactive Streamlit UI dashboard
Architecture
- 1JD Input → JD Parser (Extract skills, experience, title, salary, notice period)
- 2Hard Filter (Apply strict checks on minimum experience, notice period, location)
- 3Hybrid Retrieval (Dense pgvector ANN + Sparse text search + Rule-based scoring)
- 4RRF Fusion (Reciprocal Rank Fusion combining multiple retrieval channels)
- 5Cross-Encoder Reranking (ms-marco-MiniLM-L6-v2 precision scoring)
- 6Match Scoring (Multi-axis feature fit S_f & raw match score M_raw + Sigmoid calibration)
- 7Outreach Simulation (LLM-powered or deterministic candidate engagement)
- 8Interest Scoring (Calibrated interest score I_raw with hard caps for notice & salary)
- 9Final Shortlist + Rationale (ShortlistRankScore = 0.70 * Match + 0.30 * Interest + Feature Contributions)
Important functions
Match Score & Calibrated Interest Score Formulaspython
def calculate_match_score(candidate: Candidate, jd: JobDescription) -> float:
# S_f: Multi-axis hard feature fit score
s_f = (
0.30 * must_have_skills_fit(candidate, jd) +
0.08 * nice_to_have_skills_fit(candidate, jd) +
0.10 * title_match_score(candidate, jd) +
0.12 * experience_fit_score(candidate, jd) +
0.10 * domain_relevance_score(candidate, jd) +
0.12 * past_role_similarity(candidate, jd) +
0.08 * location_fit_score(candidate, jd) +
0.10 * company_tier_fit(candidate, jd)
)
# M_raw: Composite raw score incorporating Cross-Encoder (X), Vector (V), Sparse (K)
m_raw = 0.38 * s_f + 0.30 * cross_encoder_score + 0.17 * dense_sim + 0.15 * sparse_score
return round(100 * calibrate_sigmoid(gate_factor * quality_factor * m_raw), 1)
def calculate_interest_score(sim: OutreachResult) -> float:
# I_raw: Conversation signals & alignment weights
i_raw = (
0.35 * sim.intent_engagement +
0.18 * sim.role_alignment +
0.12 * sim.work_mode_fit +
0.15 * sim.salary_fit +
0.10 * sim.notice_period_fit +
0.06 * sim.growth_qualifiers +
0.04 * sim.flexibility_tolerance
)
calibrated = calibrate_platt(i_raw)
# Apply hard caps for salary misalignment or notice period violations
if sim.salary_exceeded or sim.notice_too_long:
calibrated = min(calibrated, 0.40)
return round(100 * calibrated, 1)Hybrid Retrieval with Reciprocal Rank Fusion (RRF)python
def hybrid_rrf_retrieval(query_vec: list[float], query_text: str, k: int = 60) -> list[Candidate]:
# 1. Dense Vector Search via pgvector ANN
dense_hits = db.query(Candidate).order_by(
Candidate.embedding.l2_distance(query_vec)
).limit(k).all()
# 2. Sparse Text Search (Full-text BM25)
sparse_hits = db.query(Candidate).filter(
Candidate.full_text.match(query_text)
).limit(k).all()
# 3. Reciprocal Rank Fusion (RRF)
rrf_map = {}
C = 60 # RRF constant parameter
for rank, c in enumerate(dense_hits):
rrf_map[c.id] = rrf_map.get(c.id, 0.0) + 1.0 / (C + rank + 1)
for rank, c in enumerate(sparse_hits):
rrf_map[c.id] = rrf_map.get(c.id, 0.0) + 1.0 / (C + rank + 1)
ranked_ids = sorted(rrf_map.keys(), key=lambda cid: rrf_map[cid], reverse=True)
return get_candidates_by_ids(ranked_ids[:k])Cross-Encoder Reranker & Shortlist Rankingpython
from sentence_transformers import CrossEncoder
reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L6-v2")
def build_shortlist(jd: JobDescription, candidates: list[Candidate]) -> list[RankedCandidate]:
pairs = [[jd.text, c.profile_summary] for c in candidates]
rerank_scores = reranker.predict(pairs)
shortlist = []
for candidate, ce_score in zip(candidates, rerank_scores):
match_score = calculate_match_score(candidate, jd)
interest_score = simulate_outreach_and_score(candidate, jd)
# Combined Shortlist Rank Score formula: 70% MatchScore + 30% InterestScore
shortlist_rank_score = 0.70 * match_score + 0.30 * interest_score
shortlist.append(RankedCandidate(
candidate=candidate,
match_score=match_score,
interest_score=interest_score,
shortlist_rank_score=round(rank_score, 1),
feature_contributions=explain_scores(candidate, jd)
))
return sorted(shortlist, key=lambda x: x.shortlist_rank_score, reverse=True)Simulation & screenshots

