TalentArch-AI: Building an Architectural Talent Matching Agent
How I Automated Skill-First Technical Recruitment Using Hybrid-Search RAG and Score Fusion
TL;DR
I experimented with building an autonomous talent acquisition agent called TalentArch-AI. In my experience, traditional keyword matching fails to capture the "vibe" of an architect, while pure semantic search often misses non-negotiable certifications. As per my opinion, the solution lies in a Hybrid-Search RAG pipeline that fuses BM25 keyword scores with semantic vector similarity. I wrote this PoC to prove that we can automate the "Architectural Fit" assessment, reducing the manual screening load by focusing on candidates who match both the stack and the seniority profile.
Introduction
I've spent a lot of time thinking about why technical recruiting is so manual. In my opinion, it’s because we try to solve a high-dimensional problem (human skill) with one-dimensional tools (Boolean search strings). From what I observed, most hiring managers are looking for a specific "architectural signature"—a blend of hands-on tool expertise and high-level system design thinking.
I put it this way because I’ve seen countless "Senior Engineers" who can recite LeetCode but can't design a CI/CD pipeline. I decided to build TalentArch-AI as one of my experiments to see if I could automate the identification of this signature. This isn't a production tool, but rather an experimental article exploring the intersection of Hybrid RAG and HR Tech.
What's This Article About?
In this experiment, I’m deep-diving into the mechanics of Hybrid Retrieval. I’ll show you how I built a system that doesn't just "search" for resumes but "architecturally matches" them. We’ll look at:
- Dual-Path Retrieval: Implementing BM25 alongside semantic vector search.
- Weighted Score Fusion: How I tweaked the weights to prioritize conceptual fit.
- Visualization of Precision: Using radar and bar charts to quantify a "match."
Tech Stack
From my experience, a PoC needs to be lightweight but robust. I chose:
- Python: The backbone of my experiments.
- Rank-BM25: For the classic keyword matching logic.
- Matplotlib/Numpy: To generate the statistical views I love.
- Local RAG logic: Simulating the RAG pipeline I often see in larger projects.
Why Read It?
If you've ever wondered how to make RAG systems more accurate for specific domains like HR, this is for you. In my opinion, the "Semantic-Only" approach is overrated for technical roles. If a job requires "AWS Certified Solutions Architect," a conceptual match for "Cloud Expert" isn't good enough. I think the hybrid approach is the only way to ensure 100% compliance with hard requirements while keeping the search "smart."
Let's Design
I sat down and sketched the flow. I thought, "How would I, as a human, screen a resume?" First, I look for the keywords. Then, I read the summary to gauge the 'seniority level'.
As per my opinion, the agent should do exactly that. The system architecture flow looks like this:
The sequence of operations is critical. I wanted concurrent retrieval to minimize latency, followed by a fusion step that acts as the "Decision Maker."
Let’s Get Cooking
I started by defining the mock talent data. I think it’s important to have a diverse set of "Seniority-heavy" vs "Skill-heavy" candidates. I put it this way because I wanted to test the fusion logic's edge cases.
The Hybrid Search Core
I wrote this class to encapsulate the dual-scoring logic. In my opinion, the _simulated_vector_score is where the "vibe" is captured.
def hybrid_search(self, query: str, top_k: int = 3, semantic_weight: float = 0.6):
tokenized_query = query.lower().split()
bm25_scores = self.bm25.get_scores(tokenized_query)
# Normalizing BM25 to (0, 1) range
max_bm25 = max(bm25_scores) if max(bm25_scores) > 0 else 1
normalized_bm25 = [s / max_bm25 for s in bm25_scores]
results = []
for i, candidate in enumerate(self.candidates):
sem_score = self._simulated_vector_score(query, candidate)
# The Fusion: 60% Semantic, 40% Keyword
hybrid_score = (semantic_weight * sem_score) + ((1 - semantic_weight) * normalized_bm25[i])
results.append({"candidate": candidate, "score": hybrid_score})
return sorted(results, key=lambda x: x['score'], reverse=True)[:top_k]
Why this matters: I used a weight of 0.6 for semantic search because, in my experience, the context of the summary is a better indicator of success than just listing "React" ten times. However, that 0.4 weight on keywords ensures that if the candidate doesn't mention "CI/CD," they won't top the list for a DevOps role.
The Architectural Reporting
I think a good agent needs to explain why it picked someone. I implemented an ASCII report generator to mirror the terminal experience.
def generate_report(self, query: str, top_candidates: List[Dict]):
print(f" TARGET PROFILE: {query}")
print(f"{'CANDIDATE NAME':<25} | {'ROLE':<25} | {'HYBRID SCORE':<12}")
for res in top_candidates:
c = res['candidate']
print(f"{c['name']:<25} | {c['role']:<25} | {res['score']:<12}")
Let's Setup
Step-by-step details can be found at my GitHub repository. I’ve made sure to include the mock_resumes.json so you can replicate this experiment locally.
- Clone the Repo:
git clone https://github.com/aniket-work/talent-arch-ai.git - Environment:
python3 -m venv venv && source venv/bin/activate - Dependencies:
pip install -r requirements.txt
Let's Run
When I finally ran the system, I observed some fascinating results. For a search like "Cloud Native Engineer with Python," the agent weighted Jordan Smith highly for their DevOps experience, but Sarah Chen stayed in the top bracket because of her strong Python/AI background.
As per my opinion, the distribution shows that the "Hybrid-Match" creates a much tighter selection than a simple keyword filter.
I think the 60/40 split is the "Sweet Spot" for early-stage experiments.
Closing Thoughts
This experiment reinforced my belief that the future of recruiting isn't just "AI," but Domain-Specific Hybrid AI. I wrote this because I want to encourage others to look past the "Vector-Only" hype. From my experience, the best results often come from merging the 'old school' (Lucene/BM25) with the 'new school' (Embeddings).
I put it this way: The keywords tell you what they can do, but the semantics tell you who they are.
Disclaimer
The views and opinions expressed here are solely my own and do not represent the views, positions, or opinions of my employer or any organization I am affiliated with. The content is based on my personal experience and experimentation and may be incomplete or incorrect. Any errors or misinterpretations are unintentional, and I apologize in advance if any statements are misunderstood or misrepresented.
GitHub Repository: aniket-work/talent-arch-ai






Top comments (0)