Em um artigo anterior, utilizamos Ollama com LangChain e SingleStore. LangChain forneceu uma solução eficiente e compacta para a integração de Ollama com SingleStore. No entanto, e se dessemos a LangChain? Neste artigo, demonstraremos um exemplo de uso de Ollama com SingleStore sem depender do LangChain. Veremos que, embora possamos alcançar os mesmos resultados descritos no artigo anterior, o número de linhas de código aumenta, exigindo que gerencemos mais da infraestrutura que o LangChain normalmente lida.
O arquivo de notebook usado neste artigo está disponível no GitHub.
Introdução
Do artigo anterior, seguiremos os mesmos passos para configurar nosso ambiente de teste conforme descrito nessas seções:
- Introdução
- Use uma Máquina Virtual ou
venv
.
- Use uma Máquina Virtual ou
- Crie uma conta SingleStoreDB Cloud
- Use Ollama Demo Group como o Nome do Grupo de Workspace e ollama-demo como o Nome do Workspace. Anote a senha e o nome host. Temporariamente, permita o acesso de qualquer lugar configurando o firewall sob Ollama Demo Group > Firewall.
- Criar um Banco de Dados
CREATE DATABASE IF NOT EXISTS ollama_demo;
- Instalar Jupyter
pip install notebook
- Instalar Ollama
curl -fsSL https://ollama.com/install.sh | sh
- Variável de Ambiente
export SINGLESTOREDB_URL="admin:<senha>@<host>:3306/ollama_demo"
Substituir<senha>
e<host>
pelos valores do seu ambiente.
- Iniciar Jupyter
jupyter notebook
Preencha o Notebook
Primeiro, algumas pacotes:
!pip install ollama numpy pandas sqlalchemy-singlestoredb --quiet --no-warn-script-location
A seguir, importaremos algumas bibliotecas:
import ollama
import os
import numpy as np
import pandas as pd
from sqlalchemy import create_engine, text
Criaremos embeddings usando all-minilm
(45 MB no momento da escrita):
ollama.pull("all-minilm")
{'status': 'success'}
Para nossa LLM, usaremos llama2
(3.8 GB no momento de escrita):
ollama.pull("llama2")
Exemplo de saída:
{'status': 'success'}
A seguir, usaremos o texto de exemplo do site Ollama:
documents = [
"Llamas are members of the camelid family meaning they're pretty closely related to vicuñas and camels",
"Llamas were first domesticated and used as pack animals 4,000 to 5,000 years ago in the Peruvian highlands",
"Llamas can grow as much as 6 feet tall though the average llama between 5 feet 6 inches and 5 feet 9 inches tall",
"Llamas weigh between 280 and 450 pounds and can carry 25 to 30 percent of their body weight",
"Llamas are vegetarians and have very efficient digestive systems",
"Llamas live to be about 20 years old, though some only live for 15 years and others live to be 30 years old"
]
df_data = []
for doc in documents:
response = ollama.embeddings(
model = "all-minilm",
prompt = doc
)
embedding = response["embedding"]
embedding_array = np.array(embedding).astype(np.float32)
df_data.append({"content": doc, "vector": embedding_array})
df = pd.DataFrame(df_data)
dimensions = len(df.at[0, "vector"])
Configuraremos as embeddings para all-minilm
e iteraremos sobre cada documento para construir o conteúdo para um DataFrame Pandas. Além disso, convertemos as embeddings para o formato de 32 bits, já que este é o padrão de SingleStore para o tipo de dado VECTOR
. Finalmente, determinaremos o número de dimensões de embeddings para o primeiro documento no DataFrame Pandas.
A seguir, criaremos uma conexão com nossa instância SingleStore:
connection_url = "singlestoredb://" + os.environ.get("SINGLESTOREDB_URL")
db_connection = create_engine(connection_url)
Agora, criaremos uma tabela com a coluna vector
usando as dimensões determinadas anteriormente:
query = text("""
CREATE TABLE IF NOT EXISTS pandas_docs (
id BIGINT AUTO_INCREMENT NOT NULL,
content LONGTEXT,
vector VECTOR(:dimensions) NOT NULL,
PRIMARY KEY(id)
);
""")
with db_connection.connect() as conn:
conn.execute(query, {"dimensions": dimensions})
Agora, escreveremos o DataFrame Pandas para a tabela:
df.to_sql(
"pandas_docs",
con = db_connection,
if_exists = "append",
index = False,
chunksize = 1000
)
Exemplo de saída:
6
Agora, criaremos um índice para corresponder ao criado no artigo anterior:
query = text("""
ALTER TABLE pandas_docs ADD VECTOR INDEX (vector)
INDEX_OPTIONS '{
"metric_type": "EUCLIDEAN_DISTANCE"
}';
""")
with db_connection.connect() as conn:
conn.execute(query)
Agora, faremos uma pergunta, conforme a seguir:
prompt = "What animals are llamas related to?"
response = ollama.embeddings(
prompt = prompt,
model = "all-minilm"
)
embedding = response["embedding"]
embedding_array = np.array(embedding).astype(np.float32)
query = text("""
SELECT content
FROM pandas_docs
ORDER BY vector <-> :embedding_array ASC
LIMIT 1;
""")
with db_connection.connect() as conn:
results = conn.execute(query, {"embedding_array": embedding_array})
row = results.fetchone()
data = row[0]
print(data)
Convertermos o prompt em embeddings, garantimos que os embeddings sejam convertidos para o formato de 32 bits e então executamos a consulta SQL que usa a notação infixa <->
para Distância Euclidiana.
Exemplo de saída:
Llamas are members of the camelid family meaning they're pretty closely related to vicuñas and camels
A seguir, usaremos a LLM, conforme a seguir:
output = ollama.generate(
model = "llama2",
prompt = f"Using this data: {data}. Respond to this prompt: {prompt}"
)
print(output["response"])
Exemplo de saída:
Llamas are members of the camelid family, which means they are closely related to other animals such as:
1. Vicuñas: Vicuñas are small, wild camelids that are native to South America. They are known for their soft, woolly coats and are considered an endangered species due to habitat loss and poaching.
2. Camels: Camels are large, even-toed ungulates that are native to Africa and the Middle East. They are known for their distinctive humps on their backs, which store water and food for long periods of time.
Both llamas and vicuñas are classified as members of the family Camelidae, while camels are classified as belonging to the family Dromedaryae. Despite their differences in size and habitat, all three species share many similarities in terms of their physical characteristics and behavior.
Resumo
Neste artigo, replicamos os passos que seguímos no artigo anterior e alcançamos resultados semelhantes. No entanto, tivemos que escrever uma série de instruções SQL e gerenciar várias etapas que o LangChain teria tratado por nós. Além disso, pode haver mais tempo e custo envolvidos na manutenção da base de código a longo prazo, em comparação com a solução LangChain.
Usar LangChain em vez de escrever código personalizado para acesso ao banco de dados oferece várias vantagens, como eficiência, escalabilidade e confiabilidade.
O LangChain oferece uma biblioteca de módulos pré-construídos para interação com o banco de dados, reduzindo o tempo e esforço de desenvolvimento. Os desenvolvedores podem usar esses módulos para implementar rapidamente várias operações de banco de dados sem começar do zero.
O LangChain abstrai muitas das complexidades envolvidas no gerenciamento de bancos de dados, permitindo que os desenvolvedores se concentrem em tarefas de alto nível, em vez de detalhes de implementação de baixo nível. Isso melhora a produtividade e o tempo de chegada ao mercado para aplicativos baseados em bancos de dados.
O LangChain tem uma grande, ativa e crescente comunidade de desenvolvedores, está disponível no GitHub e fornece extensa documentação e exemplos.
Em resumo, o LangChain oferece aos desenvolvedores uma plataforma poderosa, eficiente e confiável para a construção de aplicativos baseados em bancos de dados, permitindo que eles se concentrem em problemas de negócios usando abstrações de mais alto nível, em vez de recriar a roda com código personalizado. Comparando o exemplo neste artigo com o exemplo que usamos no artigo anterior, podemos ver os benefícios.
Source:
https://dzone.com/articles/ollama-plus-singlestore-minus-langchain