ChromaDB + Autenticação e Coleções

Traduzido do original em espanhol. Ler em espanhol

Neste tutorial vamos aprender a trabalhar com o ChromaDB, um banco de dados para gerenciar vetores de embeddings, com autenticação e manipulação de coleções.

iStock AI Generator

Configuração de um servidor ChromaDB

Neste caso, usaremos o Docker para implantar o servidor. Para colocar em funcionamento um servidor ChromaDB com autenticação, é imprescindível definir corretamente as variáveis de autenticação no arquivo `docker-compose.yml`. É fundamental não guardar o token ou a chave secreta em texto puro, por motivos de segurança; esta demonstração serve apenas para ilustrar como fazer a configuração.

version: "3.9"
services:
  chroma:
    image: ghcr.io/chroma-core/chroma:latest
    environment:
      CHROMA_SERVER_AUTHN_CREDENTIALS: "test-token"
      CHROMA_SERVER_AUTHN_PROVIDER: "chromadb.auth.token_authn.TokenAuthServerProvider"
    volumes:
      - index_data:/chroma/.chroma/index
    ports:
      - 8001:8000
    networks:
      - net
volumes:
  index_data:
    driver: local
  backups:
    driver: local

networks:
  net:
    driver: bridge

Para iniciar o servidor ChromaDB, execute o seguinte comando:

docker-compose up

Parâmetros da coleção e da consulta

Definimos alguns parâmetros que usaremos para a coleção e a consulta:

EMBEDDINGS_MAX_RESULTS = 2
CHROMA_SERVER_AUTHN_CREDENTIALS = os.getenv('CHROMA_SERVER_AUTHN_CREDENTIALS')
CHROMA_CLIENT_AUTHN_PROVIDER = 'chromadb.auth.token_authn.TokenAuthClientProvider'
VECTOR_EMBEDDING_HOST = 'localhost'
directory = 'Zero/'

Carregamento e divisão de documentos

Criamos uma função para carregar documentos de um diretório e outra para dividi-los em fragmentos:

Função para carregar documentos de um diretório

def load_docs(directory):
    loader = DirectoryLoader(directory, glob="**/*.txt", loader_cls=TextLoader)
    documents = loader.load()
    return documents

Função para dividir documentos em fragmentos

def split_docs(documents, chunk_size=1000, chunk_overlap=20):
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
    docs = text_splitter.split_documents(documents)
    return docs

Carregamento e divisão dos documentos

documents = load_docs(directory)
docs = split_docs(documents)

Geração de embeddings

Geramos embeddings para os fragmentos dos documentos usando um modelo pré-treinado:

embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")

Cliente do ChromaDB e operações

Para conectar ao servidor ChromaDB e nos autenticar, primeiro precisamos instanciar o cliente. Neste exemplo, configuramos a porta e fornecemos as credenciais de autenticação necessárias.

chroma_client = chromadb.HttpClient(
    port=8001,
    settings=Settings(
    chroma_client_auth_provider=CHROMA_CLIENT_AUTHN_PROVIDER,
    chroma_client_auth_credentials=CHROMA_SERVER_AUTHN_CREDENTIALS)
)

Criação ou recuperação de uma coleção

Aqui veremos como verificar se uma coleção existe e, caso não exista, como criá-la.

collection = chroma_client.get_or_create_collection(name='myCollection')

Geração de embeddings para os documentos

Geramos os embeddings dos documentos, que depois nos permitirão fazer buscas dentro da coleção.

doc_embeddings = embeddings.embed_documents([doc.page_content for doc in docs])

Adição dos documentos e seus metadados à coleção

Com os embeddings gerados, adicionamos os documentos e seus metadados à coleção recém-criada ou recuperada.

collection.add(
    ids = [str(uuid.uuid4()) for _ in docs],
    embeddings = doc_embeddings,
    documents = [doc.page_content for doc in docs],
    metadatas = [{'timestamp': timestamp, 'chapter': 'A', 'region': 'AMER', 'book': 'REGISTRY'} for _ in docs]
)

Execução de uma consulta de exemplo

Fazemos uma consulta de exemplo: primeiro criamos o embedding da consulta e depois usamos esse embedding para obter resultados do banco de dados.

embed_query = embeddings.embed_documents('The search query')

results = collection.query(
    query_embeddings = embed_query,
    n_results= EMBEDDINGS_MAX_RESULTS,
    where= {'$and': [{'chapter': 'A'}, {'region': 'AMER'}]},
)

Por fim, exibimos os resultados da consulta.

print(f"Results: {results}")

Código completo

A seguir, o código completo usado neste tutorial:

from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from dotenv import load_dotenv
import chromadb, uuid, os, datetime
from chromadb.config import Settings
load_dotenv()

EMBEDDINGS_MAX_RESULTS = 2
CHROMA_SERVER_AUTHN_CREDENTIALS = os.getenv('CHROMA_SERVER_AUTHN_CREDENTIALS')
CHROMA_CLIENT_AUTHN_PROVIDER = 'chromadb.auth.token_authn.TokenAuthClientProvider'
VECTOR_EMBEDDING_HOST = 'localhost'
directory = 'Zero/'

def load_docs(directory):
    loader = DirectoryLoader(directory, glob="**/*.txt", loader_cls=TextLoader)
    documents = loader.load()
    return documents

def split_docs(documents, chunk_size=1000, chunk_overlap=20):
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
    docs = text_splitter.split_documents(documents)
    return docs

documents = load_docs(directory)
docs = split_docs(documents)
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")

try:
    chroma_client = chromadb.HttpClient(
        port=8001,
        settings=Settings(
        chroma_client_auth_provider=CHROMA_CLIENT_AUTHN_PROVIDER,
        chroma_client_auth_credentials=CHROMA_SERVER_AUTHN_CREDENTIALS)
    )

    collection = chroma_client.get_or_create_collection(name='myCollection')

    timestamp = datetime.datetime.now().isoformat()
    doc_embeddings = embeddings.embed_documents([doc.page_content for doc in docs])

    collection.add(
        ids = [str(uuid.uuid4()) for _ in docs],
        embeddings = doc_embeddings,
        documents = [doc.page_content for doc in docs],
        metadatas = [{'timestamp': timestamp, 'chapter': 'A', 'region': 'AMER', 'book': 'REGISTRY'} for _ in docs]
    )

    embed_query = embeddings.embed_documents('The search query')
    results = collection.query(
        query_embeddings = embed_query,
        n_results= EMBEDDINGS_MAX_RESULTS,
        where= {'$and': [{'chapter': 'A'}, {'region': 'AMER'}]},
    )

    print(f"Results: {results}")
except Exception as error:
    print(f"Error: {error}")

Maximiliano Díaz Doglia

AI Platform Engineer & Full-Stack Developer
Building Enterprise Integrations & Automations

Publicado em: IA