Why Resume-Job Matching Fails: Breaking Through the Limits of Embedding Similarity

Why embedding similarity fails for resume-job matching and how to fix it with hybrid approaches.
SOTA embedding models often fail at resume-job matching due to vocabulary overlap traps and the inherent asymmetry of the task. This article explores why cosine similarity falls short and presents a practical path forward: structured field extraction, domain-specific fine-tuning with hard negatives, two-stage retrieval with reranking, and LLM-based matching for explainable, recruiter-quality results.
An Underestimated NLP Challenge
In the recruiting technology space, semantic matching between resumes and job descriptions (CV ↔ Job) seems like a standard text similarity task — but practitioners keep hitting walls. Recently, a Reddit developer raised a question that struck a chord with many: Why do state-of-the-art (SOTA) embedding models perform so poorly on resume-job matching?
This developer was building a resume-to-job matching system and admitted: "Embedding similarity barely works — the results are mediocre at best. Skill vocabulary overlaps so heavily that every job looks like a match, even positions that are clearly unsuitable for the candidate still get high similarity scores."

This is not an isolated case. In fact, even embedding models that perform excellently in general domains often fall flat in this vertical scenario. Understanding why is the first step toward building a usable system.
Why Do SOTA Embedding Models Fail at Resume Matching?
The Vocabulary Overlap Trap
The core objective of general-purpose embedding models is to capture overall semantic similarity between texts. But in resume-job matching, this "overall similarity" is precisely what leads you astray.
A data engineer's resume and a data analyst's job description will share a large number of high-frequency skill terms — Python, SQL, data pipelines, visualization, and so on. From a pure semantic standpoint, the vector distance between the two texts is small. But from an actual hiring decision perspective, the core responsibilities, seniority levels, and tech stack depth of these two roles can be vastly different.
Embedding models cannot distinguish between "mentioning a skill" and "being proficient in it as a core competency." They also struggle to understand structured constraints like seniority level (junior vs. senior), employment type, and industry context.
The Asymmetry of Matching
Another overlooked issue: resume-job matching is fundamentally asymmetric. Job descriptions typically list hard requirements that "must be met" and soft requirements that are "nice to have," while resumes are free-form narratives of a candidate's experience. An ideal matching algorithm needs to determine "whether the candidate meets the job requirements" — not "whether the two texts are similar."
General-purpose cosine similarity is a symmetric metric and inherently cannot express this "fulfills/is fulfilled by" logical relationship.
From "Barely Works" to "Actually Works": A Path Forward
Addressing the directions the original poster raised — fine-tuning, structured field extraction, reranking — industry practice offers some clear answers.
Step 1: Structured Field Extraction
The most effective and cost-efficient improvement is often to start with information structuring. Rather than feeding entire resumes and job descriptions into an embedding model, first use LLMs or specialized parsers to extract key fields:
- Skill entities: Distinguish core skills from merely mentioned skills
- Years of experience: Explicit quantitative metrics
- Seniority level: Junior / Mid-level / Senior / Management
- Industry and domain: Finance, healthcare, e-commerce, etc.
- Education and certifications
Once structured, matching shifts from "fuzzy semantic comparison" to "field-level rule + semantic hybrid scoring." For example, years of experience can be hard-filtered with numerical constraints, skills can be set-matched, and embedding similarity is only used for descriptive content.
Step 2: Domain Fine-Tuning to Improve Matching Accuracy
The representation space of general-purpose embedding models is not optimized for recruitment scenarios. If you have sufficient labeled data (e.g., positive samples where "this resume successfully landed this job" and negative samples of rejections), contrastive learning fine-tuning of the embedding model can significantly improve results.
The key lies in negative sample construction: you can't just use random negatives — you need hard negatives that "look similar but actually don't match" — such as positions in the same domain but at different seniority levels. This is precisely where general models fail, and where fine-tuning delivers the greatest gains.
Step 3: Introduce Reranking
Embedding-based retrieval works well for rough recall but lacks precision. Mature matching systems typically adopt a two-stage architecture:
- Recall stage: Use embedding similarity to quickly filter a candidate job set (Top-K)
- Reranking stage: Use a Cross-Encoder or LLM to do fine-grained scoring on each candidate pair
Cross-Encoders see the full content of both the resume and the job description simultaneously, modeling the interaction between them through attention mechanisms and capturing fine-grained signals that bi-encoder embedding models miss. While computationally more expensive, they only run on a small candidate set, making the overall cost acceptable.
New Matching Paradigms in the LLM Era
As large language model capabilities improve, a new paradigm is emerging: using LLMs to directly make matching judgments.
By providing the resume and job description as context, you can have an LLM output matching rationale and scores from a "recruiter's" perspective. The advantages of this approach include:
- Understanding implicit seniority requirements and responsibility alignment
- Providing explainable matching rationale instead of a black-box score
- Naturally handling the asymmetric "meets requirements" logic
In practice, an efficient combination is: embedding recall + LLM reranking. Use lightweight embeddings to quickly narrow the scope, then let the LLM do deep evaluation on a small number of candidates. This controls costs while approaching the judgment quality of a human recruiter.
Advice for Practitioners
If you're also stuck at the "barely works" stage, try the following in order of priority:
- Start with structured extraction — Best ROI; immediately solves false matches caused by skill vocabulary overlap
- Build a two-stage architecture — Embedding recall + Cross-Encoder/LLM reranking
- Do domain fine-tuning when you have data — Focus on constructing hard negatives
- Embrace LLM explainability — Matching rationale is often more valuable to the business than the score itself
The core challenge of resume-job matching is fundamentally not a "text similarity" problem — it's a "capability-to-requirement alignment" problem. Breaking free from the mindset of pure embedding similarity and adopting a hybrid approach combining structure + semantics + reasoning is the right path to a production-grade system.
Related articles

Devin CLI Model Picker: A Deep Dive into One-Click Model Switching and Cost Comparison
Devin CLI adds a Model Picker feature for viewing available models, comparing costs, and switching effort levels. A deep dive into its three core capabilities and practical value for AI coding workflows.

AI Beginner's Guide: Three Stages to Building Your Own Personal AI Assistant from Scratch
No tech background? No problem. This beginner's guide maps out a 3-stage path to building a personal AI assistant — from prompt engineering to no-code automation to API calls.

Zero to Vibe Coding in Seven Days: A Complete Beginner's Guide to AI Programming
A beginner's guide to Vibe Coding: learn the 6-step path covering Claude Code, Cursor, Codex, prompt engineering, and project practice to build products with AI.