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é.
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.
- 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.
- 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.
- É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.
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.
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.jsonconstitue 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.