A geração aumentada por recuperação (RAG) é a abordagem mais popular para obter dados em tempo real ou dados atualizados de uma fonte de dados com base na entrada de texto pelos usuários. Assim, capacitando todas as nossas aplicações de busca com pesquisa neural de ponta.
Nos sistemas de busca RAG, cada solicitação do usuário é convertida em uma representação vetorial por meio do modelo de incorporação, e essa comparação de vetores é realizada usando vários algoritmos como similaridade de cosseno, subsequência comum mais longa, etc., com as representações de vetor existentes armazenadas em nosso banco de dados de suporte a vetor.
Os vetores existentes armazenados no banco de dados de vetor também são gerados ou atualizados de forma assíncrona por um processo de plano de fundo separado.
Este diagrama fornece uma visão conceitual da comparação de vetores
Para usar o RAG, precisamos de pelo menos um modelo de incorporação e de um banco de dados de armazenamento de vetores a serem usados pela aplicação. Contribuições da comunidade e de projetos de código aberto nos fornecem um conjunto incrível de ferramentas que nos ajudam a construir aplicações de RAG eficazes e eficientes aplicações de RAG.
Neste artigo, implementaremos o uso de um banco de dados de vetor e um modelo de geração de embedding em uma aplicação Python. Se você está lendo esse conceito pela primeira vez ou pela enésima vez, você só precisa das ferramentas para trabalhar, e não é necessário inscrição para nenhuma ferramenta. Você pode simplesmente baixar as ferramentas e começar.
Nossa pilha tecnológica é composta pelas seguintes ferramentas de código aberto e gratuitas:
- Sistema operacional – Ubuntu Linux
- Banco de dados de vetor – Apache Cassandra
- Modelo de embedding – nomic-embed-text
- Linguagem de programação – Python
Principais benefícios desta pilha
- Código aberto
- Dados isolados para atender aos padrões de conformidade de dados
Passo a passo da implementação
Você pode implementar e seguir os passos se os pré-requisitos forem atendidos; caso contrário, leia até o final para entender os conceitos.
Pré-requisitos
- Linux (No meu caso, é Ubuntu 24.04.1 LTS)
- Configuração do Java (OpenJDK 17.0.2)
- Python (3.11.11)
- Ollama
Configuração do Modelo Ollama
Ollama é um servidor middleware de código aberto que atua como uma abstração entre a IA generativa e aplicativos, instalando todas as ferramentas necessárias para disponibilizar modelos de IA generativa para consumo como CLI e API em uma máquina. Ele possui a maioria dos modelos disponíveis abertamente, como llama, phi, mistral, snowflake-arctic-embed, etc. É multiplataforma e pode ser facilmente configurado em sistemas operacionais.
No Ollama, vamos buscar o modelo nomic-embed-text para gerar embeddings.
Execute na linha de comando:
ollama pull nomic-embed-text
Este modelo gera embeddings de vetores de tamanho 768.
Configuração e Scripts do Apache Cassandra
O Cassandra é um banco de dados NoSQL de código aberto projetado para trabalhar com uma grande quantidade de cargas de trabalho que requerem alta escalabilidade de acordo com as necessidades da indústria. Recentemente, adicionou suporte para busca vetorial na versão 5.0 que facilitará nosso caso de uso do RAG.
Observação: O Cassandra requer um sistema operacional Linux para funcionar; também pode ser instalado como uma imagem docker.
Instalação
Baixe o Apache Cassandra em https://cassandra.apache.org/_/download.html.
Configure o Cassandra em seu PATH.
Inicie o servidor executando o seguinte comando na linha de comando:
cassandra
Tabela
Abra um novo terminal Linux e escreva cqlsh
; isso abrirá o shell para a Linguagem de Consulta do Cassandra. Agora, execute os scripts abaixo para criar o espaço de chaves embeddings
, a tabela document_vectors
e o índice necessário edv_ann_index
para realizar uma busca vetorial.
CREATE KEYSPACE IF NOT EXISTS embeddings
WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : '1' };
USE embeddings;
CREATE TABLE IF NOT EXISTS embeddings.document_vectors (
record_id timeuuid,
id uuid,
content_chunk text,
content_vector VECTOR <FLOAT, 768>,
created_at timestamp,
PRIMARY KEY (id, created_at)
)
WITH CLUSTERING ORDER BY (created_at DESC);
CREATE INDEX IF NOT EXISTS edv_ann_index
ON embeddings.document_vectors(content_vector) USING 'sai';
Nota: content_vector VECTOR <FLOAT, 768>
é responsável por armazenar vetores de comprimento 768 gerados pelo modelo.
Etapa 1: Estamos prontos com a configuração do banco de dados para armazenar vetores.
Código Python
Esta linguagem de programação certamente não precisa de introdução; é fácil de usar e amada pela indústria com forte suporte da comunidade.
Ambiente Virtual
Configurar ambiente virtual:
sudo apt install python3-virtualenv && python3 -m venv myvenv
Ativar ambiente virtual:
source /media/setia/Data/Tutorials/cassandra-ollama-app/myvenv/bin/activate
Pacotes
Baixar o pacote Datastax Cassandra:
pip install cassandra-driver
Baixar o pacote requests:
pip install requests
Arquivo
Criar um arquivo chamado app.py
.
Agora, escreva o código abaixo para inserir documentos de amostra no Cassandra. Este é sempre o primeiro passo para inserir dados no banco de dados; pode ser feito por um processo separado de forma assíncrona. Para fins de demonstração, escrevi um método que irá inserir os documentos primeiro no banco de dados. Mais tarde, podemos comentar este método uma vez que a inserção de documentos for bem-sucedida.
from cassandra.cluster import Cluster
from cassandra.query import PreparedStatement, BoundStatement
import uuid
import datetime
import requests
cluster = Cluster(['127.0.0.1'],port=9042)
session = cluster.connect()
def generate_embedding(text):
embedding_url = 'http://localhost:11434/api/embed'
body = {
"model": "nomic-embed-text",
"input": text
}
response = requests.post(embedding_url, json = body)
return response.json()['embeddings'][0]
def insert_chunk(content, vector):
id = uuid.uuid4()
content_chunk = content
content_vector = vector
created_at = datetime.datetime.now()
insert_query = """
INSERT INTO embeddings.document_vectors (record_id, id, content_chunk, content_vector, created_at)
VALUES (now(), ?, ?, ?, ?)
"""
prepared_stmt = session.prepare(insert_query)
session.execute(prepared_stmt, [
id,
content_chunk,
content_vector,
created_at
])
def insert_sample_data_in_cassandra():
sentences = [
"The aroma of freshly baked bread wafted through the quaint bakery nestled in the cobblestone streets of Paris, making Varun feel like time stood still.",
"Sipping a spicy masala chai in a bustling tea stall in Mumbai, Varun felt he was tasting the very soul of the city.",
"The sushi in a small Tokyo diner was so fresh, it felt like Varun was on a culinary journey to the sea itself.",
"Under the starry desert sky in Morocco, Varun enjoyed a lamb tagine that tasted like a dream cooked slowly over a fire.",
"The cozy Italian trattoria served the creamiest risotto, perfectly capturing the heart of Tuscany on a plate, which Varun savored with delight.",
"Enjoying fish tacos on a sunny beach in Mexico, with the waves crashing nearby, made the flavors unforgettable for Varun.",
"The crispy waffles drizzled with syrup at a Belgian café were worth every minute of waiting, as Varun indulged in the decadent treat.",
"A bowl of warm pho in a roadside eatery in Hanoi felt like comfort wrapped in a broth of herbs and spices, giving Varun a sense of warmth.",
"Sampling chocolate truffles in a Swiss chocolate shop, Varun found himself in a moment of pure bliss amidst snow-capped mountains.",
"The street food stalls in Bangkok served fiery pad Thai that left Varun with a tangy memory of the city’s vibrant energy."
]
for sentence in sentences:
vector = generate_embedding(sentence)
insert_chunk(sentence, vector)
insert_sample_data_in_cassandra()
Agora, execute este arquivo usando o comando na linha de comando no ambiente virtual:
python app.py
Uma vez que o arquivo é executado e os documentos são inseridos, isso pode ser verificado consultando o banco de dados Cassandra a partir do console cqlsh. Para isso, abra cqlsh
e execute:
SELECT content_chunk FROM embeddings.document_vectors;
Isto retornará 10 documentos inseridos no banco de dados, conforme visto na captura de tela abaixo.
Marco 2: Concluímos a configuração dos dados em nosso banco de dados vetorial.
Agora, escreveremos o código para consultar documentos com base na similaridade de cosseno. A similaridade de cosseno é o produto escalar de dois valores vetoriais. Sua fórmula é A.B / |A||B|. Essa similaridade de cosseno é suportada internamente pelo Apache Cassandra, nos ajudando a calcular tudo no banco de dados e lidar eficientemente com grandes volumes de dados.
O código abaixo é autoexplicativo; ele busca os três principais resultados com base na similaridade de cosseno usando ORDER BY <nome da coluna> ANN OF <text_vector>
e também retorna os valores de similaridade de cosseno. Para executar este código, é necessário garantir que a indexação seja aplicada a esta coluna vetorial.
def query_rag(text):
text_embeddings = generate_embedding(text)
select_query = """
SELECT content_chunk,similarity_cosine(content_vector, ?) FROM embeddings.document_vectors
ORDER BY content_vector ANN OF ?
LIMIT 3
"""
prepared_stmt = session.prepare(select_query)
result_rows = session.execute(prepared_stmt, [
text_embeddings,
text_embeddings
])
for row in result_rows:
print(row[0], row[1])
query_rag('Tell about my Bangkok experiences')
Lembre-se de comentar o código de inserção:
#insert_sample_data_in_cassandra()
Agora, execute o código Python usando python app.py
.
Obteremos a saída abaixo:
(myvenv) setia@setia-Lenovo-IdeaPad-S340-15IIL:/media/setia/Data/Tutorials/cassandra-ollama-app$ python app.py
The street food stalls in Bangkok served fiery pad Thai that left Varun with a tangy memory of the city’s vibrant energy. 0.8205469250679016
Sipping a spicy masala chai in a bustling tea stall in Mumbai, Varun felt he was tasting the very soul of the city. 0.7719690799713135
A bowl of warm pho in a roadside eatery in Hanoi felt like comfort wrapped in a broth of herbs and spices, giving Varun a sense of warmth. 0.7495554089546204
Você pode ver que a similaridade de cosseno de “As barracas de comida de rua em Bangkok serviram um pad Thai ardente que deixou Varun com uma memória picante da energia vibrante da cidade.” é 0.8205469250679016, que é a correspondência mais próxima.
Marco Final: Implementamos a pesquisa RAG.
Aplicações Empresariais
Apache Cassandra
Para empresas, podemos usar Apache Cassandra 5.0 de fornecedores de nuvem populares como Microsoft Azure, AWS, GCP, etc.
Ollama
Este middleware requer uma VM compatível com GPU alimentada por Nvidia para executar modelos de alto desempenho, mas não precisamos de VMs de ponta para modelos usados para gerar vetores. Dependendo dos requisitos de tráfego, várias VMs podem ser usadas, ou qualquer serviço de IA generativa como Open AI, Anthropy, etc., cujo Custo Total de Propriedade seja menor para necessidades de escalabilidade ou necessidades de Governança de Dados.
VM Linux
Apache Cassandra e Ollama podem ser combinados e hospedados em uma única VM Linux se o caso de uso não exigir alto uso para reduzir o Custo Total de Propriedade ou para atender às necessidades de Governança de Dados.
Conclusão
Podemos facilmente construir aplicações RAG usando o sistema operacional Linux, Apache Cassandra, modelos de incorporação (nomic-embed-text) usados via Ollama e Python com bom desempenho sem precisar de qualquer assinatura de nuvem adicional ou serviços no conforto de nossas máquinas/servidores.
No entanto, hospedar uma VM em servidor(es) ou optar por uma assinatura na nuvem para escalonamento como uma aplicação empresarial compatível com arquiteturas escaláveis é recomendado. Neste contexto, o Apache Cassandra é um componente chave para realizar o trabalho pesado do armazenamento de vetores e comparação de vetores, e o servidor Ollama para gerar incorporações de vetores.
É isso! Obrigado por ler até o final.
Source:
https://dzone.com/articles/build-rag-apps-apache-cassandra-python-ollama