Benelux AI Job Scout

Un outil de veille interne qui a remplacé deux heures de recherche manuelle d’emplois en Benelux par une revue filtrée de 20 minutes — en automatisant la collecte depuis 14 sources gratuites et en classifiant chaque offre selon le seul signal que les plateformes d’emploi ne montrent jamais : les exigences linguistiques

Rôle
Solo de bout en bout — stratégie produit, UX, front-end, back-end, pipeline NLP, infrastructure
Disciplines
Product DesignUXAI / LLMDataFront-end
Liens
En bref
  • Problème — Chercher des postes ML/Data/AI en Benelux prenait ~2 h/semaine ; ~38 % des offres pertinentes cachent des exigences linguistiques dures, invisibles dans les aperçus
  • Insight — Le vocabulaire des exigences linguistiques est cohérent et apprenable, de sorte que des classifieurs à base de règles couvrent 5 des 7 dimensions ; un LLM n’est nécessaire que pour ~3 % des cas
  • Solution — J’ai construit le pipeline seule de bout en bout : collecte depuis 14 sources gratuites, classification de chaque offre sur 6 dimensions + correspondance CV, dans un tableau de bord React axé sur le filtrage
  • Résultat — Disponible sur ai-job-hunter.ontwrpn.com ; 282 offres indexées, 100 % classifiées sur la langue ; recherche hebdomadaire de ~2 h à ~20 min (−83 %), €0/mois

Le blocage était invisible — enfoui au troisième paragraphe

Rechercher des postes ML/Data/AI en Belgique, aux Pays-Bas et au Luxembourg prenait environ deux heures chaque lundi. Le problème de fond : ~38 % des offres qui semblaient pertinentes exigeaient la maîtrise du néerlandais, du français ou de l’allemand — un blocage rédhibitoire qui n’apparaissait jamais dans le titre ni dans l’aperçu. Il surgissait au troisième paragraphe, signalé par un mot comme vereist, requis ou Voraussetzung. Un candidat sans cette langue passait dix minutes à lire une offre pour laquelle il n’avait jamais été éligible.

Trois défaillances cumulées : la découverte était fragmentée entre cinq plateformes sans recoupement ; les exigences linguistiques étaient systématiquement cachées ; et sans signal de pertinence, chaque offre semblait mériter la même attention. Résultat : deux heures de navigation non ciblée avec un tableur obsolète.

Le problème n’était pas un manque d’offres d’emploi. C’était le coût de lire le bon signal dans le bruit

Huit semaines d’auto-audit avant la première ligne de code

La phase de découverte s’est déroulée en novembre 2025. J’ai audité mes propres sessions de recherche d’emploi pendant huit semaines (moyenne : ~2 heures, dont ~40 minutes sur des offres bloquées par la langue), sondé 12 sources Benelux actives pour la disponibilité des API et les contraintes des CGU, et échantillonné manuellement 50 offres ML/Data d’Adzuna BE et NL pour caractériser le vocabulaire des exigences linguistiques.

Principales conclusions : Adzuna est la seule source gratuite couvrant la Belgique et les Pays-Bas avec des signaux salariaux ; VDAB conditionne l’accès à son API à un accord de partenariat signé ; LinkedIn et Indeed sont pratiquement hors d’atteinte pour des outils personnels. Le Luxembourg présente une lacune de couverture structurelle — aucun point d’accès .lu n’existe et l’ADEM ne publie aucune API d’offres d’emploi en temps réel. Le vocabulaire des blocages linguistiques s’est avéré cohérent et apprenable : vloeiend, vereist, courant, maîtrise, muttersprachlich, C1, B2 pour les exigences ; een plus, un atout, von Vorteil, nice to have pour les préférences.

~38 % des offres échantillonnées manuellement contenaient une exigence linguistique dure invisible dans l’aperçu. Le vocabulaire était suffisamment stable pour une classification à base de règles — avec un LLM nécessaire uniquement pour les ~3 % de cas ambigus où des formulations comme « working language is French » résistaient aux regex.

Règles d’abord ; LLM uniquement pour les 3 % ambigus

Le pipeline de classification couvre sept dimensions. Cinq se sont avérées fiablement traitables par règles : langue de l’offre (modèle trigramme franc-min), type de contrat (regex multilingue), famille de rôle (correspondance de motifs de titre avec repli fuzzy), niveau de séniorité (regex de titre) et extraction de compétences (gazetteer de 50 termes avec alias). Le type de travail à distance utilise un classifieur par mots-clés. Seules les exigences linguistiques sont transmises à un LLM — lorsque le modificateur autour d’une mention de langue est ambigu.

Le label de correspondance linguistique comporte quatre valeurs : Bon (anglais suffisant), Peut-être (langue locale préférée), Risque (probablement requise, formulation ambiguë), Bloquant (explicitement requise). Lors de la première exécution en production sur 282 offres, le LLM a été appelé 8 fois — 8 des 1 500 requêtes quotidiennes gratuites de Gemini. Coût NLP : €0/mois. La logique à base de règles a fonctionné quatre semaines sans faux positif sur la catégorie fortement requise. Un modèle affiné serait marginalement plus précis sur les cas limites ; pour un domaine au vocabulaire stable comme les signaux RH, la logique déterministe est la bonne valeur par défaut.

Les blocages linguistiques apparaissent avant l’ouverture d’une fiche — le classifieur signale les exigences dures que les plateformes enfouissent au troisième paragraphe

Tableau de bord axé sur le filtrage, construit autour du signal de correspondance linguistique

14 sources gratuites (Adzuna, EURES, Arbeitnow, Remotive, RemoteOK, Jobicy, The Muse, Greenhouse, Lever, Recruitee, SmartRecruiters, Ashby, Workable, HN Who’s-Hiring) alimentent un pipeline quotidien de collecte→classification→embedding s’exécutant en interne via node-cron. Chaque offre est classifiée sur six dimensions et scorée par rapport à un CV téléversé grâce à une correspondance par chevauchement de termes. Le tableau de bord React expose les filtres en paramètres d’URL — toute vue filtrée est partageable et survit à un rechargement de page.

Une légende des langues permanente figure sous la barre de filtres dans chaque vue. Le détail d’une offre affiche les badges de classification et un bouton Postuler au-dessus de la ligne de flottaison — avant la description. Les thèmes sombre (par défaut) et clair sont tous deux disponibles ; la préférence est enregistrée dans localStorage via un unique attribut data-theme sur l’élément racine. Une visite guidée d’onboarding en cinq étapes accompagne les nouveaux utilisateurs dans la logique des badges linguistiques.

ai-job-hunter.ontwrpn.com — aperçu en ligne
Démo en ligne
ai-job-hunter.ontwrpn.com
Ouvrir

En ligne — 14 sources, 282+ offres indexées, filtrage par correspondance linguistique, famille de rôle, séniorité, type de travail à distance

Thème sombre (par défaut)

Thème clair

Détail de l’offre — Postuler au-dessus de la ligne de flottaison

Légende des langues — permanente dans chaque vue

Recherche hebdomadaire : 2 heures → 20 minutes. Coût d’infrastructure : €0

En production depuis mai 2026. Quatre semaines de données early-production (estimées à partir de sessions suivies, sans étude rigoureuse) : session de recherche hebdomadaire −83 % (2 h → 20 min) ; temps passé sur les offres bloquées par la langue −95 % (40 min → 2 min) ; temps pour identifier les candidatures à envoyer immédiatement −92 % (60 min → 5 min). 282 offres indexées en Belgique (122), aux Pays-Bas (145) et en Benelux à distance (15). 100 % classifiées avec correspondance linguistique. Coût d’infrastructure : €0/mois — VPS Hetzner partagé avec Coolify et Postgres auto-hébergés, LLM sur les niveaux gratuits de Gemini/Groq.

Révision manuelle de la précision sur 30 classifications échantillonnées aléatoirement : correspondance linguistique 28/30 correctes (deux faux positifs issus du néerlandais dans des sections juridiques boilerplate, correction connue en attente) ; type de contrat 26/30 ; famille de rôle 29/30. Encourageant à titre indicatif — sans étude rigoureuse. L’économie dominante réside dans le filtrage par exigences linguistiques : le classifieur signale le blocage avant l’ouverture de la fiche, éliminant les lectures de dix minutes qui n’auraient jamais abouti à une candidature viable.

Le signal le plus précieux est souvent celui que personne ne met en avant. Toutes les plateformes d’emploi connaissent les exigences linguistiques. Aucune ne les propose comme filtre

Ce que j’aurais fait différemment — et ce que la contrainte €0 m’a appris

Trois notes rétrospectives honnêtes. Premièrement : j’ai construit le tableau de bord avant le score de pertinence. Pendant les quatre premières semaines en production, 282 offres étaient classées uniquement par date de publication — pas vraiment différent d’une plateforme d’emploi. Un score de pertinence dès le premier jour aurait rendu le produit utile immédiatement. Deuxièmement : le classifieur de blocages linguistiques a été validé sur un échantillon manuel de 30 offres ; la bonne validation aurait été de journaliser les résultats des candidatures dès le départ pour calculer le rappel et la précision réels. Troisièmement : VDAB — la source la plus riche pour les offres belges — a été reporté en raison de son accord de partenariat requis. Il aurait dû être la première intégration tentée.

La contrainte €0/mois a imposé une meilleure architecture. Le NLP à base de règles ne nécessite aucune API et se débogue de façon prévisible lors d’un échec. Le planificateur node-cron en interne n’a besoin d’aucun service cron payant et tourne sur la même machine que les données. La discipline de construire sous un plafond de coût strict a produit un code plus portable et moins couplé qu’un budget ouvert ne l’aurait fait.

Projet suivant
Set d’icônes 3D — plateforme e‑commerce pour enfants