使用 WebLLM 构建本地和离线聊天机器人

发布时间:2024 年 1 月 13 日

本文是有关 LLM 和聊天机器人的三篇系列文章中的第二篇。上一篇文章讨论了设备端和浏览器端 LLM 的优缺点

现在,您已经更好地了解了客户端 AI,接下来可以将 WebLLM 添加到待办事项 Web 应用了。您可以在 GitHub 代码库的 web-llm 分支中找到该代码。

WebLLM 是机器学习编译提供的面向 LLM 的基于 Web 的运行时。您可以试用将 WebLLM 作为一款独立应用。该应用的灵感来自于云端支持的聊天应用(例如 Gemini),但 LLM 推理是在设备上运行的,而不是在云端运行。您的提示和数据绝不会离开您的设备,您可以放心,它们不会用于训练模型。

为了在设备上执行模型推理,WebLLM 结合使用了 WebAssemblyWebGPU。虽然 WebAssembly 支持在中央处理器 (CPU) 上高效计算,但 WebGPU 可让开发者对设备的图形处理单元 (GPU) 进行低级访问。

Browser Support

  • Chrome: 113.
  • Edge: 113.
  • Firefox Technology Preview: supported.
  • Safari Technology Preview: supported.

Source

安装 WebLLM

WebLLM 可作为 npm 软件包提供。您可以通过运行 npm install @mlc-ai/web-llm 将此软件包添加到您的待办事项应用。

选择模型

接下来,您需要确定要在本地执行的 LLM。有多种型号可供选择。

为此,您应了解以下关键术语和数据:

  • 令牌:LLM 可处理的最小文本单元。
  • 上下文窗口:模型可以处理的词元数量上限。
  • 参数或权重:在训练期间学习到的内部变量,数量以十亿计。
  • 量化:表示权重的位数。位数越多,精度越高,但内存用量也越高。
  • 浮点数格式:32 位浮点数(全精度,F32)提供更高的精确度,而 16 位浮点数(半精度,F16)速度更快且内存用量更低,但需要兼容的硬件。

这些关键字通常是模型名称的一部分。例如,Llama-3.2-3B-Instruct-q4f32_1-MLC 包含以下信息:

  • 模型是 LLaMa 3.2。
  • 该模型有 30 亿个参数。
  • 它经过了精细调整,适用于指令和提示式助理(Instruct)。
  • 它使用 4 位 (q4)均匀 (_1) 量化
  • 它使用全精度 32 位浮点数。
  • 这是机器学习编译创建的特殊版本。

您可能需要测试不同的模型,以确定哪种模型适合您的用例。

在撰写本文时,一个包含 30 亿个参数且每个参数为 4 位的模型的文件大小已经达到 1.4 GB,应用需要在首次使用前将其下载到用户设备上。您可以使用 3B 模型,但在翻译功能或琐事知识方面,7B 模型可以提供更好的结果。不过,如果超过 3.3 GB,则会大得多。

如需创建 WebLLM 引擎并为待办事项聊天机器人启动模型下载,请将以下代码添加到您的应用:

import {CreateMLCEngine} from '@mlc-ai/web-llm';
const engine = await CreateMLCEngine('Llama-3.2-3B-Instruct-q4f32_1-MLC', {
  initProgressCallback: ({progress}) =>  console.log(progress);
});

CreateMLCEngine 方法采用模型字符串和可选的配置对象。您可以使用 initProgressCallback 方法查询模型的下载进度,以便在用户等待时向他们显示进度。

Cache API:让 LLM 离线运行

该模型会下载到您网站的缓存存储空间中。 Cache API 与 Service Worker 一起推出,旨在让您的网站或 Web 应用能够离线运行。它是缓存 AI 模型的最佳存储机制。与 HTTP 缓存不同,Cache API 是一种可编程缓存,完全由开发者控制。

下载后,WebLLM 会从 Cache API 读取模型文件,而不是通过网络请求这些文件,从而使 WebLLM 完全脱离线。

与所有网站存储空间一样,缓存是按源站隔离的。这意味着,两个源(example.comexample.net)不能共享同一存储空间。如果这两个网站想要使用相同的模型,则必须单独下载该模型。

您可以使用开发者工具检查缓存,方法是前往应用 > 存储,然后打开“缓存”存储空间。

设置对话

模型可以使用一组初始提示进行初始化。通常,消息有三种角色:

  • 系统提示:此提示定义了模型的行为、角色和性格。它还可用于对齐,即将不属于其训练集的自定义数据(例如特定于领域的数据)馈送到模型。您只能指定一个系统提示。
  • 用户提示:用户输入的提示。
  • Google 助理提示:Google 助理的回答,可选。

用户和助理提示可用于 N 次提示,方法是向 LLM 提供有关其应如何行为或响应的自然语言示例。

以下是为待办事项应用设置对话的最小示例:

const messages = [
  { role: "system",
    content: `You are a helpful assistant. You will answer questions related to
    the user's to-do list. Decline all other requests not related to the user's
    todos. This is the to-do list in JSON: ${JSON.stringify(todos)}`
  },
  {role: "user", content: "How many open todos do I have?"}
];

回答第一个问题

聊天内容补全功能会作为之前创建的 WebLLM 引擎 (engine.chat.completions) 上的属性公开。下载模型后,您可以通过对此属性调用 create() 方法来运行模型推理。对于您的用例,您希望流式传输回答,以便用户在回答生成时开始阅读,从而缩短感知等待时间:

const chunks = await engine.chat.completions.create({  messages,  stream: true, });

此方法会返回 AsyncGenerator,它是隐藏的 AsyncIterator 类的子类。使用 for await...of 循环等待数据块的传入。不过,响应中仅包含新令牌 (delta),因此您必须自行组合完整的回复。

let reply = '';

for await (const chunk of chunks) {
  reply += chunk.choices[0]?.delta.content ?? '';
  console.log(reply);
}

事实证明,网络始终必须处理流式响应。您可以使用 DOMImplementation 等 API 处理这些流式响应并高效更新 HTML。

结果完全基于字符串。如果您想将其解读为 JSON 或其他文件格式,则必须先对其进行解析。

不过,WebLLM 有一些限制:应用需要在首次使用前下载一个巨大的模型,该模型无法跨源共享,因此其他 Web 应用可能必须重新下载相同的模型。虽然 WebGPU 可实现接近原生推理性能,但未达到完全原生速度。

演示

Prompt API 解决了这些缺点。Prompt API 是由 Google 提出的一种探索性 API,它也运行在客户端,但使用下载到 Chrome 中的中央模型。这意味着,多个应用可以以全速执行速度使用相同的模型。

请参阅下一部分,详细了解如何使用 Prompt API 添加聊天机器人功能