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

Maud Nalpas
Maud Nalpas

Publié le 21 octobre 2024

Les boutiques en ligne peuvent augmenter leurs conversions de 270% en affichant des avis sur les produits. Les avis négatifs sont également importants, car ils renforcent la 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émonstration et code

Testez notre démo d'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 facilitent le processus de publication d'un avis sur un produit pour l'utilisateur. Dans notre implémentation, l'utilisateur peut publier un avis même si le modèle n'a pas été chargé et qu'il n'offre 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 que ce qui semble immédiat. Nous signalons donc à l'utilisateur que le modèle effectue une inférence, ou "réfléchit". 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 se charge, puis "réfléchit" et est 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 le refus. 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 pourquoi cette fonctionnalité existe. Une brève explication peut encourager vos utilisateurs à utiliser l'outil d'envoi 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 un article d'informations complémentaires.
  • Communiquez sur l'utilisation de l'IA lorsque cela est pertinent. 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 un plan de secours côté serveur ou que vous collectez d'autres informations à l'aide de l'IA, envisagez de l'ajouter à votre politique de confidentialité, à vos conditions d'utilisation ou ailleurs.

Implémentation

Notre implémentation du générateur d'avis sur les produits peut fonctionner pour un large éventail de cas d'utilisation. Considérez les informations suivantes comme une 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 long. 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 les entrées de l'utilisateur, ou en d'autres termes le brouillon d'avis qu'il a rédigé.

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 requête. 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. Pour cette démonstration, nous avons donc 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êtes 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 invite, en fonction de la page que l'utilisateur consulte.

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."

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

Problèmes et correctifs liés aux LLM

Gemma 2B nécessite généralement plus d'ingénierie de requête 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 l'invite. Une approche en chaîne de pensée est également susceptible de générer des améliorations.
  • Les instructions n'étaient pas 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 l'invite aide le modèle à différencier la liste d'exemples (quelques prises de vue) de l'entrée réelle.

  • Mauvaise cible. 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.