Explorer des suggestions d'avis sur les produits avec l'IA côté client

Maud Nalpas
Maud Nalpas

Publié le 21 octobre 2024

Les magasins en ligne peuvent enregistrer une augmentation de 270% du nombre de conversions en affichant des avis sur les produits. Les avis négatifs sont également essentiels, car ils renforcent leur crédibilité. 82 % des acheteurs en ligne les recherchent avant d'acheter.

Il peut être difficile d'encourager les clients à rédiger des avis sur les produits, en particulier lorsqu'ils sont négatifs. Nous allons voir comment utiliser l'IA générative pour aider les utilisateurs à rédiger des avis informatifs qui aident les autres à prendre des décisions d'achat.

Démo et code

Utilisez notre démonstration sur les avis sur les produits et examinez le code sur GitHub.

Comment nous avons créé cette fonctionnalité

IA côté client

Pour cette démonstration, nous avons implémenté la fonctionnalité côté client pour les raisons suivantes :

  • Latence. Nous souhaitons fournir des suggestions rapidement, dès que l'utilisateur cesse de taper. Pour ce faire, nous évitons les aller-retours vers le serveur.
  • Coût Bien qu'il s'agisse d'une démonstration, si vous envisagez de lancer une fonctionnalité similaire en production, il est intéressant de la tester sans frais côté serveur jusqu'à ce que vous puissiez vérifier si elle a du sens pour vos utilisateurs.

IA générative MediaPipe

Nous avons choisi d'utiliser le modèle Gemma 2B via l'API d'inférence LLM MediaPipe (package MediaPipe GenAI), pour les raisons suivantes:

  • Précision du modèle: Gemma 2B offre un excellent équilibre entre taille et précision. Lorsqu'il a été correctement invité, il a fourni des résultats que nous avons jugés satisfaisants pour cette démonstration.
  • Compatibilité multinavigateur : MediaPipe est compatible avec tous les navigateurs compatibles avec WebGPU.

Expérience utilisateur

Appliquer les bonnes pratiques en matière de performances

Bien que Gemma 2B soit un petit LLM, il s'agit tout de même d'un téléchargement volumineux. Appliquez les bonnes pratiques en matière de performances, y compris l'utilisation d'un worker Web.

Rendre la fonctionnalité facultative

Nous souhaitons que les suggestions d'avis basées sur l'IA améliorent le workflow de l'utilisateur lorsqu'il souhaite publier un avis sur le produit. Dans notre implémentation, l'utilisateur peut publier un avis même si le modèle n'est pas chargé et ne propose donc pas de conseils d'amélioration.

Figure 1. Les utilisateurs peuvent toujours publier leur avis, même lorsque la fonctionnalité d'IA n'est pas encore prête.

États et animations de l'interface utilisateur

L'inférence prend généralement plus de temps qu'une opération immédiate. Nous signalons donc à l'utilisateur que le modèle exécute une inférence (ou "réflexion"). Nous utilisons des animations pour faciliter l'attente, tout en assurant à l'utilisateur que l'application fonctionne comme prévu. Découvrez les différents états de l'interface utilisateur que nous avons implémentés dans notre démonstration, conçus par Adam Argyle.

Figure 2. Les animations montrent que le modèle est en cours de chargement, puis en phase de réflexion, et enfin terminé.

Autres points à noter

Dans un environnement de production, vous pouvez :

  • Fournissez un mécanisme d'envoi de commentaires. Que faire si les suggestions sont médiocres ou n'ont aucun sens ? Implémentez un mécanisme de commentaires rapides (comme les "J'aime" et "Je n'aime pas") et appliquez des heuristiques pour déterminer ce que les utilisateurs trouvent utile. Par exemple, évaluez combien d'utilisateurs interagissent avec la fonctionnalité et s'ils la désactivent.
  • Autoriser la désactivation. Que se passe-t-il si l'utilisateur préfère utiliser ses propres mots sans l'aide de l'IA ou s'il trouve la fonctionnalité gênante ? Autorisez l'utilisateur à désactiver et réactiver la fonctionnalité selon ses besoins.
  • Expliquez l'intérêt de cette fonctionnalité. Une brève explication peut encourager vos utilisateurs à utiliser l'outil de commentaires. Par exemple : "De meilleurs commentaires aident les autres acheteurs à choisir ce qu'ils veulent acheter et nous aident à créer les produits que vous souhaitez." Vous pouvez ajouter une longue explication du fonctionnement de la fonctionnalité et de la raison pour laquelle vous l'avez fournie, par exemple sous la forme d'un lien vers des informations supplémentaires.
  • Indiquez l'utilisation de l'IA, le cas échéant. Avec l'IA côté client, le contenu de l'utilisateur n'est pas envoyé à un serveur pour traitement et peut donc rester privé. Toutefois, si vous créez une création de remplacement côté serveur ou collectez des informations avec l'IA, envisagez de les ajouter à vos règles de confidentialité, à vos conditions d'utilisation ou à d'autres éléments.

Implémentation

Notre implémentation du générateur d'avis sur les produits peut fonctionner pour un large éventail de cas d'utilisation. Prenez en compte les informations suivantes comme base pour vos futures fonctionnalités d'IA côté client.

MediaPipe dans un nœud de calcul Web

Avec l'inférence LLM MediaPipe, le code d'IA ne compte que quelques lignes : créez un résolveur de fichiers et un objet d'inférence LLM en lui transmettant une URL de modèle, puis utilisez cette instance d'inférence LLM pour générer une réponse.

Toutefois, notre exemple de code est un peu plus étendu. En effet, il est implémenté dans un nœud de calcul Web. Il transmet donc les messages avec le script principal via des codes de message personnalisés. En savoir plus sur ce modèle

// Trigger model preparation *before* the first message arrives
self.postMessage({ code: MESSAGE_CODE.PREPARING_MODEL });
try {
  // Create a FilesetResolver instance for GenAI tasks
  const genai = await FilesetResolver.forGenAiTasks(MEDIAPIPE_WASM);
  // Create an LLM Inference instance from the specified model path
  llmInference = await LlmInference.createFromModelPath(genai, MODEL_URL);
  self.postMessage({ code: MESSAGE_CODE.MODEL_READY });
} catch (error) {
  self.postMessage({ code: MESSAGE_CODE.MODEL_ERROR });
}

// Trigger inference upon receiving a message from the main script
self.onmessage = async function (message) {
  // Run inference = Generate an LLM response
  let response = null;
  try {
    response = await llmInference.generateResponse(
      // Create a prompt based on message.data, which is the actual review
      // draft the user has written. generatePrompt is a local utility function.
      generatePrompt(message.data),
    );
  } catch (error) {
    self.postMessage({ code: MESSAGE_CODE.INFERENCE_ERROR });
    return;
  }
  // Parse and process the output using a local utility function
  const reviewHelperOutput = generateReviewHelperOutput(response);
  // Post a message to the main thread
  self.postMessage({
    code: MESSAGE_CODE.RESPONSE_READY,
    payload: reviewHelperOutput,
  });
};
export const MESSAGE_CODE ={
  PREPARING_MODEL: 'preparing-model',
  MODEL_READY: 'model-ready',
  GENERATING_RESPONSE: 'generating-response',
  RESPONSE_READY: 'response-ready',
  MODEL_ERROR: 'model-error',
  INFERENCE_ERROR: 'inference-error',
};

Entrées et sorties

Figure 3. Schéma illustrant le traitement de l'invite par inférence pour obtenir une sortie LLM brute, qui est ensuite analysée pour obtenir une recommandation prête à être affichée.

Notre invite complète a été créée avec des invites few-shot. Il inclut l'entrée de l'utilisateur, c'est-à-dire le brouillon de l'avis rédigé par l'utilisateur.

Pour générer notre invite en fonction de la saisie de l'utilisateur, nous appelons au moment de l'exécution notre fonction d'utilité generatePrompt.

Les modèles et bibliothèques d'IA côté client sont généralement fournis avec moins d'utilitaires que l'IA côté serveur. Par exemple, le mode JSON n'est souvent pas disponible. Cela signifie que nous devons fournir la structure de sortie souhaitée dans notre invite. Cette approche est moins claire, moins facile à gérer et moins fiable que de fournir un schéma via la configuration du modèle. De plus, les modèles côté client ont tendance à être plus petits, ce qui signifie qu'ils sont plus sujets aux erreurs structurelles dans leur sortie.

En pratique, nous avons constaté que Gemma 2B fournit une sortie structurée sous forme de texte plus efficacement que JSON ou JavaScript. C'est pourquoi, pour cette démonstration, nous avons opté pour un format de sortie textuel. Le modèle génère du texte, que nous analysons ensuite dans un objet JavaScript pour un traitement ultérieur dans notre application Web.

Améliorer notre requête

Ma requête et la réponse dans l'interface Gemini Chat.
Figure 4. Nous avons demandé à Gemini Chat d'améliorer notre requête. Il a répondu, en expliquant les améliorations apportées et en précisant l'efficacité.

Nous avons utilisé un LLM pour itérer sur notre requête.

  • Requête few-shot : Pour générer les exemples de nos requêtes few-shot, nous nous sommes appuyés sur Gemini Chat. Gemini Chat utilise les modèles Gemini les plus performants. Nous avons ainsi généré des exemples de haute qualité.
  • Finition des requêtes Une fois la structure de l'invite prête, nous avons également utilisé Gemini Chat pour l'affiner. Cela a amélioré la qualité de la sortie.

Utiliser le contexte pour améliorer la qualité

L'inclusion du type de produit dans notre requête a permis au modèle de fournir des suggestions plus pertinentes et de meilleure qualité. Dans cette démonstration, le type de produit est statique. Dans une application réelle, vous pouvez inclure le produit de manière dynamique dans votre requête, en fonction de la page consultée par l'utilisateur.

Review: "I love these."
Helpful: No  
Fix: Be more specific, explain why you like these **socks**.
Example: "I love the blend of wool in these socks. Warm and not too heavy."

L'un des exemples de la section few-shots de notre requête: le type de produit ("chaussettes") est inclus dans la correction suggérée et dans l'exemple d'examen.

Erreurs et corrections des LLM

Gemma 2B nécessite généralement plus d'ingénierie des requêtes qu'un modèle côté serveur plus puissant et plus volumineux.

Nous avons rencontré des difficultés avec Gemma 2B. Voici comment nous avons amélioré les résultats :

  • Trop gentil. Gemma 2B a eu du mal à marquer les avis comme "non utiles", semblant hésiter à les juger. Nous avons essayé de rendre le langage des libellés plus neutre ("spécifique" et "non spécifique" au lieu de "utile" et "non utile") et avons ajouté des exemples, mais cela n'a pas amélioré les résultats. Ce qui a amélioré les résultats, c'est l'insistance et la répétition dans la requête. Une approche en chaîne de pensée est également susceptible de générer des améliorations.
  • Instructions peu claires. Le modèle a parfois surinterprété la requête. Au lieu d'évaluer l'avis, il a continué la liste d'exemples. Pour résoudre ce problème, nous avons inclus une transition claire dans l'invite :

    I'll give you example reviews and outputs, and then give you one review
    to analyze. Let's go:
    Examples:
    <... Examples>
    
    Review to analyze:
    <... User input>
    

    Une structuration claire de la requête aide le modèle à faire la différence entre la liste d'exemples (quelques plans) et l'entrée réelle.

  • Cible incorrecte. De temps en temps, le modèle suggérait des modifications du produit au lieu du texte de l'avis. Par exemple, pour un avis indiquant "Je déteste ces chaussettes", le modèle pourrait suggérer "Envisagez de remplacer les chaussettes par une autre marque ou un autre style", ce qui n'est pas l'effet souhaité. La division de l'invite a permis de clarifier la tâche et d'améliorer la concentration du modèle sur l'examen.