Condividi tramite


Esercitazione: eseguire una ricerca di somiglianza vettoriale in incorporamenti OpenAI di Azure con Cache Redis di Azure

In questa esercitazione si esaminerà un caso d'uso di ricerca di somiglianza vettoriale di base. Si useranno incorporamenti generati dal servizio Azure OpenAI e le funzionalità di ricerca vettoriale predefinite del livello Enterprise di Cache Redis di Azure per eseguire query su un set di dati relativi a film per trovare la corrispondenza più pertinente.

L'esercitazione usa il set di dati Trame di film di Wikipedia, che include descrizioni di Wikipedia delle trame di oltre 35.000 film, dal 1901 al 2017. Il set di dati include un riepilogo della trama per ogni film, oltre a metadati quali l'anno di uscita, il/i regista/i, il cast principale e il genere. Si seguiranno i passaggi dell'esercitazione per generare incorporamenti in base al riepilogo della trama e usare gli altri metadati per eseguire query ibride.

In questa esercitazione apprenderai a:

  • Creare un'istanza di Cache Redis di Azure configurata per la ricerca vettoriale
  • Installare Azure OpenAI e altre librerie Python necessarie.
  • Scaricare il set di dati del film e prepararlo per l'analisi.
  • Usare il modello text-embedding-ada-002 (versione 2) per generare incorporamenti.
  • Creare un indice vettoriale in Cache Redis di Azure
  • Usare la somiglianza del coseno per classificare i risultati della ricerca.
  • Usare la funzionalità di query ibrida tramite RediSearch per prefiltrare i dati e rendere la ricerca vettoriale ancora più efficace.

Importante

Questa esercitazione illustra come creare un notebook di Jupyter. È possibile seguire questa esercitazione con un file di codice Python (.py) e ottenere risultati simili, ma sarà necessario aggiungere tutti i blocchi di codice contenuti in questa esercitazione nel file .py ed eseguirli una volta per visualizzare i risultati. In altre parole, Jupyter Notebook fornisce risultati intermedi durante l'esecuzione delle celle, ma non si tratta del comportamento previsto quando si lavora in un file di codice Python.

Importante

Se invece si vuole seguire la procedura in un notebook Jupyter completato, scaricare il file del notebook Jupyter denominato tutorial.ipynb e salvarlo nella nuova cartella redis-vector.

Prerequisiti

Creare un'istanza di Azure Cache per Redis

  1. Seguire l’Avvio rapido: Creare una cache Redis Enterprise. Nella pagina Avanzate, assicurarsi di aver aggiunto il modulo RediSearch e di aver scelto i criteri cluster Enterprise. Tutte le altre impostazioni possono corrispondere alle impostazioni predefinite descritte nell’avvio rapido.

    Per creare la cache, sono necessari alcuni minuti. Nel frattempo, è possibile proseguire con il passaggio successivo.

Screenshot che mostra la scheda Informazioni di base del livello Enterprise compilata.

Configurare l'ambiente di sviluppo

  1. Creare una cartella nel computer locale denominata redis-vector nel percorso in cui si salvano in genere i progetti.

  2. Creare un nuovo file Python (tutorial.py) o un notebook Jupyter (tutorial.ipynb) nella cartella.

  3. Installare i pacchetti Python necessari:

    pip install "openai==1.6.1" num2words matplotlib plotly scipy scikit-learn pandas tiktoken redis langchain
    

Scaricare il set di dati

  1. In un Web browser accedere a https://www.kaggle.com/datasets/jrobischon/wikipedia-movie-plots.

  2. Accedere o registrarsi con Kaggle. La registrazione è necessaria per scaricare il file.

  3. Selezionare il collegamento di Download in Kaggle per scaricare il file archive.zip.

  4. Estrarre il file archive.zip e spostare wiki_movie_plots_deduped.csv nella cartella redis-vector.

Importare le librerie e configurare le informazioni di connessione

Per effettuare correttamente una chiamata ad Azure OpenAI, sono necessari un endpoint e una chiave. Per connettersi alla cache di Azure per Redis, è necessario avere anche un endpoint e una chiave.

  1. Passare alla risorsa Azure OpenAI nel portale di Azure.

  2. Individuare Endpoint e chiavi nella sezione Gestione risorse. Copiare l'endpoint e la chiave di accesso in base alle esigenze per l'autenticazione delle chiamate API. Un endpoint di esempio è https://docs-test-001.openai.azure.com. Puoi usare entrambi KEY1 o KEY2.

  3. Passare alla pagina Panoramica della risorsa cache di Azure per Redis nel portale di Azure. Copiare l'endpoint.

  4. Individuare Chiavi di accesso nella sezione Impostazioni. Copiare la chiave di accesso. Puoi usare entrambi Primary o Secondary.

  5. Aggiungere il codice seguente in una nuova cella di codice:

    # Code cell 2
    
    import re
    from num2words import num2words
    import os
    import pandas as pd
    import tiktoken
    from typing import List
    from langchain.embeddings import AzureOpenAIEmbeddings
    from langchain.vectorstores.redis import Redis as RedisVectorStore
    from langchain.document_loaders import DataFrameLoader
    
    API_KEY = "<your-azure-openai-key>"
    RESOURCE_ENDPOINT = "<your-azure-openai-endpoint>"
    DEPLOYMENT_NAME = "<name-of-your-model-deployment>"
    MODEL_NAME = "text-embedding-ada-002"
    REDIS_ENDPOINT = "<your-azure-redis-endpoint>"
    REDIS_PASSWORD = "<your-azure-redis-password>"
    
  6. Aggiornare i valori di API_KEY e RESOURCE_ENDPOINT con i valori di chiave ed endpoint della distribuzione di Azure OpenAI. DEPLOYMENT_NAME deve essere impostato sul nome della distribuzione usando il modello di incorporamento text-embedding-ada-002 (Version 2) e MODEL_NAME deve essere il modello di incorporamento specifico usato.

  7. Aggiornare REDIS_ENDPOINT e REDIS_PASSWORD con i valori di endpoint e chiave dell'istanza della cache di Azure per Redis.

    Importante

    È consigliabile usare variabili di ambiente o un gestore dei segreti, ad esempio Azure Key Vault per passare le informazioni relative a chiave API, endpoint e nome della distribuzione. Queste variabili vengono impostate in testo non crittografato per semplicità.

  8. Eseguire la cella di codice 2.

Importare un set di dati in Pandas ed elaborare i dati

Successivamente, si leggerà il file CSV in un DataFrame Pandas.

  1. Aggiungere il codice seguente in una nuova cella di codice:

    # Code cell 3
    
    df=pd.read_csv(os.path.join(os.getcwd(),'wiki_movie_plots_deduped.csv'))
    df
    
  2. Eseguire la cella di codice 3. Verrà visualizzato l'output seguente:

    Screenshot dei risultati dell'esecuzione della cella di codice 3, che mostra otto colonne e un campionamento di 10 righe di dati.

  3. Successivamente, elaborare i dati aggiungendo un id indice, rimuovendo gli spazi dai titoli delle colonne e filtrando i film per prendere solo i film realizzati dopo il 1970 e da paesi o aree di lingua inglese. Questo passaggio di filtraggio riduce il numero di film nel set di dati, riducendo di conseguenza il costo e il tempo necessari per generare incorporamenti. È possibile modificare o rimuovere i parametri di filtraggio in base alle preferenze.

    Per filtrare i dati, aggiungere il codice seguente a una nuova cella di codice:

    # Code cell 4
    
    df.insert(0, 'id', range(0, len(df)))
    df['year'] = df['Release Year'].astype(int)
    df['origin'] = df['Origin/Ethnicity'].astype(str)
    del df['Release Year']
    del df['Origin/Ethnicity']
    df = df[df.year > 1970] # only movies made after 1970
    df = df[df.origin.isin(['American','British','Canadian'])] # only movies from English-speaking cinema
    df
    
  4. Eseguire la cella di codice 4. Dovresti vedere i seguenti risultati:

    Screenshot dei risultati dell'esecuzione della cella di codice 4, che mostra nove colonne e un campionamento di 10 righe di dati.

  5. Creare una funzione per pulire i dati rimuovendo spazi vuoti e punteggiatura, quindi usarla sul DataFrame contenente la trama.

    Aggiungere il codice seguente in una nuova cella di codice ed eseguirlo:

    # Code cell 5
    
    pd.options.mode.chained_assignment = None
    
    # s is input text
    def normalize_text(s, sep_token = " \n "):
        s = re.sub(r'\s+',  ' ', s).strip()
        s = re.sub(r". ,","",s)
        # remove all instances of multiple spaces
        s = s.replace("..",".")
        s = s.replace(". .",".")
        s = s.replace("\n", "")
        s = s.strip()
    
        return s
    
    df['Plot']= df['Plot'].apply(lambda x : normalize_text(x))
    
  6. Infine, rimuovere tutte le voci che contengono descrizioni di trame troppo lunghe per il modello di incorporamento (in altre parole, quelle che richiedono più token rispetto al limite di 8192 token), quindi calcolare i numeri di token necessari per generare incorporamenti. Questa operazione influisce anche sui prezzi per la generazione di incorporamenti.

    Aggiungere il codice seguente in una nuova cella di codice:

    # Code cell 6
    
    tokenizer = tiktoken.get_encoding("cl100k_base")
    df['n_tokens'] = df["Plot"].apply(lambda x: len(tokenizer.encode(x)))
    df = df[df.n_tokens<8192]
    print('Number of movies: ' + str(len(df)))
    print('Number of tokens required:' + str(df['n_tokens'].sum()))
    
  7. Eseguire la cella di codice 6. Dovrebbe essere visualizzato questo output:

    Number of movies: 11125
    Number of tokens required:7044844
    

    Importante

    Fare riferimento a Prezzi del servizio Azure OpenAI per calcolare il costo della generazione di incorporamenti in base al numero di token necessari.

Caricare DataFrame in LangChain

Caricare il DataFrame in LangChain usando la classe DataFrameLoader. Una volta che i dati si trovano in documenti LangChain, è molto più facile usare le librerie LangChain per generare incorporamenti ed eseguire ricerche in base alla somiglianza. Impostare Plot come in page_content_column modo che gli incorporamenti vengano generati in questa colonna.

  1. Aggiungere il codice seguente in una nuova cella di codice ed eseguirlo:

    # Code cell 7
    
    loader = DataFrameLoader(df, page_content_column="Plot" )
    movie_list = loader.load()
    

Generare incorporamenti e caricarli in Redis

Ora che i dati sono stati filtrati e caricati in LangChain, si creeranno incorporamenti in modo da poter eseguire query sulla trama per ogni film. Il codice seguente configura Azure OpenAI, genera incorporamenti e carica i vettori di incorporamento in Cache Redis di Azure.

  1. Aggiungere il codice seguente a una nuova cella di codice:

    # Code cell 8
    
    embedding = AzureOpenAIEmbeddings(
        deployment=DEPLOYMENT_NAME,
        model=MODEL_NAME,
        azure_endpoint=RESOURCE_ENDPOINT,
        openai_api_type="azure",
        openai_api_key=API_KEY,
        openai_api_version="2023-05-15",
        show_progress_bar=True,
        chunk_size=16 # current limit with Azure OpenAI service. This will likely increase in the future.
        )
    
    # name of the Redis search index to create
    index_name = "movieindex"
    
    # create a connection string for the Redis Vector Store. Uses Redis-py format: https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url
    # This example assumes TLS is enabled. If not, use "redis://" instead of "rediss://
    redis_url = "rediss://:" + REDIS_PASSWORD + "@"+ REDIS_ENDPOINT
    
    # create and load redis with documents
    vectorstore = RedisVectorStore.from_documents(
        documents=movie_list,
        embedding=embedding,
        index_name=index_name,
        redis_url=redis_url
    )
    
    # save index schema so you can reload in the future without re-generating embeddings
    vectorstore.write_schema("redis_schema.yaml")
    
  2. Eseguire la cella di codice 8. Il completamento di questa operazione può richiedere più di 30 minuti. Viene generato anche un file redis_schema.yaml. Questo file è utile se ci si vuole connettere all'indice nell'istanza di Cache Redis di Azure senza generare nuovamente incorporamenti.

Importante

La velocità con cui vengono generati gli incorporamenti dipende dalla quota disponibile per il modello OpenAI di Azure. Con una quota di 240.000 token al minuto, l'elaborazione di 7M token nel set di dati richiede circa 30 minuti.

Eseguire query di ricerca vettoriale

Ora che il set di dati, l'API del servizio Azure OpenAI e l'istanza di Redis sono configurati, è possibile eseguire ricerche usando i vettori. In questo esempio vengono restituiti i primi 10 risultati per una determinata query.

  1. Aggiungere il codice seguente al file di codice Python:

    # Code cell 9
    
    query = "Spaceships, aliens, and heroes saving America"
    results = vectorstore.similarity_search_with_score(query, k=10)
    
    for i, j in enumerate(results):
        movie_title = str(results[i][0].metadata['Title'])
        similarity_score = str(round((1 - results[i][1]),4))
        print(movie_title + ' (Score: ' + similarity_score + ')')
    
  2. Eseguire la cella di codice 9. Verrà visualizzato l'output seguente:

    Independence Day (Score: 0.8348)
    The Flying Machine (Score: 0.8332)
    Remote Control (Score: 0.8301)
    Bravestarr: The Legend (Score: 0.83)
    Xenogenesis (Score: 0.8291)
    Invaders from Mars (Score: 0.8291)
    Apocalypse Earth (Score: 0.8287)
    Invasion from Inner Earth (Score: 0.8287)
    Thru the Moebius Strip (Score: 0.8283)
    Solar Crisis (Score: 0.828)
    

    Il punteggio di somiglianza viene restituito insieme alla classificazione ordinale dei film in base alla somiglianza. Notare che le query più specifiche hanno punteggi di somiglianza che diminuiscono più rapidamente man mano che si scende nell’elenco.

Ricerche ibride

  1. Poiché RediSearch include anche funzionalità di ricerca avanzate sulla ricerca vettoriale, è possibile filtrare i risultati in base ai metadati nel set di dati, ad esempio genere del film, cast, anno di uscita o regista. In questo caso, filtrare in base al genere comedy.

    Aggiungere il codice seguente in una nuova cella di codice:

    # Code cell 10
    
    from langchain.vectorstores.redis import RedisText
    
    query = "Spaceships, aliens, and heroes saving America"
    genre_filter = RedisText("Genre") == "comedy"
    results = vectorstore.similarity_search_with_score(query, filter=genre_filter, k=10)
    for i, j in enumerate(results):
        movie_title = str(results[i][0].metadata['Title'])
        similarity_score = str(round((1 - results[i][1]),4))
        print(movie_title + ' (Score: ' + similarity_score + ')')
    
  2. Eseguire la cella di codice 10. Verrà visualizzato l'output seguente:

    Remote Control (Score: 0.8301)
    Meet Dave (Score: 0.8236)
    Elf-Man (Score: 0.8208)
    Fifty/Fifty (Score: 0.8167)
    Mars Attacks! (Score: 0.8165)
    Strange Invaders (Score: 0.8143)
    Amanda and the Alien (Score: 0.8136)
    Suburban Commando (Score: 0.8129)
    Coneheads (Score: 0.8129)
    Morons from Outer Space (Score: 0.8121)
    

Con Cache Redis di Azure e il servizio Azure OpenAI, è possibile usare incorporamenti e ricerca vettoriale per aggiungere funzionalità di ricerca avanzate all'applicazione.

Pulire le risorse

Per continuare a usare le risorse create in questo articolo, mantenere il gruppo di risorse.

In caso contrario, se le risorse sono state completate, per evitare addebiti è possibile eliminare il gruppo di risorse di Azure creato.

Importante

L'eliminazione di un gruppo di risorse è irreversibile. Quando si elimina un gruppo di risorse, tutte le risorse in esso contenute vengono eliminate in modo permanente. Assicurarsi di non eliminare accidentalmente il gruppo di risorse sbagliato o le risorse errate. Se le risorse sono state create all'interno di un gruppo di risorse esistente che contiene anche elementi da mantenere, è possibile eliminare ogni singolo elemento a sinistra anziché eliminare il gruppo di risorse.

Per eliminare un gruppo di risorse

  1. Accedere al portale di Azure e selezionare Gruppi di risorse.

  2. Scegliere il gruppo di risorse da eliminare.

    Se sono presenti molti gruppi di risorse, usare la casella Filtro per qualsiasi campo... e digitare il nome del gruppo di risorse creato per questo articolo. Nell’elenco dei risultati selezionare il gruppo di risorse.

    Screenshot che mostra nel riquadro di lavoro un elenco dei gruppi di risorse da eliminare.

  3. Selezionare Elimina gruppo di risorse.

  4. Verrà chiesto di confermare l'eliminazione del gruppo di risorse. Digitare il nome del gruppo di risorse per confermare e quindi selezionare Elimina.

    Screenshot che mostra un modulo richiedente il nome della risorsa per confermare l'eliminazione.

Dopo qualche istante, il gruppo di risorse e tutte le risorse che contiene vengono eliminati.