Ngày phát hành: 13 tháng 1 năm 2024
Đây là phần thứ hai trong loạt bài gồm 3 phần về LLM và chatbot. Bài viết trước đã thảo luận về các ưu và khuyết điểm của LLM trên thiết bị và trong trình duyệt.
Giờ đây, khi đã hiểu rõ hơn về AI phía máy khách, bạn đã sẵn sàng thêm WebLLM vào ứng dụng web danh sách việc cần làm. Bạn có thể tìm thấy mã này trong nhánh web-llm
của kho lưu trữ GitHub.
WebLLM là một môi trường thời gian chạy dựa trên web cho LLM do Machine Learning Compilation cung cấp. Bạn có thể dùng thử WebLLM dưới dạng một ứng dụng độc lập. Ứng dụng này được lấy cảm hứng từ các ứng dụng trò chuyện dựa trên đám mây, chẳng hạn như Gemini, nhưng hoạt động suy luận LLM được chạy trên thiết bị của bạn thay vì trên đám mây. Lời nhắc và dữ liệu của bạn không bao giờ rời khỏi thiết bị của bạn và bạn có thể chắc chắn rằng chúng không được dùng để huấn luyện mô hình.
Để thực hiện suy luận mô hình trên thiết bị, WebLLM kết hợp WebAssembly và WebGPU. Mặc dù WebAssembly cho phép tính toán hiệu quả trên bộ xử lý trung tâm (CPU), nhưng WebGPU lại cấp cho nhà phát triển quyền truy cập cấp thấp vào bộ xử lý đồ hoạ (GPU) của thiết bị.
Cài đặt WebLLM
WebLLM có sẵn dưới dạng gói npm.
Bạn có thể thêm gói này vào ứng dụng danh sách việc cần làm bằng cách chạy npm install @mlc-ai/web-llm
.
Chọn một mô hình
Tiếp theo, bạn cần quyết định một LLM để thực thi cục bộ. Có nhiều mô hình.
Để quyết định, bạn nên nắm được các thuật ngữ và con số chính sau đây:
- Mã thông báo: Đơn vị văn bản nhỏ nhất mà LLM có thể xử lý.
- Cửa sổ ngữ cảnh: Số lượng mã thông báo tối đa mà mô hình có thể xử lý.
- Tham số hoặc trọng số: Các biến nội bộ được học trong quá trình huấn luyện, được tính bằng hàng tỷ.
- Định lượng: Số bit biểu thị trọng số. Càng nhiều bit thì độ chính xác càng cao, nhưng mức sử dụng bộ nhớ cũng càng cao.
- Định dạng số dấu phẩy động: Số dấu phẩy động 32 bit (độ chính xác đầy đủ, F32) cung cấp độ chính xác cao hơn, trong khi số dấu phẩy động 16 bit (độ bán chính xác, F16) có tốc độ cao hơn và sử dụng ít bộ nhớ hơn nhưng yêu cầu phần cứng tương thích.
Những từ khoá chính này thường là một phần của tên mô hình. Ví dụ: Llama-3.2-3B-Instruct-q4f32_1-MLC
chứa các thông tin sau:
- Mô hình là LLaMa 3.2.
- Mô hình này có 3 tỷ tham số.
- Loại này được điều chỉnh cho phù hợp với các trợ lý theo hướng dẫn và lời nhắc (Instruct).
- Phương thức này sử dụng quy tắc lượng tử hoá đồng nhất (_1) 4 bit (q4).
- Loại này có số dấu phẩy động 32 bit với độ chính xác đầy đủ.
- Đây là một phiên bản đặc biệt do tính năng Biên dịch máy học tạo ra.
Bạn có thể cần thử nghiệm nhiều mô hình để xác định mô hình nào phù hợp với trường hợp sử dụng của mình.
Một mô hình có 3 tỷ tham số và 4 bit cho mỗi tham số có thể có kích thước tệp lên tới 1, 4 GB tại thời điểm viết bài này.Ứng dụng cần tải tệp này xuống thiết bị của người dùng trước khi sử dụng lần đầu. Bạn có thể sử dụng các mô hình 3B, nhưng khi nói đến khả năng dịch hoặc kiến thức về kiến thức thú vị, các mô hình 7B sẽ mang lại kết quả tốt hơn. Tuy nhiên, với dung lượng từ 3,3 GB trở lên, các tệp này sẽ lớn hơn đáng kể.
Để tạo công cụ WebLLM và bắt đầu tải mô hình xuống cho chatbot danh sách việc cần làm, hãy thêm mã sau vào ứng dụng:
import {CreateMLCEngine} from '@mlc-ai/web-llm';
const engine = await CreateMLCEngine('Llama-3.2-3B-Instruct-q4f32_1-MLC', {
initProgressCallback: ({progress}) => console.log(progress);
});
Phương thức CreateMLCEngine
sẽ nhận chuỗi mô hình và một đối tượng cấu hình không bắt buộc. Khi sử dụng phương thức initProgressCallback
, bạn có thể truy vấn tiến trình tải xuống của mô hình để hiển thị cho người dùng trong khi họ chờ.
API bộ nhớ đệm: Giúp LLM chạy ngoại tuyến
Mô hình được tải xuống bộ nhớ đệm của trang web. Cache API được giới thiệu cùng với Trình chạy dịch vụ để giúp trang web hoặc ứng dụng web của bạn chạy khi không có mạng. Đây là cơ chế lưu trữ tốt nhất để lưu các mô hình AI vào bộ nhớ đệm. Ngược lại với việc lưu vào bộ nhớ đệm HTTP, Cache API là một bộ nhớ đệm có thể lập trình và hoàn toàn nằm trong quyền kiểm soát của nhà phát triển.
Sau khi tải xuống, WebLLM sẽ đọc các tệp mô hình từ API Bộ nhớ đệm thay vì yêu cầu các tệp đó qua mạng, giúp WebLLM có thể hoạt động hoàn toàn ngoại tuyến.
Giống như tất cả bộ nhớ trang web, bộ nhớ đệm được tách biệt theo nguồn gốc. Điều này có nghĩa là hai nguồn gốc example.com và example.net không thể chia sẻ cùng một bộ nhớ. Nếu hai trang web đó muốn sử dụng cùng một mô hình, thì chúng sẽ phải tải mô hình xuống riêng biệt.
Bạn có thể kiểm tra bộ nhớ đệm bằng DevTools bằng cách chuyển đến Application (Ứng dụng) > Storage (Bộ nhớ) rồi mở bộ nhớ đệm.
Thiết lập cuộc trò chuyện
Bạn có thể khởi tạo mô hình bằng một tập hợp câu lệnh nhắc ban đầu. Thông thường, có ba vai trò thông báo:
- Lời nhắc của hệ thống: Lời nhắc này xác định hành vi, vai trò và tính cách của mô hình. Bạn cũng có thể dùng phương pháp này để liên kết, tức là đưa dữ liệu tuỳ chỉnh vào mô hình không thuộc tập huấn luyện của mô hình (chẳng hạn như dữ liệu dành riêng cho miền của bạn). Bạn chỉ có thể chỉ định một lời nhắc hệ thống.
- Câu lệnh của người dùng: Câu lệnh do người dùng nhập.
- Lời nhắc của Trợ lý: Câu trả lời của Trợ lý, không bắt buộc.
Bạn có thể sử dụng lời nhắc của người dùng và trợ lý để nhắc N lần bằng cách cung cấp các ví dụ về ngôn ngữ tự nhiên cho LLM về cách ứng dụng này hoạt động hoặc phản hồi.
Dưới đây là ví dụ tối thiểu về cách thiết lập cuộc trò chuyện cho ứng dụng danh sách việc cần làm:
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?"}
];
Trả lời câu hỏi đầu tiên
Khả năng hoàn tất cuộc trò chuyện được hiển thị dưới dạng một thuộc tính trên công cụ WebLLM đã tạo trước đó (engine.chat.completions
). Sau khi tải mô hình xuống, bạn có thể chạy quy trình suy luận mô hình bằng cách gọi phương thức create()
trên thuộc tính này. Đối với trường hợp sử dụng của mình, bạn muốn truyền trực tuyến các phản hồi để người dùng có thể bắt đầu đọc trong khi phản hồi được tạo, giúp giảm thời gian chờ:
const chunks = await engine.chat.completions.create({ messages, stream: true, });
Phương thức này trả về một AsyncGenerator
, một lớp con của lớp AsyncIterator
bị ẩn. Sử dụng vòng lặp for await...of
để đợi các phần khi chúng đến. Tuy nhiên, phản hồi chỉ chứa các mã thông báo mới (delta
), vì vậy, bạn phải tự tập hợp toàn bộ phản hồi.
let reply = '';
for await (const chunk of chunks) {
reply += chunk.choices[0]?.delta.content ?? '';
console.log(reply);
}
Hóa ra web luôn phải xử lý các phản hồi truyền trực tuyến. Bạn có thể sử dụng các API như DOMImplementation để xử lý các phản hồi truyền trực tuyến này và cập nhật HTML một cách hiệu quả.
Kết quả hoàn toàn dựa trên chuỗi. Trước tiên, bạn phải phân tích cú pháp các tệp này nếu muốn diễn giải chúng dưới dạng JSON hoặc các định dạng tệp khác.
Tuy nhiên, WebLLM có một số hạn chế: Ứng dụng cần tải một mô hình rất lớn xuống trước khi sử dụng lần đầu tiên. Mô hình này không thể được chia sẻ trên các nguồn gốc, vì vậy, một ứng dụng web khác có thể phải tải lại cùng một mô hình. Mặc dù WebGPU đạt được hiệu suất suy luận gần như gốc, nhưng không đạt được tốc độ gốc đầy đủ.
Bản minh hoạ
Các hạn chế này được giải quyết bằng Prompt API, một API khám phá do Google đề xuất. API này cũng chạy phía máy khách, nhưng sử dụng một mô hình trung tâm được tải xuống Chrome. Điều này có nghĩa là nhiều ứng dụng có thể sử dụng cùng một mô hình ở tốc độ thực thi đầy đủ.
Hãy đọc thêm về cách thêm chức năng chatbot bằng Prompt API trong bài viết tiếp theo.