Benelux AI Job Scout

Rôle

Solo de bout en bout ⁠— stratégie produit, UX, front-end, back-end, pipeline NLP, infrastructure ; développé avec Claude Code

Client

SVP Consulting ⁠— cabinet de conseil en IA & data science à Anvers

Disciplines

Product Design · UX · AI / LLM · Data · Front-end

Année

2025–2026

Un outil de veille interne qui a remplacé deux heures de recherche manuelle d’emplois au 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

Problème
Chercher des postes ML/Data/AI au 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 7 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, chacune avec un label de langue (28/30 corrects à la vérification manuelle) ; 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 chronométré huit semaines de recherches manuelles sur le marché de l’emploi Benelux (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 de petits outils. 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 tourne depuis quatre semaines sans aucun faux label Bloquant ⁠— les deux faux positifs relevés à la vérification étaient Peut-être/Risque. 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 sept 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 clair et sombre sont tous deux disponibles : l’application suit le réglage du système, et le bouton de la barre de navigation enregistre le choix 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 clair

Thème sombre ⁠— suit le réglage du système

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 au Benelux à distance (15). 100 % classifiées avec correspondance linguistique. Coût d’infrastructure marginal : €0/mois ⁠— l’outil tourne sur un VPS Hetzner partagé déjà en service, 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. Presque aucune ne permet de filtrer dessus ⁠— et celles qui le font ne couvrent que leur propre marché

Des règles d’abord, et les quatre semaines où ce n’était qu’un site d’annonces

Faire classer chaque annonce par un LLM est la réponse par défaut en 2026. J’ai préféré mesurer avant de construire. Un échantillon de 50 annonces a montré que le vocabulaire des exigences linguistiques était assez stable pour des règles, un modèle n’étant nécessaire que pour les 3 % de cas ambigus où des formulations comme « la langue de travail est le français » mettent en échec une regex. Tout envoyer à un modèle aurait acheté du non-déterminisme et une facture récurrente pour un problème que les règles réglaient déjà.

Choisir les sources revenait surtout à en refuser. Le VDAB conditionne l’accès API à un accord de partenariat signé, et LinkedIn comme Indeed sont de fait interdits à un petit outil au regard de leurs conditions. Contourner cela par du scraping était possible et je ne l’ai pas fait. Adzuna est la seule source gratuite couvrant à la fois la Belgique et les Pays-Bas avec des signaux de salaire, donc une couverture plus étroite est devenue le prix d’un outil réellement publiable.

L’erreur de séquencement vaut plus que l’architecture. Pendant les quatre premières semaines en production, 282 offres n’étaient classées que par date de publication, ce qui ne diffère pas réellement des sites d’annonces que cet outil devait remplacer. Le score d’adéquation était tout le différenciateur et il est arrivé tard. Il aurait dû être là dès le premier jour. Le classifieur a aussi été validé sur un échantillon manuel de 30 annonces, alors que la bonne validation aurait été de journaliser les résultats de candidature dès le départ et de calculer un vrai rappel et une vraie précision.

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

Une autre note rétrospective, au-delà de l’erreur de séquençage ci-dessus : le 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
SVP Consulting — marque, positionnement & le site de l’entreprise