Every "skills parser" API I tried had the same two problems.
Problem 1: they return word salad. I fed one a single real resume line and got back a flat list of raw tokens — ["led",
"team", "backend", "kubernetes", "our"] — junk like "our" included, no structure at all. No confidence, no hard-vs-soft
distinction, no canonical names. You still have to clean up the mess yourself.
Problem 2: they only speak English. I gave one a sentence in another language and got back an empty array. For anything with
a global user base, that's a dealbreaker.
Here's the thing: most of what matters in a resume or job post is implicit. "Led a team of four" is Leadership. "Mentored two
juniors" is Mentoring. A keyword matcher will never catch those, because the words "leadership" and "mentoring" aren't
anywhere in the text. You need something that actually understands the sentence.
So I built one.
What it does
One endpoint. Text in, normalized skills out — in any language.
Input:
Migrated our backend to Kubernetes and led a team of 4 engineers.
Output:
{
"skills": [
{ "name": "Kubernetes", "esco_label": "kubernetes", "type": "hard", "confidence": 0.95 },
{ "name": "Backend Development", "esco_label": "backend development", "type": "hard", "confidence": 0.90 },
{ "name": "Leadership", "esco_label": "leadership", "type": "soft", "confidence": 0.90 }
]
}
Notice what happened:
- "led a team" → Leadership — a soft skill that never appears literally in the text.
- "our backend" did NOT become a skill — "our" is noise, so it gets dropped.
- Every skill is canonicalized (k8s, kubernetes, Kubernetes all collapse to one), tagged hard/soft, and given a confidence score.
Now the exact same thing in Spanish:
Input:
Migré el backend a Kubernetes y lideré un equipo de 4 ingenieros
Output: the same canonical English skills — Kubernetes, Backend Development, Leadership. It normalizes across languages into
one vocabulary, so your downstream code only ever deals with English skill names no matter what language the input was in.
I've tested English and Spanish so far, with more on the way. That multilingual + implicit-soft-skill combination is the
whole point — it's the exact gap the keyword parsers leave wide open.
How it's built
- Claude Haiku 4.5 does the extraction, with structured outputs (a JSON schema the model is forced to conform to) so the response is always valid JSON. No "sometimes it returns prose and your parser explodes" failures.
- A small normalization layer canonicalizes synonyms and de-dupes, keeping the higher-confidence instance when a skill shows up twice.
- The whole thing is a single serverless function. Boring on purpose.
The interesting engineering wasn't the plumbing — it was guarding quality. The entire value here is extraction quality, so I
wrote a labeled eval set (must_include / must_exclude cases across languages) that runs before every deploy. If a prompt
tweak makes it start hallucinating "our" as a skill again, the eval catches it before it ships.
What I learned
- Building the API was the easy part — a weekend. Distribution is the actual business, and it's the part I'm figuring out right now. This post is me learning that in public.
- Structured outputs turned "the LLM returns JSON… usually" into "the LLM returns valid JSON, always." If you're wrapping a model in an API, use them.
Try it / tell me where it breaks
It's live with a free trial: https://zylalabs.com/api-marketplace/other/skills+extraction+api/13176
I'd genuinely love for you to throw weird input at it — mixed-language sentences, sarcasm, job posts full of buzzwords — and
tell me where it falls apart. What language should I test next?
Top comments (0)