Crie um chatbot local e off-line com o WebLLM

Publicado em 13 de janeiro de 2024

Esta é a segunda parte de uma série de três partes sobre LLMs e chatbots. O artigo anterior discutiu os benefícios e as desvantagens dos LLMs no dispositivo e no navegador.

Agora que você entende melhor a IA do lado do cliente, está tudo pronto para adicionar a WebLLM a um aplicativo da Web de lista de tarefas. Encontre o código na filial web-llm do repositório do GitHub.

O WebLLM é um ambiente de execução baseado na Web para LLMs fornecidos pela compilação de aprendizado de máquina. Você pode testar o WebLLM como um aplicativo independente. O app é inspirado em apps de chat com suporte em nuvem, como o Gemini, mas a inferência de LLM é executada no dispositivo em vez da nuvem. Seus comandos e dados nunca saem do dispositivo, e você pode ter certeza de que eles não são usados para treinar modelos.

Para realizar a inferência de modelo no dispositivo, o WebLLM combina WebAssembly e WebGPU. Enquanto o WebAssembly permite cálculos eficientes na unidade de processamento central (CPU), o WebGPU oferece aos desenvolvedores acesso de baixo nível à unidade de processamento gráfico (GPU) do dispositivo.

Browser Support

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

Source

Instalar o WebLLM

O WebLLM está disponível como um pacote npm. Para adicionar esse pacote ao seu aplicativo de lista de tarefas, execute npm install @mlc-ai/web-llm.

Selecione um modelo

Em seguida, você precisa decidir qual LLM será executado localmente. Vários modelos estão disponíveis.

Para decidir, você precisa conhecer os seguintes termos e números importantes:

  • Token:a menor unidade de texto que um LLM pode processar.
  • Janela de contexto:o número máximo de tokens que o modelo pode processar.
  • Parâmetros ou pesos:as variáveis internas aprendidas durante o treinamento, contadas em bilhões.
  • Quantização:o número de bits que representam os pesos. Mais bits significam maior precisão, mas também maior uso de memória.
  • Formatos de número de ponto flutuante:números de ponto flutuante de 32 bits (precisão total, F32) oferecem maior precisão, enquanto números de ponto flutuante de 16 bits (meia precisão, F16) têm velocidades mais altas e menos uso de memória, mas exigem hardware compatível.

Esses termos-chave tendem a fazer parte do nome do modelo. Por exemplo, Llama-3.2-3B-Instruct-q4f32_1-MLC contém as seguintes informações:

  • O modelo é o LLaMa 3.2.
  • O modelo tem 3 bilhões de parâmetros.
  • Ele é ajustado para assistentes de instrução e de comando (Instruct).
  • Ele usa quantização uniforme (_1) de 4 bits (q4).
  • Ele tem números de ponto flutuante de 32 bits e precisão total.
  • É uma versão especial criada pela compilação de aprendizado de máquina.

Talvez seja necessário testar modelos diferentes para determinar qual deles se adapta ao seu caso de uso.

Um modelo com 3 bilhões de parâmetros e 4 bits por parâmetro já pode ter um tamanho de arquivo de até 1,4 GB no momento em que este artigo foi escrito, que o aplicativo precisa fazer o download no dispositivo do usuário antes do primeiro uso. É possível trabalhar com modelos 3B, mas, quando se trata de recursos de tradução ou conhecimento de curiosidades, os modelos 7B oferecem resultados melhores. Com 3, 3 GB ou mais, eles são significativamente maiores.

Para criar o mecanismo do WebLLM e iniciar o download do modelo para seu chatbot de lista de tarefas, adicione o seguinte código ao seu aplicativo:

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

O método CreateMLCEngine usa a string de modelo e um objeto de configuração opcional. Usando o método initProgressCallback, é possível consultar o progresso do download do modelo para apresentá-lo aos usuários enquanto eles esperam.

API Cache: faça com que o LLM seja executado off-line

O modelo é transferido para o armazenamento em cache do seu site. A API Cache foi introduzida com os Service Workers para que seu site ou aplicativo da Web seja executado off-line. É o melhor mecanismo de armazenamento para armazenar modelos de IA em cache. Ao contrário do armazenamento em cache HTTP, a API Cache é um cache programável que está totalmente sob o controle do desenvolvedor.

Após o download, o WebLLM lê os arquivos do modelo da API Cache em vez de solicitar por meio da rede, tornando o WebLLM totalmente compatível com o modo off-line.

Como em todo armazenamento de sites, o cache é isolado por origem. Isso significa que duas origens, example.com e example.net, não podem compartilhar o mesmo armazenamento. Se esses dois sites quisessem usar o mesmo modelo, eles precisariam fazer o download do modelo separadamente.

É possível inspecionar o cache usando o DevTools abrindo Application > Storage e acessando o armazenamento de cache.

Configurar a conversa

O modelo pode ser inicializado com um conjunto de comandos iniciais. Geralmente, há três papéis de mensagem:

  • Comando do sistema: define o comportamento, o papel e o personagem do modelo. Ele também pode ser usado para aterramento, ou seja, para alimentar dados personalizados no modelo que não fazem parte do conjunto de treinamento (como dados específicos do domínio). Só é possível especificar uma solicitação do sistema.
  • Comando do usuário: comandos inseridos pelo usuário.
  • Comando do Google Assistente: respostas do Assistente, opcionais.

Os comandos do usuário e do assistente podem ser usados para comandos N-shot, fornecendo exemplos de linguagem natural ao LLM sobre como ele deve se comportar ou responder.

Confira um exemplo mínimo de configuração da conversa para o app de lista de tarefas:

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?"}
];

Responda à primeira pergunta

O recurso de conclusão de chat é exposto como uma propriedade no mecanismo do WebLLM criado anteriormente (engine.chat.completions). Depois que o modelo é transferido por download, é possível executar a inferência de modelo chamando o método create() nessa propriedade. Para o caso de uso, você quer transmitir as respostas para que o usuário possa começar a ler enquanto elas são geradas, reduzindo o tempo de espera percebido:

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

Esse método retorna um AsyncGenerator, uma subclasse da classe AsyncIterator oculta. Use um loop for await...of para aguardar os blocos conforme eles chegam. No entanto, a resposta contém apenas os novos tokens (delta), então você precisa montar a resposta completa.

let reply = '';

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

Acontece que a Web sempre teve que lidar com respostas de streaming. É possível usar APIs como a DOMImplementation para trabalhar com essas respostas de streaming e atualizar o HTML de maneira eficiente.

Os resultados são puramente baseados em strings. Você precisa analisar os dados primeiro se quiser interpretá-los como JSON ou outros formatos de arquivo.

No entanto, o WebLLM tem algumas restrições: o aplicativo precisa fazer o download de um modelo enorme antes do primeiro uso, que não pode ser compartilhado entre origens. Portanto, outro app da Web pode precisar fazer o download do mesmo modelo novamente. Embora a WebGPU alcance um desempenho de inferência quase nativo, ela não atinge a velocidade nativa total.

Demonstração

Essas desvantagens são abordadas pela API Prompt, uma API exploratória proposta pelo Google que também é executada no lado do cliente, mas usa um modelo central transferido para o Chrome. Isso significa que vários aplicativos podem usar o mesmo modelo na velocidade de execução total.

Leia mais sobre como adicionar recursos de chatbot usando a API Prompt no próximo artigo.