Une cliente regarde la veste Vallo sur notre site. Le mannequin la porte bien, mais la question que personne ne pose à voix haute reste entière : et sur moi ?

Depuis juin 2026, elle peut répondre elle-même. Un bouton « Essayer » sous la sélection de taille, une photo, quelques secondes d’attente, et la veste apparaît sur elle, dans son salon, avec sa coiffure et ses chaussures.

Sur le papier, c’est une démo d’IA générative comme on en voit passer chaque semaine. En production, sur huit storefronts européens et tout le prêt-à-porter femme et homme, c’est autre chose : un service qui doit refuser ce qu’il ne sait pas faire, protéger la photo qu’on lui confie, tenir quand le modèle se trompe, et prouver qu’il sert à quelque chose. Voici comment on l’a construit.

Fiche produit mobile de la veste Vallo, avec le bouton Essayer entre le choix de taille et l'ajout au panier Fenêtre Essayage virtuel sur mobile : conseils de cadrage, boutons Importer et Appareil photo, mentions sur le traitement par IA
Le point d'entrée sur la fiche produit, puis l'étape photo, avec les conseils de cadrage et les mentions IA.

Pourquoi le faire nous-mêmes

L’idée n’était pas neuve chez nous. Une première version renvoyait vers un service tiers : un lien sortant, une expérience hors du site, aucune prise sur le rendu ni sur les données. Elle a été retirée en janvier, pendant la refonte.

Ce qui avait changé entre-temps, ce sont les modèles. Les modèles d’image de Gemini savent désormais composer une scène à partir de plusieurs images en gardant l’identité d’une personne. Le cœur du problème n’était plus de générer une image, mais d’encadrer un modèle qui sait déjà le faire : lui dire quoi garder, quoi remplacer, et quand se taire.

Le premier jet du service a été écrit par un agent de code le 31 mars. Quatre semaines de durcissement plus tard, il partait en production, encore invisible pour les clientes.

Un service, trois appels au modèle

L’essayage est une fonction AWS Lambda derrière notre passerelle d’API, à côté d’Helios, notre couche catalogue. Elle reçoit la photo de la cliente et l’URL du visuel produit, et appelle Gemini trois fois, avec trois rôles bien séparés.

Pipeline de l'essayage virtuel : la photo et le visuel passent par le guardian, le générateur puis le critique ; le guardian peut refuser, le critique peut écarter, et un score moyen déclenche une seconde passe. Photo + visuel produit Guardian valide, classe Générateur par famille Critique score 0-100 Résultat score < 50 : seconde passe avec les défauts relevés Refus 422 photo, cadrage, famille Écarté si score < 20
Trois appels au modèle, trois occasions de dire non. Le critique est le seul maillon qui échoue ouvert : en panne, l'image est affichée.

Le guardian : valider et classer avant de dépenser

Le premier appel ne génère rien. Il regarde les deux images et répond en JSON compact : la photo est-elle exploitable, quel est le cadrage (corps entier, buste, portrait), et dans quelle famille tombe le vêtement (robe, bas, haut, accessoire, ou exclu comme les chaussures et les bijoux).

C’est le filtre le moins cher et le plus utile du pipeline. Pas de personne sur la photo, plusieurs personnes, une capture d’écran, un mannequin, une image floue, un enfant : refus immédiat, avec un code précis que le site traduit en message clair dans les cinq langues.

Le guardian sert aussi à refuser ce qui ne marchera pas. Une robe ou un pantalon demandent une photo en pied ; un haut, au moins le buste. Plutôt que de générer une image ratée, le service répond 422 avec body_type_full_required, et l’interface demande une autre photo.

On a appris une chose dès les premiers jours : la sortie d’un modèle est une entrée utilisateur, à valider comme telle. Le JSON du guardian passe par un schéma Zod, et chaque champ a un repli explicite quand le modèle invente une valeur :

const guardianSchema = z.object({
  isValid: z.boolean(),
  bodyType: z.enum(['full_body', 'upper_body', 'portrait']).catch('full_body'),
  garmentBucket: z.enum(['dress', 'bottom', 'top', 'accessory', 'excluded', 'unknown']).catch('unknown'),
  reason: z
    .enum(['no_human_found', 'multiple_persons', 'inappropriate_content',
      'child_detected', 'not_a_photo', 'poor_quality', 'image_rejected'])
    .nullable()
    .catch('image_rejected'),
});

Un motif de refus imprévu devient image_rejected, que le site sait afficher. Le front ne reçoit jamais une chaîne qu’il ne connaît pas.

Le générateur : des règles au pixel près

Le deuxième appel produit l’image. Son prompt tient en deux blocs.

Le premier est un verrou d’identité : la sortie montre la même personne, le même visage, la même silhouette, la même pose et le même arrière-plan que la photo d’origine. Quand on fournit au modèle une seconde image du produit porté par un mannequin, pour l’aider sur le tombé, il a une fâcheuse tendance à reprendre le mannequin. Le prompt le lui interdit en toutes lettres.

Le second bloc dépend de la famille du vêtement, et c’est là que la qualité s’est jouée. Une consigne générale comme « remplace la tenue » donne des robes portées par-dessus un jean. Les règles décrivent donc le résultat attendu zone par zone : sous l’ourlet d’une robe, des jambes nues puis les chaussures d’origine ; pour un pantalon, le haut reste identique au pixel près au-dessus de la taille ; pour un sac, aucun bras ne grossit pour le tenir.

Le nom, la couleur, la matière et la catégorie du produit sont injectés dans le prompt, après nettoyage : ce sont des données du catalogue, mais on ne laisse aucun texte libre arriver brut dans une consigne.

Le critique et la seconde passe

Le troisième appel relit l’image générée face à la photo d’origine et rend un score de 0 à 100, avec des codes de défaut : personne remplacée, arrière-plan modifié, vêtement d’origine encore visible dessous, couleur fausse, texture perdue.

Sous 20, l’image est écartée et la cliente voit un message d’échec plutôt qu’un rendu cassé. Au-dessus, elle s’affiche tout de suite. Et si le score reste sous 50, le navigateur relance discrètement une seconde génération en passant les défauts relevés : chaque code correspond à une consigne corrective précise, beaucoup plus efficace qu’un « fais mieux ». Si la seconde passe aboutit, son image remplace la première ; si elle échoue, la première reste.

Le critique est le seul maillon qui échoue ouvert. Une panne passagère de la relecture ne doit pas jeter une image déjà payée et probablement correcte : on lui substitue un verdict neutre et on affiche. Le guardian, lui, échoue fermé. La règle est simple : on est indulgent sur la qualité, jamais sur ce qu’on accepte d’envoyer au modèle.

La photo d’une cliente n’est pas une donnée comme les autres

Le service manipule une photo personnelle. Quelques principes ont guidé chaque décision.

  • Rien n’est stocké. La photo traverse le service en mémoire et disparaît à la fin de la requête. L’interface le dit avant l’envoi, avec la mention que l’image sera traitée par IA.
  • Le navigateur réduit la photo avant l’envoi : 1 280 pixels de côté, JPEG. Moins de données transmises, des appels plus rapides, et aucune photo de 12 mégapixels qui transite pour rien.
  • Le service ne va chercher que nos visuels. L’URL du produit vient du navigateur : elle n’est suivie que si elle pointe vers nos domaines d’images, en HTTPS, sans redirection, avec une taille plafonnée.
  • Un débit limité par connexion, une liste fixe d’origines autorisées, et des modèles choisis par configuration, pour changer de version sans redéployer le code.
  • Réservé aux adultes. Le guardian refuse une photo d’enfant, et depuis septembre le module n’apparaît plus sur les produits enfant.
  • Une mention claire sur chaque résultat : l’image est générée par IA et peut être imparfaite.

Ouvrir par étapes

Le service est en production fin avril, mais le module n’apparaît que sur les produits dont le type figure dans une liste blanche, réglée storefront par storefront dans le back-office Magento. L’ouverture s’est faite par familles :

Date Étape
31 mars Premier jet du service
fin avril Service en production, module éteint
juin Ouverture des tops et des jeans, puis des robes et des t-shirts
9 juillet Passage à la génération 3.x des modèles Gemini
27 juillet Tout le prêt-à-porter femme et homme, sur les storefronts européens
septembre Motif de chaque refus journalisé, produits enfant exclus

Le passage aux modèles 3.x a apporté une contrainte inattendue : les modèles d’image de cette génération ne sont servis que sur le point de terminaison global de Google Cloud, pas dans une région européenne. Une valeur régionale dans la configuration casse simplement la génération. C’est noté en tête du fichier de configuration, parce que c’est le genre de détail qu’on redécouvre à 23 heures.

Le site américain n’a pas le module : sa liste de types est vide. Un réglage, pas une branche de code.

Ce que disent les chiffres

Août 2026 est le premier mois complet et comparable. On a mesuré sur les marchés européens, en comptant des visiteurs distincts sur le mois.

Entonnoir de l'essayage virtuel en août 2026, en part des visiteurs qui ouvrent le module : 100 % ouvrent, 29,7 % envoient une photo, 28,6 % lancent un essayage, 21 % voient un résultat, 5 % téléchargent l'image. Ouvre le module 100 % Envoie une photo 29,7 % Lance un essayage 28,6 % Voit un résultat 21 % Télécharge l'image 5 %
Août 2026, marchés européens, part des visiteurs qui ouvrent le module. Le décrochage se joue avant le modèle : à l'envoi de la photo.

Deux décrochages dominent. Sept visiteurs sur dix qui ouvrent le module n’envoient jamais de photo. Et parmi ceux qui lancent un essayage, plus d’un sur deux rencontre au moins un échec.

On pensait que ces échecs venaient du modèle. Les journaux du service disent l’inverse : sur les requêtes d’août et du début septembre, un quart sont des refus de la photo avant toute génération, et les pannes techniques pèsent environ 1 %. Le frein n’est ni la latence ni la fiabilité de Gemini, c’est la photo : mauvais cadrage, plusieurs personnes, image trop sombre. C’est pour pouvoir le lire qu’on journalise depuis septembre le motif de chaque refus.

Reste la question que tout le monde pose : est-ce que ça fait vendre ?

La réponse facile serait de comparer les utilisateurs du module à l’ensemble des visiteurs de fiche produit. L’écart est spectaculaire, proche d’un facteur dix. Il ne veut rien dire : ouvrir le module est un geste volontaire, fait par des visiteurs déjà très engagés. Cette comparaison mesure qui choisit d’essayer, pas ce que l’essayage produit.

La lecture qu’on retient compare les utilisateurs du module entre eux, à intention égale :

Comparaison (août 2026) Écart de conversion Significativité
A vu un résultat (≈ 1 900 visiteurs) contre a seulement ouvert le module (≈ 6 500) +24 % relatif oui, z ≈ 2,6, p < 0,01
A vu un résultat contre n’a eu que des échecs (≈ 700) dans le même sens non, p ≈ 0,10

Les visiteurs qui obtiennent un rendu convertissent nettement plus que ceux qui se contentent d’ouvrir le module. L’écart face à ceux qui n’ont eu que des échecs va dans le même sens, mais l’échantillon ne permet pas de l’affirmer.

Il faut aussi dire ce que ces chiffres ne sont pas. Il n’y a pas de groupe témoin : le module est ouvert à tous les visiteurs éligibles. Ce sont des associations, mesurées en cohorte sur le mois, pas un effet causal. Mais elles disent où agir : augmenter la part des photos acceptées.

Ce qu’on a appris

  • Encadrer coûte plus cher que générer. Le modèle savait produire une image dès le premier jour. Les semaines suivantes ont servi à décider quand ne pas le faire, et à rendre chaque refus compréhensible.
  • Plusieurs appels spécialisés battent un prompt géant. Valider, générer et relire sont trois métiers. Les séparer a rendu chaque étape testable, et chacune peut changer de modèle indépendamment.
  • Choisir où l’on échoue ouvert. Fermé sur ce qu’on accepte, ouvert sur la relecture de qualité. Écrit dans le code, pas dans une page de doc.
  • Mesurer avant d’optimiser le mauvais maillon. On aurait pu passer l’été à accélérer la génération. Les chiffres montrent que le levier est en amont, dans l’aide à la prise de photo.
  • Refuser la comparaison flatteuse. Un facteur dix aurait fait un beau titre. Un +24 % mesuré à intention égale, avec ses limites, est un chiffre sur lequel on peut décider.

La suite est déjà écrite par ces mesures : mieux guider la photo avant l’envoi, compter les fiches réellement éligibles pour connaître le vrai taux d’adoption, et, le jour où le volume le permet, un test A/B pour passer de l’association à l’effet.