
Classement personnalisé des restaurants avec une variante d’intégration à deux tours
j’aimerais partager une variante pratique de L’intégration à deux tours d’Uber (TTE) approche pour les cas où les données relatives aux utilisateurs et les ressources informatiques sont limitées. Le problème provenait d’un widget de découverte à fort trafic sur l’écran d’accueil d’une application de livraison de nourriture. Ce widget affiche des sélections organisées telles que italien, Des hamburgers, Sushisou En bonne santé. Les sélections sont créées à partir de balises : chaque restaurant peut avoir plusieurs balises, et chaque vignette est essentiellement une tranche du catalogue définie par des balises (avec l’ajout d’une sélection manuelle). En d’autres termes, l’ensemble des candidats est déjà connu, le vrai problème n’est donc pas la récupération mais le classement.
À cette époque, ce widget était nettement sous-performant par rapport aux autres widgets sur un écran de découverte (principal). La sélection finale a été classée selon la popularité générale sans prendre en compte aucun signal personnalisé. Ce que nous avons découvert, c’est que les utilisateurs sont réticents à faire défiler la page et s’ils ne trouvent pas quelque chose d’intéressant dans les 10 à 12 premières positions, ils ne convertissent généralement pas. D’un autre côté, les choix peuvent parfois être énormes, dans certains cas jusqu’à 1 500 restaurants. De plus, un seul restaurant peut être sélectionné pour différentes sélections, ce qui signifie que par exemple McDonald’s peut être sélectionné pour les deux. Des hamburgers et Glacemais il est clair que sa popularité n’est valable que pour la première sélection, mais le tri général de popularité le placerait en tête dans les deux sélections.
La configuration du produit rend le problème encore moins convivial pour les solutions statiques telles que le tri par popularité générale. Ces collections sont dynamiques et changent fréquemment en raison de campagnes saisonnières, de besoins opérationnels ou de nouvelles initiatives commerciales. Pour cette raison, former un modèle dédié pour chaque sélection individuelle n’est pas réaliste. Un recommandateur utile doit généraliser aux nouvelles collections basées sur des balises dès le premier jour.
Avant de passer à une solution à deux tours, nous avons essayé des approches plus simples telles qu’un classement de popularité localisé au niveau de la ville et du district et des bandits multi-armés. Dans notre cas, ni l’un ni l’autre n’a apporté une augmentation mesurable par rapport à la popularité générale. Dans le cadre de notre initiative de recherche, nous avons essayé d’ajuster le TTE d’Uber à notre cas.
Récapitulatif des intégrations à deux tours
Un modèle à deux tours apprend deux encodeurs en parallèle : un pour le côté utilisateur et un pour le côté restaurant. Chaque tour produit un vecteur dans un espace latent partagé, et la pertinence est estimée à partir d’un score de similarité, généralement un produit scalaire. L’avantage opérationnel réside dans le découplage : les intégrations de restaurants peuvent être précalculées hors ligne, tandis que l’intégration d’utilisateurs est générée en ligne au moment de la demande. Cela rend l’approche attrayante pour les systèmes nécessitant une notation rapide et des représentations réutilisables.
L’article d’Uber se concentre principalement sur la récupération, mais il note également que la même architecture peut servir de couche de classement final lorsque la génération de candidats est déjà gérée ailleurs et que la latence doit rester faible. Cette deuxième formulation était beaucoup plus proche de notre cas d’utilisation.
Notre approche

Nous avons conservé la structure à deux tours mais simplifié les parties les plus gourmandes en ressources. Du côté des restaurants, nous n’avons pas affiné de modèle linguistique au sein du recommandeur. Au lieu de cela, nous avons réutilisé un modèle TinyBERT qui avait déjà été affiné pour la recherche dans l’application et l’avons traité comme un encodeur sémantique figé. Son intégration de texte a été combinée avec des fonctionnalités explicites du restaurant telles que le prix, les notes et les signaux de performances récents, ainsi qu’une petite intégration d’ID de restaurant pouvant être entraînée, puis projetée dans le vecteur final du restaurant. Cela nous a donné une couverture sémantique sans payer le coût total de la formation de bout en bout du modèle linguistique. Pour un POC ou un MVP, un petit transformateur de phrase figé serait également un point de départ raisonnable.
Nous avons évité d’apprendre une intégration d’ID utilisateur dédiée et avons plutôt représenté chaque utilisateur à la volée à travers ses interactions précédentes. Le vecteur utilisateur a été construit à partir d’intégrations moyennes de restaurants auprès desquels le client avait commandé (le message d’Uber mentionnait également cette source, mais les auteurs ne précisent pas comment il a été utilisé), ainsi que des fonctionnalités d’utilisateur et de session. Nous avons également utilisé les vues sans ordres comme un faible signal négatif. Cela importait lorsque l’historique des commandes était rare ou sans rapport avec la sélection actuelle. Si le modèle ne permet pas de déduire clairement ce que l’utilisateur apprécie, il permet néanmoins de savoir quels restaurants ont déjà été explorés et rejetés.
Le choix de modélisation le plus important consistait à filtrer cet historique par la balise de la sélection actuelle. La moyenne de l’ensemble de l’historique des commandes créait trop de bruit. Si un client commandait principalement des hamburgers et ouvrait ensuite un Glace sélection, une moyenne mondiale pourrait orienter le modèle vers les établissements de hamburgers qui vendent des desserts plutôt que vers les meilleurs candidats aux glaces. En filtrant les interactions passées sur les balises correspondantes avant de faire la moyenne, nous avons rendu la représentation de l’utilisateur contextuelle plutôt que globale. En pratique, c’était la différence entre la modélisation du goût à long terme et la modélisation de l’intention actuelle.
Enfin, nous avons formé le modèle au niveau de la session et utilisé l’apprentissage multitâche. Le même restaurant peut être positif dans une session et négatif dans une autre, selon l’intention actuelle de l’utilisateur. Le responsable du classement a prédit conjointement le clic, l’ajout au panier et la commande, avec une simple contrainte d’entonnoir : P (commande) ≤ P (ajout au panier) ≤ P (clic). Cela a rendu le modèle moins statique et amélioré la qualité du classement par rapport à l’optimisation d’une seule cible de manière isolée.
La validation hors ligne était également plus stricte qu’une répartition aléatoire : l’évaluation utilisait des données hors délai et des utilisateurs invisibles pendant la formation, ce qui rendait la configuration plus proche du comportement de production.
Résultats
Selon les tests A/B, le système final a montré une augmentation statistiquement significative du taux de conversion. Tout aussi important, il n’était pas lié à un seul widget. Étant donné que le modèle note une paire utilisateur-restaurant plutôt qu’une liste fixe, il s’est naturellement généralisé aux nouvelles sélections sans modifications architecturales puisque les balises font partie des métadonnées du restaurant et peuvent être récupérées sans sélections à l’esprit.
Cette transférabilité a rendu le modèle utile au-delà de la surface de classement originale. Nous l’avons ensuite réutilisé dans Ads, où ses résultats orientés CTR ont été appliqués à des restaurants individuels promus avec des résultats positifs. La même configuration d’apprentissage des représentations a donc fonctionné à la fois pour le classement des sélections et pour d’autres problèmes de placement de type recommandation au sein de l’application.
Recherches complémentaires
La prochaine étape la plus évidente est la multimodalité. Des images de restaurant, des icônes et éventuellement des visuels de menu peuvent être ajoutés en tant que branches supplémentaires à la tour du restaurant. Cela est important car le comportement des clics est fortement influencé par la présentation. Une pizzeria au sein d’une sélection de pizzas peut sous-performer si son image principale ne montre pas de pizza, tandis qu’un restaurant économique peut paraître haut de gamme uniquement en raison de son image de héros. Les fonctionnalités textuelles et tabulaires ne capturent pas bien cet écart.
Points clés à retenir :
- Les modèles à deux tours peuvent fonctionner même avec des données limitées. Vous n’avez pas besoin d’une infrastructure à l’échelle Uber si la récupération des candidats est déjà résolue et que le modèle se concentre uniquement sur l’étape de classement.
- Réutilisez les intégrations pré-entraînées au lieu de les entraîner à partir de zéro. Un modèle de langage léger et figé (par exemple, TinyBERT ou un petit transformateur de phrases) peut fournir des signaux sémantiques forts sans ajustement fin coûteux.
- La moyenne des intégrations de restaurants précédemment commandés fonctionne étonnamment bien lorsque l’historique des utilisateurs est clairsemé.
- Le filtrage contextuel réduit le bruit et aide le modèle à capturer l’intention actuelle de l’utilisateur, et pas seulement son goût à long terme.
- Les signaux négatifs sont utiles dans les environnements clairsemés. Les restaurants que les utilisateurs ont consultés mais n’ont pas commandé fournissent des informations utiles lorsque les signaux positifs sont limités.
- L’apprentissage multitâche stabilise le classement. La prédiction des clics, des ajouts au panier et de la commande conjointement avec les contraintes d’entonnoir produit des scores plus cohérents.
- Conception pour la réutilisation. Un modèle qui note les paires utilisateur-restaurant plutôt que des listes spécifiques peut être réutilisé sur plusieurs surfaces de produits telles que les sélections, le classement dans les recherches ou les publicités.



