ChromaDB + Autenticazione e Collezioni

Tradotto dall'originale in spagnolo. Leggi in spagnolo

In questo tutorial impareremo a lavorare con ChromaDB, un database per gestire vettori di embedding, con l’autenticazione e la gestione delle collezioni.

iStock AI Generator

Configurazione di un server ChromaDB

In questo caso useremo Docker per distribuire il server. Per avviare un server ChromaDB con autenticazione è indispensabile definire correttamente le variabili di autenticazione nel file `docker-compose.yml`. È fondamentale non salvare il token o la chiave segreta in chiaro, per motivi di sicurezza; questa dimostrazione serve solo a illustrare come procedere con la configurazione.

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

Per avviare il server ChromaDB, esegui il seguente comando:

docker-compose up

Parametri per la collezione e la query

Definiamo alcuni parametri che useremo per la collezione e la query:

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/'

Caricamento e divisione dei documenti

Creiamo una funzione per caricare i documenti da una cartella e un’altra per dividerli in frammenti:

Funzione per caricare documenti da una cartella

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

Funzione per dividere i documenti in frammenti

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

Caricamento e divisione dei documenti

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

Generazione degli embedding

Generiamo gli embedding per i frammenti dei documenti usando un modello pre-addestrato:

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

Client di ChromaDB e operazioni

Per collegarci al server ChromaDB e autenticarci, dobbiamo prima istanziare il client. In questo esempio configuriamo la porta e forniamo le credenziali di autenticazione necessarie.

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

Creazione o recupero di una collezione

Qui vedremo come verificare se una collezione esiste e, in caso contrario, come crearla.

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

Generazione degli embedding per i documenti

Generiamo gli embedding dei documenti, che ci permetteranno poi di fare ricerche all’interno della collezione.

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

Aggiunta dei documenti e dei loro metadati alla collezione

Una volta generati gli embedding, aggiungiamo i documenti e i relativi metadati alla collezione appena creata o recuperata.

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]
)

Esecuzione di una query di esempio

Eseguiamo una query di esempio: prima creiamo l’embedding della query, poi lo usiamo per ottenere i risultati dal database.

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'}]},
)

Infine mostriamo i risultati della query.

print(f"Results: {results}")

Codice completo

Ecco il codice completo usato in questo 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

Pubblicato in: IA