Guida a Chroma DB | Un archivio vettoriale per i tuoi LLMs di intelligenza artificiale generativa

Guida a Chroma DB | Archivio vettoriale per i LLMs di IA generativa

Introduzione

I modelli linguistici generativi di grandi dimensioni come GPT, PaLM, ecc. vengono addestrati su grandi quantità di dati. Questi modelli non prendono i testi dal dataset così come sono, perché i computer non comprendono il testo, ma comprendono solo i numeri. Le embedding sono la rappresentazione del testo ma in formato numerico. Tutte le informazioni dai modelli linguistici di grandi dimensioni passano attraverso queste embedding. Accedere direttamente a queste embedding richiede tempo. Pertanto, quello che viene chiamato Vector Databases memorizza queste embedding appositamente progettate per un archiviazione e un recupero efficienti delle embedding vettoriali. In questa guida, ci concentreremo su un tale archivio/vettore di database, Chroma DB, che è ampiamente utilizzato e open-source.

Obiettivi di Apprendimento

  • Generare embedding con ChromaDB e modelli di embedding
  • Creare collezioni all’interno del Chroma Vector Store
  • Memorizzare documenti, immagini e embedding all’interno delle collezioni
  • Eseguire operazioni di collezione come eliminare e aggiornare dati, rinominare le collezioni
  • Infine, interrogare le collezioni per estrarre informazioni rilevanti

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

Breve introduzione alle Embedding

Le embedding o le embedding vettoriali sono un modo per rappresentare i dati (testo, immagini, audio, video, ecc.) in formato numerico, per essere precisi è un modo per rappresentare i dati sotto forma di numeri in uno spazio n-dimensionale (un vettore numerico). In questo modo, le embedding ci consentono di raggruppare insieme dati simili. Ci sono modelli che prendono questi input e li convertono in vettori. Un esempio di ciò è il Word2Vec, che è un modello di embedding popolare sviluppato da Google, che converte le parole in vettori (i vettori sono punti che hanno n-dimensioni). Tutti i modelli linguistici di grandi dimensioni hanno i loro modelli di embedding rispettivi, che creano le embedding per il loro LLM.

A cosa servono queste embedding?

La cosa positiva di convertire le parole in vettori è che possiamo confrontarli. Un computer non può confrontare due parole così come sono, ma se le diamo sotto forma di input numerici, cioè embedding vettoriali, può confrontarle. Possiamo creare un cluster di parole che hanno embedding simili. Le parole Re, Regina, Principe e Principessa appariranno in un cluster perché sono correlate tra loro.

In questo modo, le embedding ci permettono di trovare parole simili a una parola data. Possiamo incorporare questo nelle frasi, dove inseriamo una frase e otteniamo le frasi correlate dai dati forniti. Questa è la base per la Ricerca Semantica, la Similarità delle Frasi, la Rilevazione di Anomalie, il chatbot e molti altri casi d’uso. I chatbot che costruiamo per eseguire il Question Answering da un PDF o un documento, sfruttano questo stesso concetto di embedding. Tutti i modelli linguistici generativi di grandi dimensioni utilizzano questo approccio per ottenere contenuti simili alle query fornite loro.

Archivio Vettoriale e la necessità di essi

Come discusso, le embedding sono rappresentazioni di qualsiasi tipo di dati, di solito quelli non strutturati, in formato numerico in uno spazio n-dimensionale. Ora, dove li memorizziamo? I tradizionali RDMS (Sistemi di Gestione di Database Relazionali) non possono essere utilizzati per memorizzare queste embedding vettoriali. Ed è qui che entrano in gioco gli Archivi Vettoriali / Database Vettoriali. I Database Vettoriali sono progettati per memorizzare e recuperare embedding vettoriali in modo efficiente. Ci sono molti Archivi Vettoriali là fuori, che differiscono per i modelli di embedding che supportano e per il tipo di algoritmo di ricerca che utilizzano per ottenere vettori simili.

Perché ne abbiamo bisogno? Ne abbiamo bisogno perché forniscono un accesso rapido ai dati di cui abbiamo bisogno. Consideriamo un chatbot basato su un PDF. Quando un utente inserisce una query, la prima cosa da fare è recuperare i contenuti correlati dal PDF a quella query e fornire queste informazioni al chatbot. In modo che il chatbot possa prendere queste informazioni correlate alla query e fornire una risposta pertinente all’utente. Ma come otteniamo i contenuti rilevanti dal PDF relativi alla query dell’utente? La risposta è una semplice ricerca di similarità

Quando i dati sono rappresentati in embedding vettoriali, possiamo trovare somiglianze tra diverse parti dei dati e estrarre i dati simili a una particolare embedding. La query viene prima convertita in embedding da un modello di embedding e quindi l’Archivio Vettoriale prende questa embedding vettoriale e quindi esegue una ricerca di similarità (attraverso gli algoritmi di ricerca) tra altre embedding che ha memorizzato nel suo database e recupera tutti i dati pertinenti. Queste embedding vettoriali pertinenti vengono quindi passate al Grande Modello Linguistico che è il chatbot che utilizza queste informazioni per generare una risposta finale all’utente.

Cos’è Chroma DB?

Chroma è un Vector Store / Vector DB dell’azienda Chroma. Chroma DB, come molti altri Vector Store disponibili, serve per archiviare e recuperare embedding vettoriali. La cosa interessante è che Chroma è un progetto gratuito e open source. Questo permette ad altri sviluppatori esperti di dare suggerimenti e apportare miglioramenti notevoli al Database e ci si può aspettare una risposta rapida a un problema quando si tratta di software open source, poiché l’intera comunità open source è lì per vedere e risolvere quel problema.

Attualmente Chroma non fornisce servizi di hosting. Archivia i dati localmente nel file system locale quando si creano applicazioni basate su Chroma. Tuttavia, Chroma sta pianificando di costruire un servizio di hosting in futuro. Chroma DB offre diversi modi per archiviare embedding vettoriali. È possibile archiviarli in memoria, salvarli e caricarli in memoria, o semplicemente eseguire Chroma come client per comunicare con il server di backend. In generale, Chroma DB ha solo 4 funzioni nell’API, rendendolo breve, semplice e facile da iniziare.

Iniziamo con Chroma DB

In questa sezione installeremo Chroma e vedremo tutte le funzionalità che offre. In primo luogo, installeremo la libreria tramite il comando pip

$ pip install chromadb

API del Chroma Vector Store

Questo scaricherà l’API del Chroma Vector Store per Python. Con questo pacchetto, possiamo eseguire tutte le operazioni come archiviare gli embedding vettoriali, recuperarli e eseguire una ricerca semantica per un dato embedding vettoriale.

import chromadb
from chromadb.config import Settings


client = chromadb.Client(Settings(chroma_db_impl="duckdb+parquet",
                                    persist_directory="/content/"
                                ))

Database in memoria

Inizieremo creando un database persistente in memoria. Il codice sopra creerà un database per noi. Per creare un client, prendiamo l’oggetto Client() da Chroma DB. Per creare un database in memoria, configuriamo il nostro client con i seguenti parametri

  • chroma_db_impl = “duckdb+parquet”
  • persist_directory = “/content/”

In questo modo creeremo un database DuckDB in memoria con il formato file parquet. Forniamo anche la directory in cui memorizzare questi dati. Qui stiamo salvando il database nella cartella /content/. Quindi ogni volta che ci connettiamo a un client Chroma DB con questa configurazione, Chroma DB cercherà un database esistente nella directory fornita e lo caricherà. Se non è presente, lo creerà. E quando chiudiamo la connessione, i dati verranno salvati in questa directory.

Ora creeremo una collezione. La collezione in Vector Store è dove salviamo il set di embedding vettoriali, documenti e eventuali metadati se presenti. Una collezione in un database vettoriale può essere considerata come una tabella in un database relazionale.

Creare una Collezione e Aggiungere Documenti

Ora creeremo una collezione e aggiungeremo dei documenti ad essa.

collection = client.create_collection("my_information")


collection.add(
    documents=["Questo è un documento contenente informazioni sulle auto",
    "Questo è un documento contenente informazioni sui cani", 
    "Questo documento contiene un catalogo di veicoli a quattro ruote"],
    metadatas=[{"source": "Libro delle Auto"},{"source": "Libro dei Cani"},{'source':'Informazioni sui Veicoli'}],
    ids=["id1", "id2", "id3"]
)
  • Iniziamo creando prima una collezione. Qui diamo il nome “my_information” alla collezione.
  • A questa collezione aggiungeremo dei documenti. Qui stiamo aggiungendo 3 documenti, nel nostro caso, stiamo aggiungendo tre frasi come tre documenti. Il primo documento riguarda le auto, il secondo riguarda i cani e l’ultimo riguarda i veicoli a quattro ruote.
  • Stiamo anche aggiungendo i metadati. Vengono forniti i metadati per tutti e tre i documenti.
  • Ogni documento deve avere un ID univoco, quindi diamo loro id1, id2 e id3
  • Tutti questi sono come variabili per la funzione add() della collezione
  • Dopo aver eseguito il codice, aggiungiamo questi documenti alla nostra collezione “my_information”

Database vettoriali

Abbiamo appreso che le informazioni memorizzate nei database vettoriali sono sotto forma di embedding vettoriali. Ma qui abbiamo fornito testo/file di testo, ovvero documenti. Come vengono memorizzati? Chroma DB utilizza di default un modello di embedding vettoriale all-MiniLM-L6-v2 per creare gli embedding per noi. Questo modello prenderà i nostri documenti e li convertirà in embedding vettoriali. Se vogliamo lavorare con una funzione di embedding specifica come altri modelli di sentence-transformer di HuggingFace o il modello di embedding di OpenAI, possiamo specificarlo sotto il nome di variabile embeddings_function=nome_funzione_embedding nel metodo create_collection().

Possiamo anche fornire direttamente gli embedding al Vector Store, anziché passare i documenti. Proprio come il parametro “document” in create_collection, abbiamo un parametro “embedding” al quale passiamo gli embedding che vogliamo memorizzare nel Database vettoriale.

Quindi ora il modello ha memorizzato con successo i nostri tre documenti sotto forma di embedding vettoriali nel Vector Store. Ora, vedremo come recuperare documenti rilevanti da essi. Passeremo una query e recupereremo i documenti rilevanti ad essa. Il codice corrispondente sarà

results = collection.query(
    query_texts=["Auto"],
    n_results=2
)


print(results)

Interrogare un Vector Store

  • Per interrogare un Vector Store, abbiamo una funzione query() fornita dalle collezioni che ci consente di interrogare il database vettoriale per documenti rilevanti. In questa funzione, forniamo due parametri
  • query_texts – A questo parametro, forniamo una lista di query per le quali vogliamo estrarre i documenti rilevanti.
  • n_results – Questo parametro specifica quanti risultati principali il database deve restituire. Nel nostro caso, vogliamo che la collezione restituisca i 2 documenti più rilevanti relativi alla query
  • Quando eseguiamo e stampiamo i risultati, otteniamo il seguente output

Vediamo che il Vector Store restituisce due documenti associati a id1 e id3. L’id1 è il documento sulle auto e l’id3 è il documento sulle quattro ruote, che è di nuovo relativo a un’auto. Quindi quando abbiamo dato una query, Chroma DB converte la query in un embedding vettoriale con il modello di embedding che abbiamo fornito all’inizio. Quindi questo embedding vettoriale esegue una ricerca semantica (vicini simili) su tutti i documenti disponibili. La query qui “auto” è più rilevante per i documenti id1 e id3, quindi otteniamo il seguente risultato per la query.

Questo è molto utile quando stiamo cercando di costruire un’applicazione di chat che include documenti multipli. Attraverso un Vector Store, possiamo recuperare i documenti rilevanti per la query fornita eseguendo una ricerca semantica e alimentando solo questi documenti al modello AI generativo finale, che prenderà quindi questi documenti rilevanti e genererà una risposta alla query fornita.

Aggiornamento ed eliminazione dei dati

Non sempre aggiungiamo tutte le informazioni in una volta sola al Vector Store. Nella maggior parte dei casi, all’inizio abbiamo solo dati/documenti limitati, che aggiungiamo così come sono al Vector Store. Successivamente, quando otteniamo più dati, diventa necessario aggiornare i dati/espressioni vettoriali esistenti presenti nel Vector Store. Per aggiornare i dati in Chroma DB, facciamo quanto segue

collection.update(
    ids=["id2"],
    documents=["Questo è un documento che contiene informazioni su gatti"],
    metadatas=[{"source": "Libro sui gatti"}],
)

In precedenza, le informazioni nel documento associato a id2 riguardavano i cani. Ora le stiamo cambiando in gatti. Perché queste informazioni siano aggiornate all’interno del Vector Store, passiamo l’id del documento, il documento aggiornato e i metadati aggiornati del documento alla funzione update() delle collezioni. In questo modo verrà ora aggiornato l’id2 con i gatti che prima riguardava i cani.

Interrogazione nel Database

results = collection.query(
    query_texts=["Felini"],
    n_results=1
)


print(results)

Passiamo Felini come query al Vector Store. I gatti appartengono alla famiglia dei mammiferi chiamati Felini. Quindi la collezione deve restituirci il documento sul gatto come documento rilevante. Nell’output vediamo esattamente lo stesso. Il Vector Store è stato in grado di eseguire una ricerca semantica tra la query e il contenuto dei documenti ed è stato in grado di restituire il documento perfetto per la query fornita.

La funzione Upset

C’è una funzione simile alla funzione di aggiornamento chiamata funzione upsert(). L’unico differenza tra la funzione update() e la funzione upsert() è che se l’ID del documento specificato nella funzione update() non esiste, la funzione update() genererà un errore. Ma nel caso della funzione upsert(), se l’ID del documento non esiste nella collezione, allora verrà aggiunto alla collezione in modo simile alla funzione add().

A volte, per ridurre lo spazio o rimuovere informazioni inutili, potremmo voler eliminare alcuni documenti dalla collezione nel Vector Store.

collection.delete(ids = ['id1'])


results = collection.query(
    query_texts=["Auto"],
    n_results=2
)


print(results)

La funzione di eliminazione

Per eliminare un elemento da una collezione, abbiamo la funzione delete(). Nell’esempio sopra, stiamo eliminando il primo documento associato a id1 che parlava di auto. Ora per verificare, effettuiamo una query sulla collezione con “auto” come query e poi vediamo i risultati. Vediamo che compaiono solo 2 documenti id2 e id3, dove id2 è il documento sulle auto a quattro ruote che sono più vicine alle auto e id3 è il documento sui gatti che è il meno vicino alle auto, ma poiché abbiamo specificato n_results = 2 otteniamo anche id3. Se non specifichiamo alcuna variabile alla funzione delete(), allora tutti gli elementi verranno eliminati da quella collezione.

Funzioni della collezione

Abbiamo visto come creare una nuova collezione e quindi aggiungere documenti ed embedding ad essa. Abbiamo anche visto come estrarre informazioni rilevanti per una query dalla collezione, cioè dai documenti memorizzati nel Vector Store. L’oggetto collezioni di Chroma DB è anche associato a molte altre utili funzioni.

Guardiamo altre funzionalità fornite da Chroma DB

new_collections = client.create_collection("nuova_collezione")


new_collections.add(
    documents=["Questa è la documentazione di Python",
               "Questa è la documentazione di Javascript",
               "Questo documento contiene il cheatsheet di Flask API"],
    metadatas=[{"sorgente": "Python per tutti"},
    {"sorgente": "JS Docs"},
    {'sorgente':'Everything Flask'}],
    ids=["id1", "id2", "id3"]
)


print(new_collections.count())
print(new_collections.get())

La funzione di conteggio

La funzione count() delle collezioni restituisce il numero di elementi presenti nella collezione. Nel nostro caso, abbiamo 3 documenti memorizzati nella nostra collezione, quindi l’output sarà 3. Per quanto riguarda la funzione get(), restituisce tutti gli elementi presenti nella nostra collezione insieme ai metadati, agli id e agli embedding, se presenti. Nell’output, vediamo che tutti gli elementi che abbiamo nella nostra collezione vengono restituiti dal comando get(). Ora vediamo come modificare il nome della collezione

collection.modify(name="nuovo_nome_raccolta")

La Funzione di Modifica

Utilizza la funzione modify() delle collezioni per cambiare il nome della raccolta che è stato fornito all’inizio della creazione della raccolta. Quando viene eseguita, cambia il nome della raccolta dal vecchio nome definito all’inizio al nuovo nome fornito nella funzione modify() sotto la variabile name. Ora supponiamo di avere più collezioni nel nostro Vector Store. Come lavorare su una raccolta specifica, cioè come ottenere una raccolta specifica dal Vector Store e come eliminare una raccolta specifica? Vediamo questo.

my_collection = client.get_collection(name="my_information_2")

client.delete_collection(name="my_information_2")

La Funzione per Ottenere la Raccolta

La funzione get_collection() recupererà una raccolta esistente fornita il nome, dal Vector Store. Se la raccolta fornita non esiste, la funzione genererà un errore per lo stesso. Qui get_collection() cercherà di ottenere la raccolta my_information_2 e la assegnerà alla variabile my_collection. Per eliminare una raccolta esistente, abbiamo la funzione delete_collection(), che prende il nome della raccolta come parametro (my_information in questo caso) e la elimina, se esiste.

Conclusione

In questa guida, abbiamo visto come iniziare con Chroma, uno dei Database Vettoriali Open Source. Abbiamo iniziato con l’apprendimento di cosa sono i vettori di incorporamento, perché sono necessari per i modelli di intelligenza artificiale generativa e come i Vector Store aiutano questi modelli di linguaggio generativi di grandi dimensioni. Poi siamo entrati nel dettaglio di Chroma e abbiamo visto come creare raccolte in Chroma. Poi abbiamo esaminato come aggiungere dati come documenti a Chroma e come il database Chroma crea vettori di incorporamento da essi. Infine, abbiamo visto come recuperare informazioni pertinenti alla query fornita da una raccolta specifica presente nel Vector Store.

Alcuni dei punti chiave da ricordare di questa guida includono:

  • I vettori di incorporamento sono rappresentazioni numeriche (vettori numerici) di dati non numerici come testo, immagini, audio, ecc.
  • I Vector Store sono i database utilizzati per memorizzare i vettori di incorporamento sotto forma di raccolte.
  • Offrono un’efficace archiviazione e recupero delle informazioni dai dati di incorporamento.
  • Chroma DB può funzionare sia come database in memoria che come backend.
  • Chroma DB ha la funzionalità di memorizzare i dati alla chiusura e di caricarli in memoria all’inizio di una connessione, mantenendo così i dati.
  • Con i Vector Store, estrarre informazioni dai documenti, generare raccomandazioni e creare applicazioni di chatbot sarà molto più semplice.

Domande Frequenti

I contenuti mostrati in questo articolo non sono di proprietà di Analytics Vidhya e sono utilizzati a discrezione dell’autore.