Construire l'outil de recherche sémantique
Réutiliser la brique du module 9
Section titled “Réutiliser la brique du module 9”L’outil de recherche sémantique reprend directement la technique du module 9 : encoder du texte libre en vecteurs, puis mesurer une similarité cosinus par simple produit scalaire.
def company_culture_tool(souhait_candidat, top_k=None): """Classe TOUTES les entreprises par similarite semantique. top_k=None (par defaut) retourne le classement complet, pour pouvoir noter n'importe quelle offre, pas seulement les mieux classees.""" embedder = _get_embedder() emb = embedder.encode(souhait_candidat, normalize_embeddings=True) similarites = _embeddings_entreprises @ emb ordre = np.argsort(-similarites) if top_k is not None: ordre = ordre[:top_k] return [(ids[i], noms[i], float(similarites[i])) for i in ordre]Un piège réel : ne classer que les meilleures ne suffit pas
Section titled “Un piège réel : ne classer que les meilleures ne suffit pas”Une première version de cet outil ne renvoyait que les 3 entreprises les plus proches de l’envie exprimée (top_k=3). Problème découvert en testant l’agent complet : certaines offres retenues par l’outil SQL appartenaient à des entreprises hors de ce top 3, et se retrouvaient donc sans aucun score d’affinité (NaN) une fois les deux résultats combinés.
# Ce test documente exactement ce piège, comme garde-fou permanent :def test_agent_never_leaves_an_offer_without_a_cultural_score(conn): resultats, _ = job_search_agent(...) assert resultats["affinite_culture"].notna().all()La correction : faire de top_k=None (classement complet) le comportement par défaut de l’outil, et ne tronquer qu’au moment de l’affichage si nécessaire — jamais avant d’avoir combiné les résultats des deux outils. Une fonction utilitaire réutilisée par deux composants différents (ici : booster l’affichage d’un côté, noter des offres arbitraires de l’autre) doit rester complète par défaut ; c’est à l’appelant de tronquer s’il en a besoin, pas à l’outil de décider à sa place.
Prochaine étape
Section titled “Prochaine étape”👉 Le cœur de l’agent : relâchement de contraintes
Junior TSAFACK – 12/09/2026