Data publikacji: 13 stycznia 2025 r.
To jest druga część z 3 częściowej serii dotyczącej LLM i czatbotów. W poprzednim artykule omawialiśmy zalety i wady LLM na urządzeniu oraz w przeglądarce.
Teraz, gdy lepiej rozumiesz AI po stronie klienta, możesz dodać WebLLM do aplikacji internetowej do zarządzania listą zadań. Kod znajdziesz na gałęzi web-llm
w repozytorium GitHub.
WebLLM to środowisko wykonawcze w internecie dla LLM udostępniane przez kompilację systemów uczących się. Możesz wypróbować WebLLM jako samodzielną aplikację. Aplikacja została zainspirowana aplikacjami do czatu opartymi na chmurze, takimi jak Gemini, ale wnioskowanie LLM jest wykonywane na urządzeniu, a nie w chmurze. Prompty i dane nigdy nie opuszczają Twojego urządzenia. Możesz mieć pewność, że nie są one używane do trenowania modeli.
Aby przeprowadzić wnioskowanie modelu na urządzeniu, WebLLM łączy WebAssembly i WebGPU. WebAssembly umożliwia wydajne wykonywanie obliczeń na procesorze centralnym (CPU), a WebGPU zapewnia deweloperom dostęp do niskiego poziomu procesora graficznego (GPU) urządzenia.
Instalowanie WebLLM
WebLLM jest dostępny jako pakiet npm.
Możesz dodać ten pakiet do aplikacji listy zadań, uruchamiając npm install @mlc-ai/web-llm
.
Wybierz model
Następnie musisz wybrać LLM do wykonania lokalnie. Dostępne są różne modele.
Aby podjąć decyzję, musisz znać te kluczowe terminy i liczby:
- Token: najmniejsza jednostka tekstu, jaką może przetworzyć model LLM.
- Okno kontekstu: maksymalna liczba tokenów, które model może przetworzyć.
- Parametry lub wagi: wewnętrzne zmienne wyuczone podczas trenowania, liczone w miliardach.
- Kwantyzacja: liczba bitów reprezentujących wagi. Więcej bitów oznacza większą dokładność, ale też większe wykorzystanie pamięci.
- Formaty liczb zmiennoprzecinkowych: 32-bitowe liczby zmiennoprzecinkowe (pełna precyzja, F32) zapewniają większą dokładność, a 16-bitowe liczby zmiennoprzecinkowe (półpełna precyzja, F16) mają większą szybkość i mniejszą konsumpcję pamięci, ale wymagają kompatybilnego sprzętu.
Te kluczowe terminy zwykle wchodzą w skład nazwy modelu. Na przykład:
Llama-3.2-3B-Instruct-q4f32_1-MLC
zawiera te informacje:
- Model to LLaMa 3.2.
- Model ma 3 mld parametrów.
- Jest ono dostosowane do asystentów, którzy udzielają instrukcji i zachęcają do działania (Instrukcja).
- Używa 4-bitowej (q4) jednolitej (_1) kwantyzacji.
- Zawiera 32-bitowe liczby zmiennoprzecinkowe o pełnej precyzji.
- Jest to specjalna wersja utworzona przez systemy uczące się.
Aby określić, który model jest odpowiedni do Twojego przypadku użycia, konieczne może być przetestowanie różnych modeli.
Model z 3 miliardami parametrów i 4 bitami na parametr może mieć rozmiar do 1, 4 GB w momencie pisania tego tekstu.Aplikacja musi pobrać go na urządzenie użytkownika przed pierwszym użyciem. Można korzystać z modeli 3B, ale jeśli chodzi o umiejętności związane z tłumaczeniem lub wiedzą na tematy ogólne, modele 7B dają lepsze wyniki. Jednak pliki o rozmiarze 3,3 GB i większym są znacznie większe.
Aby utworzyć mechanizm WebLLM i rozpocząć pobieranie modelu do chatbota do zadań, dodaj do aplikacji ten kod:
import {CreateMLCEngine} from '@mlc-ai/web-llm';
const engine = await CreateMLCEngine('Llama-3.2-3B-Instruct-q4f32_1-MLC', {
initProgressCallback: ({progress}) => console.log(progress);
});
Metoda CreateMLCEngine
przyjmuje ciąg znaków modelu i opcjonalny obiekt konfiguracji. Korzystając z metody initProgressCallback
, możesz wysłać zapytanie dotyczące postępu pobierania modelu, aby wyświetlić je użytkownikom podczas oczekiwania.
Cache API: uruchamianie LLM offline
Model jest pobierany do pamięci podręcznej witryny. Interfejs Cache API został wprowadzony wraz ze skryptami service worker, aby umożliwić działanie witryny lub aplikacji internetowej w trybie offline. Jest to najlepszy mechanizm przechowywania danych do buforowania modeli AI. W przeciwieństwie do buforowania HTTP interfejs Cache API to programowalna pamięć podręczna, nad którą deweloper ma pełną kontrolę.
Po pobraniu WebLLM odczytuje pliki modelu z Cache API zamiast wysyłać żądania przez sieć, dzięki czemu będzie w pełni obsługiwać tryb offline.
Podobnie jak w przypadku wszystkich innych danych witryny, pamięć podręczna jest odizolowana na podstawie źródła. Oznacza to, że 2 źródła, example.com i example.net, nie mogą korzystać z tego samego miejsca na dane. Jeśli te 2 witryny chciałyby używać tego samego modelu, musiałyby go osobno pobrać.
Możesz sprawdzać pamięć podręczną za pomocą DevTools, otwierając Aplikacja > Pamięć i otwierając pamięć podręczną.
Konfigurowanie rozmowy
Model można zainicjować za pomocą zestawu początkowych promptów. Zwykle występują 3 role wiadomości:
- Prompt systemowy: ten prompt określa zachowanie, rolę i postać modelu. Można go też używać do uziemienia, czyli podawania do modelu danych niestandardowych, które nie są częścią jego zbioru danych treningowych (np. danych dotyczących Twojej domeny). Możesz podać tylko 1 prompt systemowy.
- Prośba do użytkownika: prośby wprowadzane przez użytkownika.
- Prośba do Asystenta: opcjonalne odpowiedzi Asystenta.
Prompty użytkownika i asystenta można wykorzystać do promptów N-shot, podając modelowi LLM przykłady języka naturalnego, które pokazują, jak powinien się zachowywać lub odpowiadać.
Oto minimalny przykład konfiguracji konwersacji w aplikacji do zarządzania zadaniami:
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?"}
];
Odpowiedz na pierwsze pytanie
Funkcja uzupełniania czatu jest udostępniana jako właściwość w uprzednio utworzonym silniku WebLLM (engine.chat.completions
). Po pobraniu modelu możesz wykonać wnioskowanie modelu, wywołując metodę create()
w tej właściwości. W przypadku Twojego przypadku użycia chcesz przesyłać odpowiedzi strumieniowo, aby użytkownik mógł zacząć czytać, gdy tylko zostaną wygenerowane. Dzięki temu czas oczekiwania będzie wydawał się krótszy:
const chunks = await engine.chat.completions.create({ messages, stream: true, });
Ta metoda zwraca obiekt AsyncGenerator
, który jest podklasą ukrytej klasy AsyncIterator
. Użyj pętli for await...of
, aby czekać na kawałki w miarę ich pojawiania się. Odpowiedź zawiera jednak tylko nowe tokeny (delta
), więc musisz samodzielnie utworzyć pełną odpowiedź.
let reply = '';
for await (const chunk of chunks) {
reply += chunk.choices[0]?.delta.content ?? '';
console.log(reply);
}
Okazuje się, że internet zawsze musiał radzić sobie z odpowiedziami strumieniowymi. Możesz używać interfejsów API, takich jak DOMImplementation, do obsługi tych odpowiedzi strumieniowych i skutecznego aktualizowania kodu HTML.
Wyniki są całkowicie oparte na ciągach znaków. Jeśli chcesz interpretować je jako pliki JSON lub inne formaty plików, musisz je najpierw przeanalizować.
WebLLM ma jednak pewne ograniczenia: przed pierwszym użyciem aplikacja musi pobrać ogromny model, którego nie można udostępniać w różnych źródłach, więc inna aplikacja internetowa może ponownie pobrać ten sam model. Chociaż WebGPU osiąga wydajność wnioskowania zbliżoną do natywnej, nie osiąga pełnej natywnej szybkości.
Prezentacja
Te wady eliminuje interfejs Prompt API, który jest proponowanym przez Google interfejsem API do eksploracji. Działa on również po stronie klienta, ale korzysta z centralnego modelu pobranego do Chrome. Oznacza to, że wiele aplikacji może korzystać z tego samego modelu z pełną prędkością.
Więcej informacji o dodawaniu funkcji chatbota za pomocą interfejsu Prompt API znajdziesz w następnym artykule.