发布时间:2025 年 1 月 13 日
这是关于 LLM 和聊天机器人的三部分系列文章的第二篇。上一篇文章讨论了设备端和浏览器端 LLM 的优点和缺点。
既然您对客户端 AI 有了更好的了解,那么您就可以将 WebLLM 添加到待办事项列表 Web 应用程序中了。您可以在 web-llm
branch of the GitHub repository 中找到代码。
WebLLM 是 Machine Learning Compilation 提供的基于 Web 的 LLM 运行时。您可以试用作为独立应用程序的 WebLLM。该应用程序的灵感来自云支持的聊天应用程序,例如 Gemini,但 LLM 推理是在您的设备而不是云端运行的。您的提示和数据永远不会离开您的设备,您可以确信它们不会被用于训练模型。
为了在设备上执行模型推理,WebLLM 结合了 WebAssembly 和 WebGPU。虽然 WebAssembly 允许在中央处理器 (CPU) 上进行高效计算,但 WebGPU 使开发人员能够低级别地访问设备的图形处理器 (GPU)。
安装 WebLLM
WebLLM 以 npm 包 的形式提供。您可以通过运行 npm install @mlc-ai/web-llm
将此包添加到您的待办事项列表应用程序中。
选择模型
接下来,您需要决定在本地执行哪个 LLM。有多种模型可供选择。
为了做出决定,您应该了解以下关键术语和数字
- Token(令牌): LLM 可以处理的最小文本单位。
- Context window(上下文窗口): 模型可以处理的最大令牌数量。
- Parameters or weights(参数或权重): 训练期间学习的内部变量,以数十亿计。
- Quantization(量化): 表示权重的位数。位数越多,精度越高,但内存使用量也越高。
- Floating-point number formats(浮点数格式): 32 位浮点数(全精度,F32)提供更好的精度,而 16 位浮点数(半精度,F16)具有更高的速度和更低的内存使用量,但需要兼容的硬件。
这些关键术语往往是模型名称的一部分。例如,Llama-3.2-3B-Instruct-q4f32_1-MLC
包含以下信息
- 该模型是 LLaMa 3.2。
- 该模型有 30 亿个参数。
- 它针对指令和提示式助手进行了微调 (Instruct)。
- 它使用 4 位 (q4) 均匀 (_1) 量化。
- 它具有全精度 32 位浮点数。
- 它是 Machine Learning Compilation 创建的特殊版本。
您可能需要测试不同的模型以确定哪个模型适合您的用例。
一个具有 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 Workers 一起引入的,旨在使您的网站或 Web 应用程序离线运行。它是缓存 AI 模型的最佳存储机制。与 HTTP 缓存相比,Cache API 是一种可编程缓存,完全在开发人员的控制之下。
下载完成后,WebLLM 从 Cache API 读取模型文件,而不是通过网络请求它们,这使得 WebLLM 完全具备离线功能。
与所有网站存储一样,缓存按来源隔离。这意味着两个来源,example.com 和 example.net,不能共享相同的存储。如果这两个网站想要使用相同的模型,则必须分别下载该模型。
您可以使用 DevTools 检查缓存,方法是导航至 Application(应用程序) > Storage(存储) 并打开 Cache storage(缓存存储)。
设置对话
可以使用一组初始提示来初始化模型。通常,有三种消息角色
- System prompt(系统提示): 此提示定义模型的行为、角色和性格。它也可以用于 grounding(接地),即将自定义数据(即您的特定领域数据)馈送到模型中,而这些数据不属于其训练集的一部分。您只能指定一个系统提示。
- User prompt(用户提示): 用户输入的提示。
- Assistant prompt(助手提示): 来自助手的答案,可选。
用户和助手提示可以用于 N-shot prompting(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);
}
事实证明,Web 一直需要处理流式响应。您可以使用 DOMImplementation 等 API 来处理这些流式响应并高效地更新您的 HTML。
结果纯粹是基于字符串的。如果您想将它们解释为 JSON 或其他文件格式,则必须首先对其进行解析。
然而,WebLLM 也有一些限制:应用程序需要在首次使用前下载一个庞大的模型,该模型不能在来源之间共享,因此另一个 Web 应用程序可能不得不再次下载相同的模型。虽然 WebGPU 实现了接近原生的推理性能,但它并没有达到完整的原生速度。
演示
Prompt API 解决了这些缺点,Prompt API 是 Google 提出的一个探索性 API,它也在客户端运行,但使用下载到 Chrome 中的中央模型。这意味着多个应用程序可以以全速执行速度使用同一个模型。
在下一篇文章中阅读更多关于使用 Prompt API 添加聊天机器人功能的信息。