Sai Aryan Goswami

UNMAPPED, Skill mapping for the informal economy, across three engines


Skill mapping for the informal economy, across three engines

Someone describes their work in their own words, with no certificate to point to. The system reads that and returns the occupations it matches, the nearby skills worth one wage jump, and how automation-proof each one is.

Year
2025
Domain
research
Stack
FastAPI, pgvector, fastembed/ONNX, NetworkX, Neon

Before

What a worker types about themselves

no certificate

their own words

real skills held by informal-economy workers

i do wiring work in shops and homes, almost 6 years now
also fix ceiling fans and inverter batteries when people ask
sometimes the shop owner asks me to check the meter also
learned it from my uncle, he did the same work before me
never went for any course, no ITI
i can read the wiring diagram if someone shows me once
worked 2 years in a small shop in sector 63, then on my own
people call me when something trips, mostly by phone
i know which wire is which, that is not the problem
the problem is nobody has this written down anywhere
no certificate

After

three engines

+41%

wage, two hops away

a ranked, traversable graph

Matched occupation
Electrical installer
ESCO code
7411
Solar PV installer
+34% wage, 1 hop
Battery systems tech
+41% wage, 2 hops
Automation resilience
0.71
Reached the LLM
No

The problem

In most low and middle income countries the majority of young workers are in the informal economy. They have real skills, often substantial ones, and almost none of it is legible to any formal system. There is no transcript for running a repair shop, no certificate for three years of site work, no structured record a hiring platform or a training program can read.

That illegibility is the actual barrier. Programs designed to move people into better work have to start by guessing what those people can already do, and they usually guess badly.

UNMAPPED was built for the World Bank track of Hack-Nation's 5th Global AI Hackathon, with Amit Kumar Gupta. Around 300 teams competed in the track. We had 18 hours.

Constraints

The hackathon constraints turned out to be the same constraints the real problem has, which is unusual and useful.

No labelled data. There is no dataset of informal-economy skill profiles to fine-tune on. Whatever we built had to work from unstructured descriptions of what someone actually does day to day.

Cost per profile has to approach zero. A system meant for national-scale deployment in an LMIC cannot spend a dollar per person. That ruled out routing everything through a large hosted model.

18 hours. This is not a footnote. It eliminated every architecture that required provisioning infrastructure before writing any logic, and that elimination turned out to produce a better system rather than a worse one.

Architecture: three engines

The core decision was to stop treating this as one model call and split it into three engines with different cost profiles, so the expensive one runs least.

Semantic matching

fastembed with ONNX runtime generates embeddings locally, and pgvector on Neon stores and searches them. Running embeddings on CPU through ONNX rather than calling a hosted embedding API is what makes the per-profile cost approach zero. It also removes a rate-limited network dependency from the hot path.

Neon mattered for a boring reason that turned out to be the right one. pgvector inside ordinary Postgres means the vectors live next to the relational data, so a similarity search and a metadata filter are one query rather than two systems kept in sync.

The graph engine

This is the part that makes UNMAPPED something other than a search box.

The graph is built in NetworkX, held in memory, and pre-seeded at startup from ESCO, the European Skills, Competences and Occupations taxonomy. Roughly 500 skill nodes and 2,000 weighted edges.

The edges carry four different relationships:

  • skill to adjacent skill
  • skill to occupation
  • occupation to wage
  • occupation to automation risk, using Frey-Osborne scores

A traversal takes a person's current skills and walks one to two hops out. What comes back is a ranked list of adjacent skills, ranked by wage premium and automation resilience.

That ranking is the whole idea. Skill mapping is not a nearest-neighbour problem. The useful question is not "what is this person's skill", which they already know, but "what is worth learning next from where they are standing". Answering it means combining proximity, which the graph gives you, with economic value and durability, which the edge weights carry. A recommendation that is one hop away but heading into work that automates in five years is a bad recommendation, and only a graph that knows about automation risk can decline to make it.

Why NetworkX and not Neo4j

A graph database is the obvious tool and would have been the wrong one here.

Neo4j means provisioning, a connection, a schema, and a query language, all before the first traversal runs. NetworkX is pure Python, loads in seconds, and at 500 nodes and 2,000 edges traversal is effectively instant. There is no scale at which this graph benefits from a database, because the graph fits comfortably in memory and always will at this granularity.

In an 18-hour build the setup overhead alone decided it. But the decision holds outside the hackathon frame too: adding a database to hold two thousand edges is infrastructure you maintain forever in exchange for nothing.

Language understanding

NVIDIA Nemotron, accessed through OpenRouter, handles the part that genuinely needs a language model: turning a messy free-text description of someone's work into structured input the other two engines can act on.

Putting the LLM last, behind the cheap engines, is the cost argument. Most of the work never reaches it.

Decisions and trade-offs

Local embeddings over a hosted embedding API. Slower on cold paths, but the cost curve is flat rather than linear in users, and there is one fewer service that can rate-limit you mid-demo. For a system whose premise is national scale under cost constraints, the flat curve is the only defensible choice.

Postgres with pgvector over a dedicated vector database. A dedicated store would be marginally faster at retrieval and would have meant two systems, two consistency stories, and two things to provision. One Postgres was right at this size and stays right well past it.

A REST API rather than a demo UI. A judged hackathon rewards a visible interface, so this was a real trade. We built the API because skill mapping is infrastructure: what matters is whether a ministry or an NGO platform can call it, not whether we shipped a nice screen.

The decision I would reverse

Deploying too late.

We started deployment early by hackathon standards and it was still too late. The backend bundled the sentence embedding model directly into the service, which made it large, and that size caused repeated failures on free-tier hosting through the build-up. Every one of those failures came out of the 18 hours.

The fix is not subtle in hindsight: deploy a skeleton in the first hour, before there is anything worth deploying, so the hosting constraints are known while there is still time to design around them. The embedding model being in-process is exactly the kind of decision that looks free locally and is not free on a free tier.

Outcome

2nd place globally in the World Bank track, out of roughly 300 competing teams.

The judges pushed hardest on two things, and both were fair. The first was latency. The second was the gap between a working demo and real-world deployment, specifically how much on-the-ground implementation work would sit between this and anything running in an actual program. That is the right question to ask of a hackathon project aimed at development policy, and having a good architecture is not an answer to it.

What holds up months later is the shape rather than the code: three engines with different cost profiles, cheap ones first, the expensive one last and rarely. That structure is the reason it could plausibly run at the scale the problem actually has.