O começo
Há alguns meses, enquanto trabalhava no workshop Databricks with R, me deparei com algumas de suas funções SQL personalizadas. Essas funções específicas são prefixadas com “ai_” e executam PNL com uma simples chamada SQL:
> SELECT ai_analyze_sentiment('I'm completely happy');
constructive
> SELECT ai_analyze_sentiment('I'm unhappy');
detrimental
Isso foi uma revelação para mim. Ele apresentou uma nova maneira de usar LLMs em nosso trabalho diário como analistas. Até o momento, eu havia empregado LLMs principalmente para conclusão de código e tarefas de desenvolvimento. No entanto, esta nova abordagem se concentra no uso de LLMs diretamente em nossos dados.
Minha primeira reação foi tentar acessar as funções personalizadas through R. Com
dbplyr
podemos acessar funções SQL em R, e foi ótimo vê-las funcionar:
|>
orders mutate(
sentiment = ai_analyze_sentiment(o_comment)
)#> # Supply: SQL (6 x 2)
#> o_comment sentiment
#>
#> 1 ", pending theodolites … impartial
#> 2 "uriously particular foxes … impartial
#> 3 "sleep. courts after the … impartial
#> 4 "ess foxes might sleep … impartial
#> 5 "ts wake blithely uncommon … combined
#> 6 "hins sleep. fluffily … impartial
Uma desvantagem dessa integração é que, embora acessível por meio de R, precisamos de uma conexão ativa com o Databricks para utilizar um LLM dessa maneira, limitando assim o número de pessoas que podem se beneficiar dele.
De acordo com a documentação, o Databricks está aproveitando o modelo Llama 3.1 70B. Embora este seja um modelo de linguagem grande altamente eficaz, seu enorme tamanho representa um desafio significativo para a maioria das máquinas dos usuários, tornando impraticável sua execução em {hardware} padrão.
Alcançando a viabilidade
O desenvolvimento do LLM tem acelerado em ritmo acelerado. Inicialmente, apenas Giant Language Fashions (LLMs) on-line eram viáveis para uso diário. Isto suscitou preocupações entre as empresas hesitantes em partilhar os seus dados externamente. Além disso, o custo do uso de LLMs on-line pode ser substancial e as cobranças por token podem aumentar rapidamente.
A solução superb seria integrar um LLM nos nossos próprios sistemas, exigindo três componentes essenciais:
- Um modelo que cabe confortavelmente na memória
- Um modelo que atinge precisão suficiente para tarefas de PNL
- Uma interface intuitiva entre o modelo e o laptop computer do usuário
No ano passado, ter todos esses três elementos period quase impossível. Os modelos capazes de caber na memória eram imprecisos ou excessivamente lentos. No entanto, avanços recentes, como Lhama de Meta
e mecanismos de interação entre plataformas, como Ollamaviabilizaram a implantação desses modelos, oferecendo uma solução promissora para empresas que buscam integrar LLMs em seus fluxos de trabalho.
O projeto
Este projeto começou como uma exploração, impulsionado pelo meu interesse em aproveitar um LLM de “uso geral” para produzir resultados comparáveis aos das funções de IA do Databricks. O principal desafio foi determinar quanta configuração e preparação seriam necessárias para que tal modelo fornecesse resultados confiáveis e consistentes.
Sem acesso a um documento de design ou código-fonte aberto, confiei apenas nos resultados do LLM como campo de testes. Isto apresentou vários obstáculos, incluindo as inúmeras opções disponíveis para o ajuste fino do modelo. Mesmo dentro da engenharia imediata, as possibilidades são vastas. Para garantir que o modelo não fosse muito especializado ou focado em um assunto ou resultado específico, precisei encontrar um equilíbrio delicado entre precisão e generalidade.
Felizmente, depois de realizar testes extensivos, descobri que um simples immediate “one-shot” produzia os melhores resultados. Por “melhor”, quero dizer que as respostas foram precisas para uma determinada linha e consistentes em várias linhas. A consistência period essential, pois significava fornecer respostas que fossem uma das opções especificadas (positiva, negativa ou neutra), sem quaisquer explicações adicionais.
A seguir está um exemplo de immediate que funcionou de maneira confiável no Llama 3.2:
>>> You're a useful sentiment engine. Return solely one of many
... following solutions: constructive, detrimental, impartial. No capitalization.
... No explanations. The reply is predicated on the next textual content:
... I'm completely happy
constructive
Como observação lateral, minhas tentativas de enviar várias linhas de uma vez não tiveram sucesso. Na verdade, passei muito tempo explorando diferentes abordagens, como enviar 10 ou 2 linhas simultaneamente, formatando-as nos formatos JSON ou CSV. Os resultados eram muitas vezes inconsistentes e não pareciam acelerar o processo o suficiente para valer a pena o esforço.
Depois que me senti confortável com a abordagem, a próxima etapa foi agrupar a funcionalidade em um pacote R.
A abordagem
Um dos meus objetivos period tornar o pacote do buying o mais “ergonômico” possível. Em outras palavras, eu queria garantir que o uso do pacote em R e Python se integrasse perfeitamente à forma como os analistas de dados usam sua linguagem preferida diariamente.
Para R, isso foi relativamente simples. Eu simplesmente precisava verificar se as funções funcionavam bem com pipes (%>%
e |>
) e poderia ser facilmente incorporado em pacotes como os do tidyverse
:
|>
opinions llm_sentiment(assessment) |>
filter(.sentiment == "constructive") |>
choose(assessment)
#> assessment
#> 1 This has been the perfect TV I've ever used. Nice display, and sound.
Porém, para Python, por ser uma linguagem não nativa para mim, significou que tive que adaptar meu pensamento sobre manipulação de dados. Especificamente, aprendi que em Python, objetos (como DataFrames do pandas) “contêm” funções de transformação por design.
Esse perception me levou a investigar se a API Pandas permite extensões e, felizmente, permitiu! Depois de explorar as possibilidades, decidi começar com o Polar, o que me permitiu estender sua API criando um novo namespace. Esta simples adição permitiu aos usuários acessar facilmente as funções necessárias:
>>> import polars as pl
>>> import mall
>>> df = pl.DataFrame(dict(x = ("I'm completely happy", "I'm unhappy")))
>>> df.llm.sentiment("x")
2, 2)
form: (
┌────────────┬───────────┐
│ x ┆ sentiment │--- ┆ --- │
│ str ┆ str │
│
╞════════════╪═══════════╡
│ I'm completely happy ┆ constructive │
│ I'm unhappy ┆ detrimental │ └────────────┴───────────┘
Ao manter todas as novas funções dentro do namespace llm, fica muito fácil para os usuários encontrar e utilizar aquelas de que precisam:
O que vem a seguir
Acho que será mais fácil saber o que está por vir mall
uma vez que a comunidade o use e forneça suggestions. Prevejo que adicionar mais back-ends LLM será a solicitação principal. A outra melhoria possível será quando novos modelos atualizados estiverem disponíveis e os prompts poderão precisar ser atualizados para esse modelo específico. Eu experimentei isso indo do Llama 3.1 para o Llama 3.2. Houve necessidade de ajustar um dos prompts. O pacote está estruturado de forma que ajustes futuros como esse serão acréscimos ao pacote, e não substituições aos prompts, de modo a manter a compatibilidade com versões anteriores.
É a primeira vez que escrevo um artigo sobre a história e estrutura de um projeto. Esse esforço específico foi tão único por causa do R + Python e de seus aspectos de LLM, que achei que valeria a pena compartilhar.
Se você deseja saber mais sobre mall
fique à vontade para visitar seu website oficial:
https://mlverse.github.io/mall/