Accueil / Articles

Conception d’un chercheur d’emplois multi-agents : pipeline, HyDE et observabilité.

Un pipeline LangGraph en neuf étapes qui associe les CV aux offres d’emploi, avec huit choix de conception concernant la récupération via HyDE, le routage des modèles, les limites de fréquence et l’observabilité.

Éditeur : REACTAPP.TOP12 min de lecture2781 mots

Sources: Agentic AI in Practice: A Case Study in Multi-Agent System Design

Agents, IA agente, systèmes multi-agents : ce vocabulaire est partout, et chaque semaine voit apparaître un nouveau modèle, un nouveau framework ou un nouveau schéma d’orchestration. Prompting, RAG, appel à des outils, MCP, couches de mémoire. L’écosystème évolue plus rapidement que la plupart des professionnels ne peuvent le suivre. Au-delà de tout ce bruit, les questions fondamentales restent inchangées :

  • Où un problème doit-il être divisé en étapes de raisonnement ?
  • Quels appels relèvent d’un LLM, et lesquels ne doivent jamais être confiés à un seul ?
  • Comment peut-on s’assurer que le système fait bien ce pour quoi on le considère ?

La sortie d’une nouvelle version du framework ne rend pas les choses plus simples. Pour rester concret, cette étude de cas aborde un problème que des millions de personnes rencontrent : trouver les bons emplois parmi une quantité écrasante d’offres. Elle conçoit un système d’IA du début à la fin pour y remédier et utilise cette conception pour répondre à trois questions pratiques. Que signifie « agentic » en termes architecturaux ? Quand plusieurs agents ajoutent-ils de la valeur, et quand deviennent-ils un fardeau ? Et qu’est-ce qui rend un système d’IA observable, fiable et prêt pour la production ?

Rechercher un emploi, ce n’est pas vraiment chercher

La plupart des gens considèrent la recherche d’emploi comme une tâche de recherche. En réalité, c’est plus proche d’une tâche de correspondance. Personne ne cherche vraiment des annonces contenant des mots-clés spécifiques. La question sous-jacente est plus difficile : compte tenu de cette expérience, de ces compétences et de cette orientation professionnelle, quels postes correspondent réellement ?

Les plateformes d’offres d’emploi traitent cela comme une recherche : vous saisissez quelques mots-clés, indiquez une localisation et espérez trouver quelque chose de pertinent. Or, un CV reflète des années d’expérience, des connaissances spécialisées, une profondeur technique, des compétences transférables, une évolution professionnelle et un contexte précis, tandis qu’une case de recherche force à résumer tout cela en quelques mots, en supposant que des mots correspondants signifient une intention identique.

Tout le monde sait comment ça se passe :

  • Faire défiler des centaines d’offres sur plusieurs plateformes
  • Évaluer la pertinence une offre à la fois
  • Se heurter à des doublons, des annonces expirées et des liens cassés
  • S’interroger sur le fait de savoir si les postes visés étaient bien ceux qu’il fallait chercher

Le manque d’intérêt n’est pas le problème principal. La véritable lacune réside entre ce que l’historique d’un candidat indique et ce que l’offre recherche réellement, et combler cette lacune nécessite de l’interprétation, du contexte et du jugement. En bref, cela requiert de la réflexion, domaine où les grands modèles de langage excellent. Imaginez qu’un système puisse lire un CV, déduire des parcours professionnels pertinents, trouver des offres d’emploi et les classer en fonction de leur adéquation réelle plutôt que de la correspondance des mots-clés. C’est le problème pour lequel ce système a été conçu.

Le processus, étape par étape

Tout commence par une action : télécharger un CV. Après cela, personne ne touche à la barre de recherche, ne feuillette pas les listes ni ne décide quelles offres valent la peine d’être postulées. Le système prend le relais et exécute neuf étapes, chacune ayant une tâche bien définie.

  1. Agent analyseur de CV. Agissant comme un recruteur expérimenté, il transforme le CV en un profil structuré plutôt qu’en une liste de mots-clés. Ce profil mentionne les postes occupés, les compétences, les domaines d’expertise, l’évolution de la carrière ainsi qu’un bref résumé au style ATS, que tous les autres agents considèrent comme la description canonique du candidat. Modèle : Claude Sonnet.
  2. Agent recommandateur de profils. Il propose deux ou trois intitulés de postes adaptés au niveau, au domaine et aux compétences du candidat, accompagnés de variantes de requêtes de recherche pour chacun. Modèle : Claude Haiku.
  3. Étape de confirmation par un humain. C’est le seul moment où une personne prend une décision. L’utilisateur examine les profils suggérés, choisit celui qui lui semble approprié, ajoute éventuellement des préférences de localisation et d’ancienneté, puis confirme. Le processus attend alors cette confirmation. Aucun modèle n’intervient, seul le jugement humain compte.
  • Recherche d’emploi. Avec le profil confirmé, des requêtes simultanées sont envoyées à cinq sources d’offres en ligne à la fois, ce qui donne environ 100 à 150 listings bruts. Aucune source ne contient tout, et l’exécution parallèle permet de réduire le temps de réponse tout en élargissant la couverture. Aucun LLM, seulement des appels API.
  • Vérificateur d’URL. Une vérification HTTP rapide teste l’URL de chaque listing. Les liens morts, les pages 404 et les redirections des agrégateurs sont plus fréquents que prévu, et tout ce qui ne se résout pas correctement est éliminé. Aucun LLM.
  • Déduplication. Différentes sources renvoient souvent la même offre d’emploi, donc les doublons (même entreprise, même poste et même localisation) sont supprimés avant toute étape coûteuse. Entrée propre, sortie propre. Aucun LLM, seulement de la logique en mémoire.
  • Prefiltre sémantique. Il est utile de comprendre en détail cette étape. Elle utilise des embeddings de documents hypothétiques (HyDE). Au lieu de comparer directement le CV avec les offres d’emploi, le système génère d’abord des descriptions de postes hypothétiques à partir du CV, puis cherche les offres réelles dont le sens est le plus proche de celles générées artificiellement. Les offres ne dépassant pas un seuil de similarité minimal sont éliminées avant toute évaluation coûteuse par un modèle LLM. Les raisons pour lesquelles cette méthode fonctionne et pourquoi une comparaison directe ne le fait pas sont expliquées dans la cinquième option de conception ci-dessous. Modèles : Claude Sonnet pour la génération des descriptions, Voyage AI voyage-3 pour les embeddings.
  • Agent de classement. Le LLM compare chaque description d’emploi au profil complet et analysé du candidat, puis évalue quatre dimensions : adéquation de l’expérience, chevauchement des compétences, alignement avec le domaine et exigences en matière d’éducation. Ces éléments sont fusionnés en un seul score d’adéquation, et chaque score s’accompagne d’une justification ainsi que d’une analyse des écarts entre le profil et les exigences, de sorte que le résultat est une explication plutôt qu’un simple classement. Modèle : Claude Haiku.
  • Finalisation et enregistrement des données d’observabilité. Les résultats classés sont affichés dans l’interface utilisateur, et chaque métrique de l’exécution, y compris le nombre de tokens, la latence et le coût, est enregistrée dans un tableau de bord MLflow pour une inspection ultérieure. Aucun LLM utilisé.
  • Cela représente neuf étapes, quatre appels au LLM, une décision humaine et un temps d’exécution total inférieur à trois minutes.

    Le schéma technologique

    Le diagramme ci-dessus place chaque composant majeur d’une pile d’IA actuelle au sein de ce pipeline. Chaque système est un ensemble de choix, c’est pourquoi les sections suivantes décrivent ce qui a été pris en compte, ce qui a été rejeté et quel en a été le coût.

    Huit décisions de conception

    1. LangGraph plutôt que CrewAI, AutoGen ou un cycle ReAct

    Les candidats habituels étaient LangGraph, CrewAI et AutoGen ; au sein de LangGraph, on distingue en outre un graphe dirigé d’un cycle ReAct.

    CrewAI met l’accent sur la collaboration autonome, avec des agents jouant des rôles qui négocient et délèguent entre eux. AutoGen se concentre sur le dialogue multiagent conversationnel. Les deux conviennent à des workflows ouverts. Cependant, ils entraînent également des coûts de coordination et un caractère non déterministe que un pipeline fixe ne peut pas se permettre de déboguer.

    Les boucles ReAct se révèlent utiles lorsque le nombre d’étapes n’est pas connu à l’avance, comme dans le cas d’un LLM qui navigue sur Internet et ne peut pas prédire le nombre de recherches nécessaires. La recherche d’emploi n’est pas ainsi : la structure du problème définit clairement les étapes — analyser avant de recommander, rechercher avant de filtrer, éliminer les doublons avant d’incorporer les données. Rien n’est découvert à l’exécution.

    Un graphe dirigé convient parfaitement à cela. Chaque transition est explicite, l’intervention humaine fait partie intégrante du processus, et l’état est représenté par un modèle Pydantic partagé que chaque nœud lit et écrit. Lorsqu’un problème survient, le nœud défaillant est immédiatement identifiable.

    2. Agents spécialisés plutôt qu’un seul mega-prompt

    Il est tentant d’écrire une seule instruction globale capable d’analyser le CV, de suggérer des titres et des classements, car cela est plus rapide à mettre en place. Cependant, cette approche échoue de manière complexe et cumulative : une défaillance en un point entraîne des échecs partout. Il devient impossible de déterminer quelle instruction a causé un résultat déficient, ajuster une partie du système comporte le risque de régressions ailleurs, et le contexte se remplit d’instructions sans rapport avec la tâche à accomplir.

    Les agents indépendants permettent d’éviter cela. Une faible note attribuée à un classeur peut être déboguée en examinant uniquement l’instruction associée à ce classeur. Chaque agent dispose de son propre script de test, ce qui permet de tester le moteur d’analyse indépendamment du reste du processus. De plus, comme le montre la choix de conception 6, différents agents peuvent être associés à des modèles distincts.

    3. Un contrôle humain intégré

    La plupart des tutoriels sur les agents considèrent l’évaluation par un humain comme une étape optionnelle visant à améliorer le résultat, afin que les utilisateurs se sentent impliqués. Ici, ce contrôle humain constitue plutôt une décision architecturale fondamentale.

    Le système de recommandation propose deux ou trois titres, et le profil que l’utilisateur confirme guide toutes les étapes suivantes : les recherches, les filtres, l’évaluation des scores. Laisser le système choisir automatiquement peut entraîner des erreurs qui gâchent tout, produisant une liste bien classée pour un profil que le candidat ne souhaitait pas du tout. Aucune autre décision dans ce processus n’implique autant de risques, et aucune ne peut être mieux gérée par une personne, car les candidats connaissent des détails sur leurs propres préférences que un analyseur ne peut pas extraire.

    4. Un préfiltre avant le classeur

    Les données du monde réel ne sont jamais propres, et les listings provenant de cinq API présentent des problèmes prévisibles :

    • Liens morts et erreurs 404, dus à des annonces expirées qui n’ont jamais été supprimées
    • Dupliqués, car le même poste apparaît simultanément à partir de plusieurs API
    • Réorientations des agrégateurs, où une URL mène à la page d’accueil d’un site d’offres d’emploi plutôt qu’à l’annonce elle-même

    Ce ne sont pas des cas limites. C’est l’état normal des données provenant d’API externes. Les étapes de validation et de suppression des doublons existent pour nettoyer l’ensemble des données avant qu’un traitement coûteux ne soit effectué, de sorte que ce qui parvient au préfiltre sémantique est valide, unique et réel.

    Alors, le coût devient important. Au cours des exécutions en production, l’outil de classement représente de 70 à 80 pour cent des dépenses totales liées aux LLM. Le analyseur coûte un montant fixe de 2,7 à 3,0 ₹, quel que soit le nombre de tâches traitées, tandis que l’outil de recommandation coûte environ 0,30 ₹, également de manière fixe. Le coût de l’outil de classement varie de 3 à 11 ₹ en fonction du nombre de tâches qui lui sont soumises, ce qui fait que le coût total par exécution se situe entre 6 et 14 ₹. Le préfiltre ne conserve que les éléments les plus en adéquation avec le candidat, permettant ainsi à l’outil de classement de traiter un sous-ensemble à forte qualité plutôt que les données brutes et bruitées provenant de cinq API différentes.

    5. HyDE plutôt que comparaison directe

    La méthode évidente consiste à intégrer le résumé du candidat destiné aux systèmes ATS et à le comparer avec chaque description d’emploi en utilisant la similarité cosinus. C’est simple, rapide et ne nécessite pas d’appels supplémentaires à un LLM. Cependant, les résultats obtenus lors des tests ont été décevants.

    La cause en est un déséquilibre dans l’espace d’incorporation. Le résumé d’un candidat est présenté sous forme de narration à la première personne, comme par exemple « J’ai mis en place des pipelines d’IA, géré le déploiement des modèles et collaboré avec différentes équipes ». Une description d’emploi, quant à elle, est formulée sous forme de liste de exigences à la troisième personne, telle que « 3 ans d’expérience en IA minimum, compétences en PyTorch et bonnes capacités de communication ». Même lorsque les deux textes décrivent les mêmes compétences, leurs styles différents les placent dans des régions différentes de l’espace d’incorporation, ce qui fait que la comparaison directe sous-estime les vraies correspondances.

    HyDE contourne ce problème en posant une question différente : à quoi ressemblerait la description d’emploi idéale pour ce candidat ? Un LLM rédige alors deux descriptions hypothétiques à partir du CV du candidat.

    • JD1 est ancré dans un domaine spécifique, rédigé comme si une entreprise du même secteur que celui du candidat recrutait quelqu’un ayant cette expérience.
    • JD2 met l’accent sur les compétences transférables, rédigé comme si l’expertise sectorielle était secondaire et que les capacités générales constituaient l’élément principal.

    Ces descriptions synthétiques se trouvent dans la même catégorie que les descriptions réelles, car il s’agit de fiches de poste hypothétiques. Leur comparaison avec les annonces réelles permet une correspondance sémantique équivalente. Chaque annonce réelle est alors classée selon la description synthétique à laquelle elle correspond le mieux. Si elle ressemble davantage à JD1, elle est placée dans la section 1, dédiée aux postes du domaine du candidat. Si elle ressemble davantage à JD2, elle est placée dans la section 2, consacrée aux opportunités plus générales.

    Une contrainte a été respectée tout au long : seuls des embeddings polyvalents, pas de modèles spécifiques à un domaine. La spécificité du domaine provient du contenu HyDE, que le LLM intègre dans les descriptions synthétiques, et non du choix du modèle d’embedding. Cela permet au système de fonctionner dans différents domaines professionnels.

    6. Modèles différents pour des agents différents

    Toutes les tâches n’ont pas besoin de la même capacité de raisonnement. Le parseur et le générateur HyDE coûtent respectivement environ 2,7 à 3,0 et 0,50 roupies par exécution, un montant fixe indépendamment du volume de travail. Leur qualité influence tout ce qui suit, car un parseur faible corrompt le profil et une description hypothétique insuffisante altère la correspondance des embeddings ; c’est pourquoi Sonnet est le choix idéal.

    Le calcul des scores s’effectue pour chaque tâche dans le classeur, ce qui fait que c’est cette étape dont le coût augmente avec le volume de travail, et elle représente déjà de 70 à 80 pour cent du budget. Sans des scores mieux structurés, Sonnet multiplierait à peu près ce montant par trois. Haiku, quant à lui, remplit cette fonction. Voici le routage :

    7. Un fichier de configuration pour chaque paramètre réglable

    Les systèmes agents rencontrent finalement un problème de réglage. Changer de modèle, ajuster un seuil ou modifier une limite de concurrence ne devrait pas nécessiter de chercher dans cinq fichiers d’agent la constante appropriée.

    Ce système conserve un seul fichier YAML qui gère tous les paramètres du pipeline, de sorte qu’aucune constante n’est codée directement dans le code des agents et qu’aucun nombre secret ne se cache dans les prompts. Il régule :

    • Le modèle par agent. Remplacer Claude Haiku par un modèle plus récent ne nécessite qu’une modification en une seule ligne.
  • Les limites de tokens et la température sont ajustées pour chaque agent. L’extraction structurée dans le analyseur utilise une valeur de 0,1 afin que les résultats restent cohérents, tandis que le système de recommandation utilise 0,4 pour varier légèrement ses suggestions de titres.
  • Limites de concurrence et de débit : semaphore_size: 4, batch_size: 4 et batch_delay_secs: 2, expliquées ci-après.
  • 8. Classement concurrent, influencé par les limites de débit

    Le premier système de classement était séquentiel : une appel à l’LLM, attente, puis le travail suivant. Avec 40 tâches et environ 2,5 secondes par appel, cela représente 100 secondes en temps réel. Les données du pipeline le confirment, le système de classement seul prenant environ 95 secondes sur une durée totale typique de 166 secondes.

    Envoyer les 40 appels en même temps semble être la solution, mais cela entre en conflit avec les limites de fréquence d’Anthropic. L’accès de niveau 1 limite le nombre de requêtes par minute, de sorte que 40 à 60 appels simultanés dépassent immédiatement cette limite et génèrent des erreurs 429. La première version en production, sans aucun mécanisme de limitation, ne renvoyait que une partie des résultats : les tâches 1 à 70 ont été évaluées avant que l’API cesse de répondre.

    La solution réside dans une conception de concurrence en trois parties, entièrement contrôlée depuis le fichier de configuration :

    • Un sémaforo (semaphore_size: 4) limite le nombre d’appels en cours à tout moment. Quatre appels simultanés restent largement dans les limites du niveau 1.
    • Le regroupement (batch_size: 4) permet d’évaluer les tâches par groupes de quatre, et chaque groupe est terminé avant que le suivant ne commence.
    • Un délai entre les groupes (batch_delay_secs: 2) ajoute une pause de deux secondes entre eux afin de faire face aux pics de charge.

    Le résultat : 60 tâches réparties en 15 lots sont traitées en environ 90 à 95 secondes, soit quatre fois plus rapidement que la méthode séquentielle avec le même nombre de tâches, sans atteindre de limites.

    Observabilité

    Un système que personne ne peut observer n’est qu’un espoir, pas un véritable système. Un incident réel le montre bien. Lors de la première exécution en production complète, l’instance EC2 manquait de VOYAGE_API_KEY. Le préfiltre HyDE a ignoré silencieusement l’incorporation de cette clé et a transmis toutes les 89 tâches au classeur, ce qui a déclenché la limite de vitesse à la 70e tâche, entraînant une liste partielle. Sans capacité d’observation, cela ressemblerait à un comportement aléatoire et déroutant. Avec elle, il a fallu moins d’une minute pour identifier la cause.

    L’observabilité fonctionne ici à deux niveaux :

    • LangSmith enregistre chaque appel à un LLM : le prompt exact, la réponse, la latence par appel ainsi que le nombre de tokens. Il offre une visibilité au niveau micro sur le processus de raisonnement et est utilisé pendant le développement pour détecter les dégradations des prompts avant qu’elles n’affectent l’ensemble du pipeline.
    • MLflow enregistre chaque exécution avec la latence par agent, le coût total et le nombre de tokens. Son fichier job_audit.json constitue l’outil diagnostique le plus utile, car il contient un enregistrement complet de chaque tâche ayant été traitée : la section HyDE dans laquelle elle a abouti, son score de similarité, le filtre qui l’a éliminée et les raisons, les composants de son score d’ajustement ainsi que sa position finale.

    À quoi ressemble la maturité

    La maturité d’un système d’IA n’est pas mesurée par son degré d’autonomie. Elle est évaluée selon la capacité des gens à comprendre ce qu’il fait, pourquoi il le fait et où il commet des erreurs. Parler d’IA agente optimisée pour la mauvaise métrique est inapproprié. L’autonomie permet de réaliser des démonstrations impressionnantes, mais elle constitue souvent une mauvaise caractéristique d’ingénierie, car le comportement autonome est coûteux à observer et à déboguer.

    Pour quiconque développe un système d’IA aujourd’hui, les questions pertinentes ne portent pas sur son degré d’agentivité ou sur le nombre d’agents qu’il contient. Ce sont plutôt les suivantes :

    • Pouvez-vous observer ce qu’il fait à chaque étape ?
    • Pouvez-vous expliquer un résultat spécifique sans avoir accès au code source ?
    • Pouvez-vous le recalibrer lorsque son comportement dévie ?
    • Pouvez-vous distinguer une bonne performance d’un échec silencieux ?

    Un système qui répond positivement aux quatre questions est un système d’apprentissage automatique fonctionnel. Tout le reste n’est qu’un prototype doté d’une bonne stratégie marketing.