Garantir la qualité du matching
Le principe : la confiance est graduée, jamais binaire
La recherche hybride (leçon prĂ©cĂ©dente) produit des candidats scorĂ©s â mais que fait-on du score ? Le pipeline le transforme en dĂ©cision Ă trois issues via deux seuils :
fast match : score â„ 0.85 â matched (voie rapide, SQL pur)
sinon â deep match (réécritures Haiku + rerank Cohere)
deep match : score â„ 0.6 â matched
candidat < 0.6 â needs_review (l'humain tranchera)
aucun candidat â not_found
Le point de design essentiel : le systĂšme ne force jamais un match douteux. Une ligne needs_review conserve son best_match ET ses alternatives (top-4) â l'UI prĂ©sente le doute au lieu de le cacher. Chaque ligne persiste aussi match_confidence et matched_by (history|fast|deep|direct) : la provenance de chaque dĂ©cision est auditable.
Ă noter (honnĂȘtetĂ© du rĂ©tro-engineering) : ces seuils sont aujourd'hui globaux et codĂ©s en dur â le ScoringConfig porte un commentaire « later read from tenant config ». Un grossiste en visserie et un distributeur pharma n'ont sans doute pas la mĂȘme tolĂ©rance au faux positif.
Le cache d'apprentissage : product_match_history
La source la plus prioritaire du pipeline n'est ni le SQL ni le LLM â c'est la mĂ©moire :
- Ă la fin de chaque pipeline, le node
match_historyupsert chaque ligne rĂ©solue : clĂ© = nom produit normalisĂ© (accents retirĂ©s, minuscules, espaces rĂ©duits â « CĂąble RJ45 Cat6 » ⥠« cable rj45 cat6 »), valeur = variant matchĂ© +usage_countincrĂ©mentĂ© ; - au pipeline suivant, une phase 0 consulte ce cache en batch AVANT tout matching : hit â
matched_by="history", statutmatched, fast et deep entiĂšrement court-circuitĂ©s (zĂ©ro LLM, zĂ©ro rerank) ; - le tout scoppĂ© par tenant automatiquement â c'est une table sous RLS comme les autres (leçon 2 !). SubtilitĂ© : le prix n'est PAS cachĂ© â il est rechargĂ© du catalogue courant Ă chaque hit (un prix figĂ© dans un cache serait un bug mĂ©tier).
Un client B2B recommande souvent les mĂȘmes produits avec les mĂȘmes libellĂ©s : ce cache transforme le 2á” import en opĂ©ration quasi gratuite et dĂ©terministe.
Le feedback utilisateur : product_match_feedback
Quand l'utilisateur corrige un match dans l'UI (PATCH .../lines/{id}), le systĂšme capture le signal : le candidat choisi est flaggĂ© was_overridden_by_user, son rang d'origine enregistrĂ©. Et Ă chaque deep match, un snapshot du top-K (avec les 5 sous-scores de chaque candidat) est persistĂ© avec was_selected. Cette table est un dataset d'entraĂźnement en construction : elle contient exactement ce qu'il faut pour, un jour, entraĂźner un reranker maison â features (sous-scores) + label (le choix humain).
Nuance dĂ©couverte au rĂ©tro-engineering : les corrections humaines vont dans PMF mais ne sont pas rĂ©injectĂ©es dans le cache history â corriger un match ne « rĂ©pare » pas encore la mĂ©moire. La boucle d'apprentissage temps rĂ©el n'est fermĂ©e qu'Ă moitiĂ©.
Les garde-fous en amont : ne pas matcher du faux
La qualitĂ© du matching commence avant le matching â si le structurer hallucine une ligne, tout l'aval travaille sur du vent :
- grounding par contrat : le prompt d'extraction interdit d'inventer un SKU, impose
raw_text(le texte source exact) sur chaque ligne â chaque sortie est traçable vers sa source ; - validator : lignes sans nom, quantitĂ© †0 ou non numĂ©rique â Ă©liminĂ©es ; un
validation_scoreglobal dĂ©clenche l'erreur bloquante si tout est invalide ; - critique LLM : les lignes suspectes (score faible, nom trop court/long) passent devant Haiku qui dĂ©tecte les artefacts classiques (un sous-total pris pour un produit, un doublon) â aujourd'hui en tĂ©lĂ©mĂ©trie seule, la boucle de re-extraction n'est pas cĂąblĂ©e ;
- brand veto & golden match : les deux rĂšgles dures du scoring â jamais de faux positif inter-marques, jamais de doute sur un SKU exact ;
- anti-pollution : le pipeline live ne crée jamais de produit au catalogue (
allow_auto_create=False) â un email mal lu ne peut pas inventer un variant.
Les chantiers ouverts (et comment l'histoire s'est écrite)
Au moment du rĂ©tro-engineering initial, trois manques Ă©taient visibles â tu as les concepts pour les nommer :
- l'éval offline : des golden sets dormaient dans
samples/sans harness pour les rejouer⊠ce manque a depuis Ă©tĂ© comblĂ© â un harness d'Ă©val complet a Ă©tĂ© construit (corpus de cas durs, scorecard, runs Langfuse), et il a immĂ©diatement fait progresser le matcher. C'est toute la leçon suivante, la plus instructive du module ; - pas de mĂ©triques agrĂ©gĂ©es en prod : le taux de correction utilisateur (LE capteur de qualitĂ©) est calculable en SQL dans PMF, mais aucun compteur/dashboard ne le suit en continu â le « monitoring Ă©tage 4 » du cours ML, toujours Ă construire ;
- seuils non tenant-isĂ©s et boucle historyâfeedback ouverte : l'Ă©val a d'ailleurs prouvĂ© le danger de cette boucle (le cache apprend les erreurs d'un premier import ratĂ© et les re-sert). Premier correctif mergĂ© depuis : un trust gate â le cache ne mĂ©morise et ne re-sert que les matchs confiants. La rĂ©forme complĂšte (write-on-validation + invalidation) reste au backlog.
La morale d'étape : la mécanique de qualité au fil de l'eau (seuils, revue, mémoire, garde-fous) était solide ; dÚs que la mesure systématique est arrivée, elle a trouvé en quelques jours ce que des mois d'usage n'avaient pas prouvé.
Une ligne dont le meilleur candidat score 0.55 au deep match devientâŠ