Resume extraction is one of those problems that seems simple until you actually try to solve it at scale. Extract a name from a resume, easy. Extract a name, email, phone, skills, experience, education, and 15 other fields from 9,500 resumes across different industries, formats, and quality levels, that is a different challenge.
This is how we built an ML-powered resume extractor that achieves 88.7% accuracy using ensemble methods, transformer-based models, and active learning.
The dataset challenge
We started with the Kaggle resume dataset, 9,544 resumes in various formats. That is a lot of data, but it comes with a problem: the labeling is inconsistent. Some resumes have complete annotations. Others have partial annotations. Some have none at all.
Rather than throw away the data, we built a training pipeline that could handle all three: fully labeled resumes for supervised training, partially labeled ones for semi-supervised learning, and unlabeled resumes for active learning where we extract what we can, flag uncertainties, and add them to the review queue.
This approach let us use the entire dataset, not just the perfectly labeled subset.
From spaCy to transformers
Our first attempt used spaCy standard en_core_web_sm model. It worked, but accuracy plateaued around 75%. The model just was not sophisticated enough for the nuance of resume data, skills listed in different formats, experience described in different ways, education systems varying by country.
We switched to en_core_web_trf, spaCy transformer-based model. The difference was immediate: accuracy jumped to 82%. The transformer architecture handles context better, understands that Java followed by Spring Boot means something different than Java alone, and captures relationships between entities that the smaller model missed.
Transformer models are not just bigger, they are better at understanding context. Java followed by Spring Boot means something different than Java alone. The smaller model missed those relationships. The transformer model did not.
The ensemble method
Even with the transformer model, we knew we could do better. We implemented an ensemble system that combines three extraction approaches:
ML-based extraction using the spaCy transformer model. This is our primary engine, it handles the general cases well and captures patterns it learned from the training data.
Regex patterns for high-confidence fields. Email addresses, phone numbers, URLs, these have predictable formats that regex can catch with near-100% accuracy. We do not waste the ML model on these.
Heuristic rules for field relationships. If we find a company name in an experience section, we look for dates nearby. If we find a degree, we look for the university name. These rules capture relationships that pure ML struggles with.
The ensemble approach gave us our final accuracy of 88.7%, a 6.7% improvement over the ML model alone.
Active learning for continuous improvement
One of the most valuable additions was the active learning system. Instead of just training once and being done, we built a system that continuously identifies low-confidence predictions, routes them to a review queue, captures the human corrections, and feeds those corrections back into the next training run.
This means our model gets better over time. Every time a human corrects an extraction, that correction becomes training data for the next iteration. Teams using this approach see accuracy improve by 3–5% per quarter as the model learns from real-world corrections.
Data validation and cleaning
Raw ML output is rarely production-ready. We implemented a validation layer that checks email and phone formats, ensures dates fall in valid ranges, matches skill tags against a known taxonomy, and normalizes inconsistent formatting, java, Java, and JAVA all become the same thing.
This validation layer catches errors before they reach downstream systems and ensures consistent data quality.
Batch processing optimization
Processing 9,500 resumes takes time. We implemented parallel batch processing with a key insight: for small batches (2-3 files), sequential processing is faster than parallel because the overhead of parallelization outweighs the benefit. For larger batches (4+ files), parallel processing wins.
We built a smart batching system that automatically chooses the right approach based on batch size. This gave us 30% faster overall processing times without changing the underlying extraction logic.
The analytics dashboard
You cannot improve what you cannot measure. We built an analytics dashboard that tracks total extractions over time, average confidence scores, field-level extraction rates, processing times, error rates by document type, and the split between batch and single-document jobs.
This dashboard is not just for monitoring, it is for improvement. When we see that email extraction is consistently 99% accurate but skill extraction is only 85%, we know where to focus our next model improvement effort.
What we learned
Building production-grade ML extraction is about more than just the model. It is about data quality and handling inconsistent labeling. Architecture choices, transformers genuinely outperform smaller models for this problem. The value of ensemble methods over any single approach. Continuous improvement through active learning. A validation layer that catches bad output before it reaches downstream systems. Smart batching for performance. And observability, you cannot operate what you cannot see.
The 88.7% accuracy is not just about the ML model, it is about the entire system we built around it.