RAG: Adicione Contexto nas Respostas do seu LLM
RAG combina técnicas de recuperação de informações com geração de texto como forma de produzir respostas mais precisas
Me siga no X | Me siga no LinkedIn | Apoie a Newsletter | Solicite uma consultoria
Você já reparou que muitas respostas fornecidas por ferramentas como ChatGPT, embora corretas, são pouco úteis?
Embora os LLMs sejam treinados em um grande conjunto de dados que abrange uma ampla variedade de tópicos, estes LLMs não possuem conhecimento especializado, por exemplo, do negócio da sua empresa, pois não foram treinados com esses dados.
Dessa forma, devido à sua natureza generalista, os LLMs podem fornecer respostas que, embora pareçam razoáveis à primeira vista, podem ser simplificadas demais quando se trata de temas mais especializados.
Imagine, por exemplo, que queremos construir um chatbot que informe sobre o andamento de processos de um tribunal municipal, onde fornecer informações específicas é crucial. Uma vez que os LLMs desconhecem essas informações, estes podem gerar respostas que parecem plausíveis, mas podem conter informações incorretas ou desatualizadas.
Essa limitação se torna um desafio em situações em que a precisão e a confiabilidade das informações são essenciais, como em pesquisas acadêmicas, consultas médicas ou questões legais.
Para minimizar essas limitações, alguns trabalhos recentes tem adotado técnicas de recuperação de informações com geração de texto, como forma de produzir respostas mais precisas e contextualmente relevantes em agentes conversacionais.
Retrieval-Augmented Generation (RAG) é uma abordagem que tem ganhado notoriedade tanto como área de pesquisa, quanto na construção de sistemas conversacionais mais contextualizados. Nesse texto, vamos entender como melhor como o RAG funciona.
📚 Você é dev e quer aprender um pouco mais sobre a criação de aplicações baseadas em LLM?
Eu criei um curso que aborda aspectos teóricos e práticos do desenvolvimento de aplicações baseadas em LLMs. Alguns dos tópicos cobertos:
🟠 O que são e como criar embeddings
🟡 Como selecionar partes relevantes nos seus documentos
🔵 Como integrar essas partes documentos com uma LLM
Qual o problema dos LLMs?
LLMs de propósito geral podem ser ajustados para realizar várias tarefas comuns, como análise de sentimento e reconhecimento de entidades nomeadas. Geralmente, essas tarefas não requerem conhecimento adicional de contexto.
No entanto, quando se faz necessário conhecimento adicional, estes LLMs apresentam duas importantes desvantagens:
Eles são estáticos: LLMs estão “congelados no tempo” e não possuem informações atualizadas.
Eles carecem de conhecimento específico de domínio: LLMs são treinados com dados públicos, o que significa que eles não possuem conhecimento sobre dados privados da sua empresa.
Infelizmente, esses problemas afetam a precisão das aplicações que utilizam LLMs. Para qualquer aplicação empresarial com requisitos mais exigentes, LLMs utilizados sem modificações tendem a ter um desempenho fraco em tarefas dependentes do contexto.
Para tarefas mais complexas e intensivas em conhecimento, é possível construir um sistema baseado em LLMs que acessa fontes de conhecimento externas para completar as tarefas. Isso permite uma maior consistência factual, melhora a confiabilidade das respostas geradas e ajuda a mitigar o problema da “alucinação”.
Pesquisadores de Meta AI introduziram um método chamado Retrieval Augmentation Generation (RAG) para lidar com tarefas intensivas em conhecimento desse tipo.
Retrieval Augmentation Generation
O Retrieval Augmentation Generation (RAG) é um sistema que amplia as capacidades de um LLM, como o ChatGPT, adicionando um sistema de recuperação de informações que fornece os dados que podem ser utilizados pelo LLM para formular uma resposta mais contextualizada.
O RAG combina um componente de recuperação de informações com um LLM gerador de texto. Como o RAG busca informações em bases locais de conhecimento, não há a necessidade de re-treinar o modelo inteiro e atualizar os parâmetros a medida que novos dados são fornecidos. Dessa forma, o RAG tende a diminuir os custos financeiros e computacionais de se rodar uma LLM. Por exemplo, OpenAI’s Sam Altman estimated it cost around $100 million to train the foundation model behind ChatGPT.
Por fim, o RAG não apenas aprimora a precisão das respostas geradas, mas também permite uma resposta mais adaptada e contextualmente relevante para perguntas complexas e específicas.
Como implementar um RAG?
Para implementar um RAG, precisamos quebra-lo em dois principais componentes: o componente de retrieval e o componente generativo.
Componente de retrieval: Este componente é desenhado para buscar informações relevantes de um determinado conjunto de base de dados. Estes componentes tipicamente utilizam de técnicas de recuperação de informação ou busca semântica para identificar os dados mais relevantes para uma determinada consulta. Estes componentes são eficientes em buscar informação relevante, porém não são capazes de gerar novo conteúdo.
Componente generativo: Os componentes generativos, por sua vez, são desenhados para gerar novo conteúdo com base em um determinado prompt. LLMs como ChatGPT são excelentes para esse tipo de tarefa.
Componente de retrieval
Há pelo menos dois exemplos populares de componentes de retrieval:
Embeddings: Embeddings são redes neurais que ranqueiam documentos com base nas suas similaridades em um espaço vetorial.
TF-IDF: O TF-IDF (Term Frequency — Inverse Document Frequency) é um modelo clássico de recuperação de informação. O TD-IDF avalia a importância de um determinado termo dentro de um documento em comparação a todo o corpo de documentos. Para ranquear a relevância de um documento, o algoritmo combina a frequência do termo (o quão frequente o termo aparece em um documento) e a frequência inversa do documento (o quão raro é o term no corpo de documento).
Embora o TF-IDF comumente empregado tanto em trabalhos científicos como em soluções industriais, o RAG é mais frequentemente implementado utilizando mecanismos de buscas semânticas, usando embeddings. Uma busca semântica tenta não somente realizar buscas com bases em palavras exatas, mas principalmente identificar o significado verdadeiro de uma query de usuário.
Como já abordado em outros textos, embeddings é um modelo que converte dados em vetores numéricos. É possível converter documentos, audios, videos, etc, em vetores numéricos. Há diversas soluções robustas para criação de embeddings. Por exemplo, a OpenAI tem um endpoint que pode ser utilizado para criação de vetores numéricos de alta qualidade, por um preço extremamente competitivo.
Para que essa representação numérica seja consultada e recuperada pelo componente de retrieval, é comum que esta esteja armazenada em uma base de dados especializada. Estas bases de dados especializadas podem ser encaradas como banco de dados com sistema de tipos ligeiramente mais sofisticado, capaz de armazenar vetores numéricos. O Postgres, por exemplo, tem uma extensão chamada pgvector, que realiza essa implementação.
Como os vetores tendem a ser armazenados em banco de dados, podemos, por exemplo, criar um index em uma tabela de forma a otimizar consultas ao banco de dados.
Componente generativo
No momento, o principal componente generativo ainda são os modelos disponibilizados pela OpenAI (como o GPT-3.5 ou o GPT-4). No entanto, há outros modelos como o Lhama que podem ser úteis, principalmente por serem open-source e não haver custo de utilização; embora exista um custo para deploy e disponibilização do modelo.
Fluxo de dados
Uma vez configurado esses dois componentes, a aplicação que utiliza RAG deve ser arquitetada da seguinte forma.
Os documentos proprietários deve ser convertidos utilizado um modelo de embeddings.
Os embeddings dos documentos proprietários devem ser armazenados em uma base de dados com suporte a tipos vetoriais, como o Postgres e sua extensão pgvector. É interessante guardar os dados vetoriais em uma coluna e também guardar o conteúdo em linguagem natural em outra coluna, na mesma tabela (veja o item 5 abaixo).
Quando um usuário faz uma consulta ao sistema, esta consulta em linguagem natural também deve ser convertida em um vetor numérico.
A consulta do usuário, em formato de embedding, deve ser também enviada ao banco de dados.
O banco de dados deve realizar uma consulta (usando um comando SELECT) que seja capaz de buscar os dados mais próximos da consulta fornecida pelo usuário. Note que aqui estamos usando um comando SELECT para comparar dois vetores numéricos. Embora o SELECT compare com base na coluna que armazena vetor numérico, o SELECT deve retornar a coluna que armazena o texto em linguagem natural; algo como:
SELECT content FROM embeddings ORDER BY embedding <=> %query LIMIT 3
Nesse comando SELECT, a tabela embedding tem duas colunas:
content
eembedding
. A comparação da consulta do usuário%query
é feita com a colunaembedding
usando o operador<=>
(implementado no pgvector). O valor armazenado na colunacontent
é retornada após a consulta. Limitamos a 3 resultados como forma de minimizar a recuperação de conteúdo irrelevante.Quando o banco de dados retornar os dados armazenados que estejam relacionados a consulta do usuário, estes dados devem ser utilizados para enriquecer o prompt. Um exemplo de prompt enriquecido é exemplificado a seguir:
Querido ChatGPT: Gostaria que você agisse como uma pessoa especialista em Design de Código. Avalie a pergunta do usuário (em <U>) e as potenciais respostas (em <R>). <U> “Quais os benefícios do CDD?” <R> “Um dos benefícios observados com a pesquisa foi que CDD ajudou …" <R> “Um dos participantes reportou que a vantagem em usar CDD foi que …” <R> “Os benefícios pareciam ser pequenos para equipes com baixa maturidade em outras técnicas de design, além de CDD” Crie uma narrativa de até 100 palavras.
O prompt enriquecido deve ser enviado ao seu LLM, que por sua vez realizará uma consulta mais contextualizada.
Conclusão
RAG é uma abordagem que tende a enriquecer LLMs com informações contextualizadas, de forma a tornar suas respostas menos genéricas, mais precisas e com menos chances de alucinação.
Para implementar um RAG, é preciso construir dois componentes: o componente de retrieval e o componente generativo. A escolha do componente generativo é simples de ser tomada, uma vez que a OpenAI ainda reina absoluta neste domínio. Da mesma forma, embora existam opções relevantes de componente de retrieval, o modelo de embedding também fornecido pela OpenAI tende a ser uma das soluções mais comumente empregadas.
Através da integração desses dois componentes, é possível criar agentes conversacionais capazes de interagir com dados que não foram treinados — e assim melhorar a qualidade das respostas e a interação com os usuários.