red_mad_robot engineer shows how to build a resume NER service, from annotation to API
An NLP engineer at red_mad_robot has walked through a complete NER pipeline for resumes, from problem definition and BIO tagging to model training and an API service. The example uses Label Studio, synthetic data, six BERT models and FastAPI. One curious detail: ruRoBERTa-large achieved the best F1, but for production the author chose the lighter mBERT because of speed and hardware requirements.
AI-processed from Habr AI; edited by Hamidun News
A practical article on Habr shows how to tackle NER not in theory but on a real case: resumes for an HR system. The author covers the whole path, from choosing entities and preparing the dataset to training the model and launching an API that can be embedded in a working product.
From task to schema
The case rests on a fairly applied problem: recruiters need a module that accepts a resume in PDF or DOC, extracts the text and finds the first name, surname, email, phone number, skills and expected salary. An NER approach is chosen precisely for this scenario.
An important point in the article: the author starts not with the model but with clarifying business requirements. First you need to understand the domain, the language of the documents, the input format and which fields the client actually needs. Without this, even a good model will solve the wrong problem.
Once the requirements are formalized, the author fixes specific tags: NAME, SURNAME, EMAIL, PHONE, SKILL and SALARY. For labeling he picks the BIO scheme, because in resumes skills often come one after another, and the model must understand where each separate entity begins. The example "Python SQL Docker" is telling here: with a poorly chosen labeling scheme, the system can merge several skills into one. This is exactly the kind of case where a decision that looks minor at the start later affects the quality of the whole system.
Where the dataset breaks
The largest part of the article is devoted to data, and that makes sense: this is usually where most of the time goes. For manual labeling the author uses Label Studio, but he separately handles two practical problems: the service cannot parse PDF properly on its own and works poorly with plain TXT import. So before labeling he writes a small Python script that extracts text from PDFs and converts the documents into a JSON format convenient for Label Studio.
"Garbage in — garbage out".
Next comes the part that is especially useful for applied teams. The author found no ready-made Russian-language resume dataset on Hugging Face, Kaggle or other popular platforms. So he had to combine several approaches to building the corpus:
- manual labeling of real or prepared resumes in Label Studio
- translating English-language resume datasets into Russian with additional checking
- generating synthetic resumes with an LLM and fake data from Faker
- re-labeling EMAIL and PHONE with regex where the LLM made mistakes
The article shows well that an LLM does not remove the data quality problem, it only changes its form. In translation, emails, phone numbers and technology names could get mangled, and in automatic labeling the model sometimes classed an employer such as Oracle as a skill or, conversely, missed obvious tags. Another important takeaway: skills should be labeled throughout the whole text, not only in the "Skills" block, otherwise the model learns the section template rather than the entity itself. For the demonstration the author assembled 114 documents and six different resume templates, but states explicitly that production usually needs thousands of examples.
Why mBERT was chosen
The author builds the modeling stage around the BERT family. For the experiment he compares six pretrained models, including mBERT, XLM-RoBERTa, ruBERT and ruRoBERTa-large. Training ran on an RTX 3090 with 16 GB of video memory, and long documents were additionally chunked to fit the model's context window.
Evaluation used the F1 score, and ruRoBERTa-large formally came out best. But the author does not stop there and moves to a question that matters more in real projects than a metrics table: what each extra bit of quality costs. The final choice fell not on the benchmark leader but on bert-base-multilingual-cased. The reason is simple: mBERT has 178 million parameters versus 355 million for ruRoBERTa-large, while the F1 difference was about 0.01. This trade-off gives faster inference and less demanding hardware requirements, which matters especially if the service later has to run not only on a GPU but also on a CPU.
On top of the chosen model the author builds a FastAPI service with a /predict endpoint that accepts resume text and returns the entities it finds. In other words, the article takes the case not to an experiment notebook but to a minimum viable API.
What this means
The red_mad_robot walkthrough is valuable because it presents NER as an engineering task, not an academic exercise. The main conclusion is simple: a working result comes not from picking a trendy model but from a combination of correct problem framing, a strict labeling scheme, manual data checks and a sober trade-off between quality and inference cost.
- Nov 2, 2026Microsoft releases 4B model Mage-VL-Cowork, which solves 66.0% of OSWorld-Verified tasks
- Nov 1, 2026Local models lose to Opus and Codex: 0.21 on a MacBook versus 1.00 for Codex
- Nov 1, 2026Pika Labs releases open video model H3 Flex: 6 steps instead of 50
- Nov 1, 2026Hugging Face's BERT Tokenizer Gets a 50x Speedup by Skipping Needless Work on ASCII
Key Questions Answered
What are the key details on From task to schema?
The case rests on a fairly applied problem: recruiters need a module that accepts a resume in PDF or DOC, extracts the text and finds the first name, surname, email, phone number, skills and expected salary. An NER approach is chosen precisely for this scenario. An important point in the article: the author starts not with the model but with clarifying business requirements. First you need to understand the domain, the language of the documents, the input format and which fields the client actually needs. Without this, even a good model will solve the wrong problem. Once th
Where the dataset breaks?
The largest part of the article is devoted to data, and that makes sense: this is usually where most of the time goes. For manual labeling the author uses Label Studio, but he separately handles two practical problems: the service cannot parse PDF properly on its own and works poorly with plain TXT import. So before labeling he writes a small Python script that extracts text from PDFs and converts the documents into a JSON format convenient for Label Studio. "Garbage in — garbage out". Next comes the part that is especially useful for applied teams. The author found no read
Why mBERT was chosen?
The author builds the modeling stage around the BERT family. For the experiment he compares six pretrained models, including mBERT, XLM-RoBERTa, ruBERT and ruRoBERTa-large. Training ran on an RTX 3090 with 16 GB of video memory, and long documents were additionally chunked to fit the model's context window. Evaluation used the F1 score, and ruRoBERTa-large formally came out best. But the author does not stop there and moves to a question that matters more in real projects than a metrics table: what each extra bit of quality costs. The final choice fell not on the benchmark
Ship AI Faster with Founders, Engineers & Weekly Architecture Reviews
Inside Vibe Club (hamidun.com/club) — weekly live masterminds with Zhemal Khamidun, Tech Radar, full LMS access, and 370+ production Claude Code skills.
The AI world, distilled — once a week
Seven stories that actually mattered, hand-picked. No noise, no reposts, no press releases.
Done! Check your inbox for a confirmation.