使用客户端 AI 探索产品评论建议

发布时间:2024 年 10 月 21 日

在线商店可以通过展示产品评论来看到 转化率提高 270%。负面评论也很关键,因为它们可以建立信誉。82% 的在线购物者在购买前会查看负面评论。

鼓励客户留下有用的产品评论,尤其是负面评论,可能很棘手。在这里,我们将探讨如何使用生成式 AI 来帮助用户撰写信息丰富的评论,以帮助其他人的购买决策。

演示和代码

体验我们的产品评论演示,并研究 GitHub 上的代码

我们是如何构建的

客户端 AI

对于此演示,我们出于以下原因在客户端实现了该功能

  • 延迟。我们希望在用户停止输入后尽快提供建议。我们可以通过避免服务器往返来实现这一点。
  • 成本。 虽然这是一个演示,但如果您正在考虑在生产环境中启动类似的功能,那么在验证该功能是否对您的用户有意义之前,以零服务器端成本进行实验是非常好的。

MediaPipe 生成式 AI

我们选择通过 MediaPipe LLM Inference API (MediaPipe GenAI 包) 使用 Gemma 2B 模型,原因如下

  • 模型准确性:Gemma 2B 在大小和准确性之间提供了很好的平衡。在正确提示的情况下,它给出了我们认为对此演示令人满意的结果。
  • 跨浏览器支持所有支持 WebGPU 的浏览器都支持 MediaPipe。

用户体验

应用性能最佳实践

虽然 Gemma 2B 是一个小型 LLM,但它仍然是一个很大的下载。应用性能最佳实践,其中包括使用 Web Worker。

使功能成为可选

我们希望基于 AI 的评论建议能够增强用户发布产品评论的工作流程。在我们的实现中,即使模型尚未加载,因此没有提供改进建议,用户仍然可以发布评论。

图 1. 即使 AI 功能尚未准备就绪,用户仍然可以发布他们的评论。

UI 状态和动画

推理通常比 即时感觉需要更多时间,因此我们向用户发出信号,表明模型正在运行推理或“思考”。我们使用动画来缓解等待,同时向用户保证应用程序正在按预期工作。了解我们在演示中实施的 不同 UI 状态,由 Adam Argyle 设计。

图 2. 动画演示了模型正在加载,然后“思考”,最后完成。

其他注意事项

在生产环境中,您可能需要

  • 提供反馈机制。 如果建议平庸或没有意义怎么办?实施快速反馈机制(例如,赞和踩),并依靠启发式方法来确定用户认为有用的内容。例如,评估有多少用户正在与该功能互动,以及他们是否关闭了该功能。
  • 允许选择退出。 如果用户更喜欢使用自己的语言而不使用 AI 辅助,或者觉得该功能很烦人怎么办?允许用户选择退出,并在需要时选择重新加入。
  • 解释为什么存在此功能。 简短的解释可能会鼓励您的用户使用反馈工具。例如,“更好的反馈有助于其他购物者决定购买什么,并帮助我们创建您想要的产品。” 您可以添加关于该功能如何工作以及您为什么提供该功能的详细解释,也许可以链接到“了解更多”。
  • 在相关的地方披露 AI 的使用。 使用客户端 AI,用户的内容不会发送到服务器进行处理,因此可以保持私密性。但是,如果您构建服务器端回退或以其他方式使用 AI 收集信息,请考虑将其添加到您的隐私政策、服务条款或其他位置。

实施

我们为产品评论建议器实施的方案可能适用于广泛的用例。请将以下信息视为您未来客户端 AI 功能的基础。

Web Worker 中的 MediaPipe

使用 MediaPipe LLM 推理,AI 代码只有几行:创建一个文件解析器和一个 LLM 推理对象,方法是向其传递一个模型 URL,然后稍后使用该 LLM 推理实例来生成响应。

但是,我们的代码示例稍微复杂一些。这是因为它是在 Web Worker 中实现的,因此它通过自定义消息代码与主脚本传递消息。了解有关 此模式的更多信息。

// 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',
};

输入和输出

图 3. 一个图表,演示了提示通过推理处理到原始 LLM 输出,然后解析为可读的显示建议。

我们的 完整提示 是使用 少样本提示 构建的。它包括用户的输入,或者换句话说,用户编写的评论草稿。

为了根据用户输入生成我们的提示,我们在运行时调用我们的实用函数 generatePrompt

与服务器端 AI 相比,客户端 AI 模型和库通常附带的实用程序较少。例如,JSON 模式通常不可用。这意味着我们需要在提示中提供所需的输出结构。这不如通过模型配置提供模式那么干净、可维护和可靠。此外,客户端模型往往较小,这意味着它们更容易在其输出中出现结构性错误。

在实践中,我们观察到,与 JSON 或 JavaScript 相比,Gemma 2B 在以文本形式提供结构化输出方面做得更好。因此,对于此演示,我们选择了基于文本的输出格式。模型生成文本,然后我们将输出解析为 JavaScript 对象,以便在我们的 Web 应用程序中进一步处理。

改进我们的提示

My prompt and the response in the Gemini Chat interface.
图 4. 我们要求 Gemini Chat 改进我们的提示,它给出了答案,并解释了进行了哪些改进,以及关于有效性的警告。

我们使用 LLM 来迭代我们的提示。

  • 少样本提示。 为了为我们的少样本提示生成示例,我们依赖于 Gemini Chat。Gemini Chat 使用最强大的 Gemini 模型。这确保我们生成了高质量的示例。
  • 提示润色。 一旦提示的结构准备就绪,我们还使用 Gemini Chat 来改进提示。这提高了输出质量。

使用上下文来提高质量

在我们的提示中包含产品类型有助于模型提供更相关、更高质量的建议。在此演示中,产品类型是静态的。在实际应用中,您可以根据用户正在访问的页面,将产品动态地包含到您的提示中。

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

我们的提示的少样本部分中的一个示例:产品类型(“袜子”)包含在建议的修复和示例评论中。

LLM 故障和修复

Gemma 2B 通常比功能更强大、更大的服务器端模型需要更多的提示工程

我们遇到了 Gemma 2B 的一些挑战。以下是我们如何改进结果

  • 过于友善。 Gemma 2B 难以将评论标记为“没有帮助”,似乎不愿做出判断。我们尝试使标签语言更中性(“具体”和“不具体”,而不是“有帮助”和“没有帮助”),并添加了示例,但这并没有改善结果。真正改善结果的是提示中的坚持和重复。思维链方法也可能会产生改进。
  • 指令不明确。 该模型有时会过度解释提示。它没有评估评论,而是继续示例列表。为了解决这个问题,我们在提示中包含了一个清晰的过渡

    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>
    

    清晰地构建提示有助于模型区分示例列表(少样本)和实际输入。

  • 目标错误。 偶尔,该模型会建议更改产品而不是评论文本。例如,对于评论“我讨厌这些袜子”,该模型可能会建议“考虑用不同的品牌或款式替换袜子”,这不是想要的效果。拆分提示有助于明确任务,并提高了模型对评论的关注度。