Share via


Esercitazione: Esplorare gli incorporamenti e la ricerca documenti del Servizio OpenAI di Azure

Questa esercitazione illustra come usare l'API incorporamenti di Azure OpenAI per eseguire una ricerca documenti in cui si eseguirà una query su una knowledge base per trovare il documento più pertinente.

In questa esercitazione apprenderai a:

  • Installare Azure OpenAI.
  • Scaricare un set di dati di esempio e prepararlo per l'analisi.
  • Creare variabili di ambiente per l'endpoint delle risorse e la chiave API.
  • Usare il modello text-embedding-ada-002 (versione 2)
  • Usare la somiglianza del coseno per classificare i risultati della ricerca.

Prerequisiti

  • Una sottoscrizione di Azure: creare un account gratuitamente
  • Accesso concesso ad Azure OpenAI nella sottoscrizione di Azure desiderata. Attualmente, l'accesso a questo servizio viene concesso solo dall'applicazione. È possibile richiedere l'accesso a OpenAI di Azure completando il modulo all'indirizzo https://aka.ms/oai/access. Apri un problema in questo repository per contattare Microsoft in caso di problemi.
  • Una risorsa OpenAI di Azure con il modello text-embedding-ada-002 (versione 2) distribuito. Questo modello è attualmente disponibile solo in determinate aree. Se non si dispone di una risorsa, il processo di creazione di una risorsa è documentato nella guida alla distribuzione delle risorse.
  • Python 3.8 o versioni successive
  • Le librerie Python seguenti: openai, num2words, matplotlib, plotly, scipy, scikit-learn, pandas, tiktoken.
  • Notebook di Jupyter

Impostazione

Librerie Python

Se non è già stato fatto, è necessario installare le librerie seguenti:

pip install openai num2words matplotlib plotly scipy scikit-learn pandas tiktoken

Scaricare il set di dati BillSum

BillSum è un set di dati di fatture statali del Congresso degli Stati Uniti e della California. A scopo illustrativo, verranno esaminate solo le fatture degli Stati Uniti. Il corpus è costituito da fatture delle sessioni del Congresso n. 103-115 (1993-2018). I dati sono stati suddivisi in 18.949 fatture di training e 3.269 fatture di test. Il corpus BillSum è incentrato sulla legislazione di media lunghezza, da 5.000 a 20.000 caratteri di lunghezza. Altre informazioni sul progetto e sullo studio accademico originale da cui deriva questo set di dati sono disponibili nel repository GitHub del progetto BillSum

Questo tutorial usa il file bill_sum_data.csv, che può essere scaricato dai dati campione di GitHub.

È anche possibile scaricare i dati campione eseguendo il comando seguente nel computer locale:

curl "https://raw.githubusercontent.com/Azure-Samples/Azure-OpenAI-Docs-Samples/main/Samples/Tutorials/Embeddings/data/bill_sum_data.csv" --output bill_sum_data.csv

Recuperare la chiave e l'endpoint

Per effettuare correttamente una chiamata ad Azure OpenAI, sono necessari un endpoint e una chiave.

Nome variabile Valore
ENDPOINT Questo valore è disponibile nella sezione Chiavi &ed endpoint durante l'esame della risorsa dalla portale di Azure. In alternativa, è possibile trovare il valore in OpenAI Studio di Azure>Playground>Visualizzazione codice. Un endpoint di esempio è https://docs-test-001.openai.azure.com/.
API-KEY Questo valore è disponibile nella sezione Chiavi ed endpoint durante l'esame della risorsa dalla portale di Azure. Puoi usare entrambi KEY1 o KEY2.

Passare alla risorsa nel portale di Azure. La sezione Chiavi ed endpoint è disponibile nella sezione Gestione risorse. Copiare l'endpoint e la chiave di accesso in base alle esigenze per l'autenticazione delle chiamate API. Puoi usare entrambi KEY1 o KEY2. Disporre sempre di due chiavi consente di ruotare e rigenerare in modo sicuro le chiavi senza causare un'interruzione del servizio.

Screenshot di panoramica dell'interfaccia utente per una risorsa OpenAI di Azure nel portale di Azure con l'endpoint e la posizione delle chiavi di accesso evidenziati in rosso.

Variabili di ambiente

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Dopo aver impostato le variabili di ambiente, potrebbe essere necessario chiudere e riaprire i notebook di Jupyter o qualsiasi IDE in uso per consentire l'accessibilità delle variabili di ambiente. Sebbene sia consigliabile usare Jupyter Notebooks, se per qualche motivo non è possibile modificare il codice che restituisce un dataframe pandas usando print(dataframe_name) anziché semplicemente chiamare direttamente come dataframe_name spesso avviene alla fine di un blocco di codice.

Eseguire il codice seguente nell'IDE Python di scelta:

Importare le librerie

import os
import re
import requests
import sys
from num2words import num2words
import os
import pandas as pd
import numpy as np
import tiktoken
from openai import AzureOpenAI

Ora, è necessario leggere il file CSV e creare un dataframe pandas. Dopo aver creato il dataframe iniziale, è possibile visualizzare il contenuto della tabella eseguendo df.

df=pd.read_csv(os.path.join(os.getcwd(),'bill_sum_data.csv')) # This assumes that you have placed the bill_sum_data.csv in the same directory you are running Jupyter Notebooks
df

Output:

Screenshot della tabella DataFrame iniziale risultante dal file CSV.

La tabella iniziale include più colonne di quelle necessarie, quindi si creerà un nuovo dataframe più piccolo denominato df_bills, che conterrà solo le colonne per text, summary e title.

df_bills = df[['text', 'summary', 'title']]
df_bills

Output:

Screenshot dei risultati della tabella DataFrame più piccola con solo colonne di testo, riepilogo e titolo visualizzate.

Successivamente, si eseguirà una pulizia dei dati leggeri rimuovendo gli spazi vuoti superflui e ripulendo la punteggiatura in modo da preparare i dati per la tokenizzazione.

pd.options.mode.chained_assignment = None #https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#evaluation-order-matters

# 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_bills['text']= df_bills["text"].apply(lambda x : normalize_text(x))

È ora necessario rimuovere le fatture troppo lunghe per il limite di token (8192 token).

tokenizer = tiktoken.get_encoding("cl100k_base")
df_bills['n_tokens'] = df_bills["text"].apply(lambda x: len(tokenizer.encode(x)))
df_bills = df_bills[df_bills.n_tokens<8192]
len(df_bills)
20

Nota

In questo caso, tutte le fatture si trovano al di sotto del limite di token di input del modello di incorporamento, ma è possibile usare la tecnica precedente per rimuovere le voci che altrimenti causerebbero un errore di incorporamento. Quando il contenuto supera il limite di incorporamento, è anche possibile suddividerlo in parti più piccole e quindi incorporarle una alla volta.

Si esaminerà di nuovo df_bills.

df_bills

Output:

Screenshot del dataframe con una nuova colonna denominata n_tokens.

Per comprendere meglio il funzionamento della colonna n_tokens e come viene tokenizzato il testo, può essere utile eseguire il codice seguente:

sample_encode = tokenizer.encode(df_bills.text[0]) 
decode = tokenizer.decode_tokens_bytes(sample_encode)
decode

Per la documentazione si sta troncando intenzionalmente l'output, ma l'esecuzione di questo comando nell'ambiente restituirà il testo completo dall'indice zero tokenizzato in blocchi. Notare che in alcuni casi un'intera parola è rappresentata con un singolo token, mentre in altri parti di parole vengono suddivise tra più token.

[b'SECTION',
 b' ',
 b'1',
 b'.',
 b' SHORT',
 b' TITLE',
 b'.',
 b' This',
 b' Act',
 b' may',
 b' be',
 b' cited',
 b' as',
 b' the',
 b' ``',
 b'National',
 b' Science',
 b' Education',
 b' Tax',
 b' In',
 b'cent',
 b'ive',
 b' for',
 b' Businesses',
 b' Act',
 b' of',
 b' ',
 b'200',
 b'7',
 b"''.",
 b' SEC',
 b'.',
 b' ',
 b'2',
 b'.',
 b' C',
 b'RED',
 b'ITS',
 b' FOR',
 b' CERT',
 b'AIN',
 b' CONTRIBUT',
 b'IONS',
 b' BEN',
 b'EF',
 b'IT',
 b'ING',
 b' SC',

Se quindi si controlla la lunghezza della variabile decode, si osserverà che questa corrisponde al primo numero nella colonna n_tokens.

len(decode)
1466

Ora che si ha più familiarità con il funzionamento della tokenizzazione, è possibile passare all'incorporamento. È importante notare che i documenti non sono ancora stati tokenizzati. La colonna n_tokens è semplicemente un modo per assicurarsi che nessuno dei dati passati al modello per la tokenizzazione e l'incorporamento superi il limite di token di input di 8.192. Quando si passano i documenti al modello di incorporamento, questi verranno suddivisi in token simili (anche se non necessariamente identici) agli esempi precedenti e quindi i token verranno convertiti in una serie di numeri a virgola mobile che saranno accessibili tramite la ricerca vettoriale. Questi incorporamenti possono essere archiviati in locale o in un database di Azure per supportare La ricerca vettoriale. Di conseguenza, ogni fattura avrà il proprio vettore di incorporamento corrispondente nella nuova colonna ada_v2 a destra del dataframe.

Nell'esempio seguente viene chiamato il modello di incorporamento una volta per ogni elemento da incorporare. Quando si lavora con progetti di incorporamento di grandi dimensioni, in alternativa è possibile passare al modello una matrice di input da incorporare anziché un input alla volta. Quando si passa il modello a una matrice di input, il numero massimo di elementi di input per chiamata all'endpoint di incorporamento è 2048.

client = AzureOpenAI(
  api_key = os.getenv("AZURE_OPENAI_API_KEY"),  
  api_version = "2024-02-01",
  azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
)

def generate_embeddings(text, model="text-embedding-ada-002"): # model = "deployment_name"
    return client.embeddings.create(input = [text], model=model).data[0].embedding

df_bills['ada_v2'] = df_bills["text"].apply(lambda x : generate_embeddings (x, model = 'text-embedding-ada-002')) # model should be set to the deployment name you chose when you deployed the text-embedding-ada-002 (Version 2) model
df_bills

Output:

Screenshot dei risultati formattati del comando df_bills.

Durante l'esecuzione del blocco di codice di ricerca riportato di seguito, si effettuerà l’incorporamento della query di ricerca "È possibile ottenere informazioni sui ricavi fiscali aziendali via cavo?" con lo stesso modello text-embedding-ada-002 (versione 2). A questo punto, è possibile trovare l'incorporamento di fattura che corrisponde più al testo appena incorporato della query, classificato in base alla somiglianza del coseno.

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

def get_embedding(text, model="text-embedding-ada-002"): # model = "deployment_name"
    return client.embeddings.create(input = [text], model=model).data[0].embedding

def search_docs(df, user_query, top_n=4, to_print=True):
    embedding = get_embedding(
        user_query,
        model="text-embedding-ada-002" # model should be set to the deployment name you chose when you deployed the text-embedding-ada-002 (Version 2) model
    )
    df["similarities"] = df.ada_v2.apply(lambda x: cosine_similarity(x, embedding))

    res = (
        df.sort_values("similarities", ascending=False)
        .head(top_n)
    )
    if to_print:
        display(res)
    return res


res = search_docs(df_bills, "Can I get information on cable company tax revenue?", top_n=4)

Output:

Screenshot dei risultati formattati di res dopo l'esecuzione della query di ricerca.

Infine, verrà visualizzato il risultato principale della ricerca di documenti in base alla query dell'utente sull'intera knowledge base. Questo restituisce come risultato principale il "Diritto del contribuente di visualizzare la legge del 1993". Questo documento ha un punteggio di somiglianza coseno pari a 0,76 tra la query e il documento:

res["summary"][9]
"Taxpayer's Right to View Act of 1993 - Amends the Communications Act of 1934 to prohibit a cable operator from assessing separate charges for any video programming of a sporting, theatrical, or other entertainment event if that event is performed at a facility constructed, renovated, or maintained with tax revenues or by an organization that receives public financial support. Authorizes the Federal Communications Commission and local franchising authorities to make determinations concerning the applicability of such prohibition. Sets forth conditions under which a facility is considered to have been constructed, maintained, or renovated with tax revenues. Considers events performed by nonprofit or public organizations that receive tax subsidies to be subject to this Act if the event is sponsored by, or includes the participation of a team that is part of, a tax exempt organization."

Prerequisiti

  • Una sottoscrizione di Azure: creare un account gratuitamente

  • Accesso concesso ad Azure OpenAI nella sottoscrizione di Azure desiderata.

    Attualmente, l'accesso a questo servizio viene concesso solo dall'applicazione. È possibile richiedere l'accesso a OpenAI di Azure completando il modulo all'indirizzo https://aka.ms/oai/access. Apri un problema in questo repository per contattare Microsoft in caso di problemi.

  • Una risorsa OpenAI di Azure con il modello text-embedding-ada-002 (versione 2) distribuito.

    Questo modello è attualmente disponibile solo in determinate aree. Se non si dispone di una risorsa, il processo di creazione di una risorsa è documentato nella guida alla distribuzione delle risorse.

  • PowerShell 7.4

Nota

Molti esempi in questa esercitazione usano nuovamente le variabili da un passaggio all'altro. Mantenere aperta la stessa sessione del terminale. Se le variabili impostate in un passaggio precedente vengono perse a causa della chiusura del terminale, è necessario ricominciare dall'inizio.

Recuperare la chiave e l'endpoint

Per effettuare correttamente una chiamata ad Azure OpenAI, sono necessari un endpoint e una chiave.

Nome variabile Valore
ENDPOINT Questo valore è disponibile nella sezione Chiavi &ed endpoint durante l'esame della risorsa dalla portale di Azure. In alternativa, è possibile trovare il valore in OpenAI Studio di Azure>Playground>Visualizzazione codice. Un endpoint di esempio è https://docs-test-001.openai.azure.com/.
API-KEY Questo valore è disponibile nella sezione Chiavi ed endpoint durante l'esame della risorsa dalla portale di Azure. Puoi usare entrambi KEY1 o KEY2.

Passare alla risorsa nel portale di Azure. La sezione Chiavi ed endpoint è disponibile nella sezione Gestione risorse. Copiare l'endpoint e la chiave di accesso in base alle esigenze per l'autenticazione delle chiamate API. Puoi usare entrambi KEY1 o KEY2. Disporre sempre di due chiavi consente di ruotare e rigenerare in modo sicuro le chiavi senza causare un'interruzione del servizio.

Screenshot di panoramica dell'interfaccia utente per una risorsa OpenAI di Azure nel portale di Azure con l'endpoint e la posizione delle chiavi di accesso evidenziati in rosso.

Creare e assegnare variabili di ambiente persistenti per la chiave e l'endpoint.

Variabili di ambiente

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Per questa esercitazione si usa la documentazione di riferimento di PowerShell 7.4 come set di dati di esempio noto e sicuro. In alternativa, è possibile scegliere di esplorare i set di dati di esempio degli strumenti di Microsoft Research.

Creare una cartella in cui archiviare il progetto. Impostare il percorso sulla cartella del progetto. Scaricare il set di dati nel computer locale usando il Invoke-WebRequest comando e quindi espandere l'archivio. Impostare infine la posizione sulla sottocartella contenente le informazioni di riferimento per PowerShell versione 7.4.

New-Item '<FILE-PATH-TO-YOUR-PROJECT>' -Type Directory
Set-Location '<FILE-PATH-TO-YOUR-PROJECT>'

$DocsUri = 'https://github.com/MicrosoftDocs/PowerShell-Docs/archive/refs/heads/main.zip'
Invoke-WebRequest $DocsUri -OutFile './PSDocs.zip'

Expand-Archive './PSDocs.zip'
Set-Location './PSDocs/PowerShell-Docs-main/reference/7.4/'

In questa esercitazione viene usata una grande quantità di dati, quindi si usa un oggetto tabella dati .NET per ottenere prestazioni efficienti. La tabella dati include il titolo delle colonne, il contenuto, la preparazione, l'URI, il file e i vettori. La colonna title è la chiave primaria.

Nel passaggio successivo si carica il contenuto di ogni file markdown nella tabella dati. Si usa anche l'operatore PowerShell -match per acquisire righe note di testo title: e online version:e archiviarle in colonne distinte. Alcuni file non contengono le righe di testo dei metadati, ma poiché sono pagine di panoramica e non documenti di riferimento dettagliati, vengono esclusi dalla tabella dati.

# make sure your location is the project subfolder

$DataTable = New-Object System.Data.DataTable

'title', 'content', 'prep', 'uri', 'file', 'vectors' | ForEach-Object {
    $DataTable.Columns.Add($_)
} | Out-Null
$DataTable.PrimaryKey = $DataTable.Columns['title']

$md = Get-ChildItem -Path . -Include *.md -Recurse

$md | ForEach-Object {
    $file       = $_.FullName
    $content    = Get-Content $file
    $title      = $content | Where-Object { $_ -match 'title: ' }
    $uri        = $content | Where-Object { $_ -match 'online version: ' }
    if ($title -and $uri) {
        $row                = $DataTable.NewRow()
        $row.title          = $title.ToString().Replace('title: ', '')
        $row.content        = $content | Out-String
        $row.prep           = '' # use later in the tutorial
        $row.uri            = $uri.ToString().Replace('online version: ', '')
        $row.file           = $file
        $row.vectors        = '' # use later in the tutorial
        $Datatable.rows.add($row)
    }
}

Visualizzare i dati usando il out-gridview comando (non disponibile in Cloud Shell).

$Datatable | out-gridview

Output:

Screenshot dei risultati iniziali di DataTable.

Eseguire quindi una pulizia dei dati leggeri rimuovendo caratteri aggiuntivi, spazio vuoto e altre notazioni del documento, per preparare i dati per la tokenizzazione. La funzione Invoke-DocPrep di esempio illustra come usare l'operatore PowerShell -replace per scorrere un elenco di caratteri da rimuovere dal contenuto.

# sample demonstrates how to use `-replace` to remove characters from text content
function Invoke-DocPrep {
param(
    [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
    [string]$content
)
    # tab, line breaks, empty space
    $replace = @('\t','\r\n','\n','\r')
    # non-UTF8 characters
    $replace += @('[^\x00-\x7F]')
    # html
    $replace += @('<table>','</table>','<tr>','</tr>','<td>','</td>')
    $replace += @('<ul>','</ul>','<li>','</li>')
    $replace += @('<p>','</p>','<br>')
    # docs
    $replace += @('\*\*IMPORTANT:\*\*','\*\*NOTE:\*\*')
    $replace += @('<!','no-loc ','text=')
    $replace += @('<--','-->','---','--',':::')
    # markdown
    $replace += @('###','##','#','```')
    $replace | ForEach-Object {
        $content = $content -replace $_, ' ' -replace '  ',' '
    }
    return $content
}

Dopo aver creato la Invoke-DocPrep funzione, usare il ForEach-Object comando per archiviare il contenuto preparato nella colonna di preparazione per tutte le righe della tabella dati. Viene usata una nuova colonna in modo che la formattazione originale sia disponibile se si vuole recuperarla in un secondo momento.

$Datatable.rows | ForEach-Object { $_.prep = Invoke-DocPrep $_.content }

Visualizzare di nuovo la tabella dati per visualizzare la modifica.

$Datatable | out-gridview

Quando passiamo i documenti al modello di incorporamento, codifica i documenti in token e quindi restituisce una serie di numeri a virgola mobile da usare in una ricerca di somiglianza coseno. Questi incorporamenti possono essere archiviati in locale o in un servizio, ad esempio Ricerca vettoriale in Ricerca di intelligenza artificiale di Azure. Ogni documento ha un proprio vettore di incorporamento corrispondente nella nuova colonna vettoriali .

Nell'esempio seguente viene eseguito un ciclo in ogni riga della tabella dati, vengono recuperati i vettori per il contenuto pre-elaborato e archiviati nella colonna vettori . Il servizio OpenAI limita le richieste frequenti, pertanto l'esempio include un back-off esponenziale come suggerito dalla documentazione.

Al termine dello script, ogni riga deve avere un elenco delimitato da virgole di 1536 vettori per ogni documento. Se si verifica un errore e il codice di stato è 400, il percorso del file, il titolo e il codice di errore vengono aggiunti a una variabile denominata $errorDocs per la risoluzione dei problemi. L'errore più comune si verifica quando il numero di token è maggiore del limite di richieste per il modello.

# Azure OpenAI metadata variables
$openai = @{
    api_key     = $Env:AZURE_OPENAI_API_KEY 
    api_base    = $Env:AZURE_OPENAI_ENDPOINT # should look like 'https://<YOUR_RESOURCE_NAME>.openai.azure.com/'
    api_version = '2024-02-01' # may change in the future
    name        = $Env:AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT # custom name you chose for your deployment
}

$headers = [ordered]@{
    'api-key' = $openai.api_key
}

$url = "$($openai.api_base)/openai/deployments/$($openai.name)/embeddings?api-version=$($openai.api_version)"

$Datatable | ForEach-Object {
    $doc = $_

    $body = [ordered]@{
        input = $doc.prep
    } | ConvertTo-Json

    $retryCount = 0
    $maxRetries = 10
    $delay      = 1
    $docErrors = @()

    do {
        try {
            $params = @{
                Uri         = $url
                Headers     = $headers
                Body        = $body
                Method      = 'Post'
                ContentType = 'application/json'
            }
            $response = Invoke-RestMethod @params
            $Datatable.rows.find($doc.title).vectors = $response.data.embedding -join ','
            break
        } catch {
            if ($_.Exception.Response.StatusCode -eq 429) {
                $retryCount++
                [int]$retryAfter = $_.Exception.Response.Headers |
                    Where-Object key -eq 'Retry-After' |
                    Select-Object -ExpandProperty Value

                # Use delay from error header
                if ($delay -lt $retryAfter) { $delay = $retryAfter++ }
                Start-Sleep -Seconds $delay
                # Exponential back-off
                $delay = [math]::min($delay * 1.5, 300)
            } elseif ($_.Exception.Response.StatusCode -eq 400) {
                if ($docErrors.file -notcontains $doc.file) {
                    $docErrors += [ordered]@{
                        error   = $_.exception.ErrorDetails.Message | ForEach-Object error | ForEach-Object message
                        file    = $doc.file
                        title   = $doc.title
                    }
                }
            } else {
                throw
            }
        }
    } while ($retryCount -lt $maxRetries)
}
if (0 -lt $docErrors.count) {
    Write-Host "$($docErrors.count) documents encountered known errors such as too many tokens.`nReview the `$docErrors variable for details."
}

È ora disponibile una tabella di database in memoria locale della documentazione di riferimento di PowerShell 7.4.

In base a una stringa di ricerca, è necessario calcolare un altro set di vettori in modo che PowerShell possa classificare ogni documento in base alla somiglianza.

Nell'esempio seguente i vettori vengono recuperati per la stringa get a list of running processesdi ricerca .

$searchText = "get a list of running processes"

$body = [ordered]@{
    input = $searchText
} | ConvertTo-Json

$url = "$($openai.api_base)/openai/deployments/$($openai.name)/embeddings?api-version=$($openai.api_version)"

$params = @{
    Uri         = $url
    Headers     = $headers
    Body        = $body
    Method      = 'Post'
    ContentType = 'application/json'
}
$response = Invoke-RestMethod @params
$searchVectors = $response.data.embedding -join ','

Infine, la funzione di esempio successiva, che prende in prestito un esempio dallo script di esempio Measure-VectorSimilarity scritto da Lee Holmes, esegue un calcolo di somiglianza coseno e quindi classifica ogni riga nella tabella dati.

# Sample function to calculate cosine similarity
function Get-CosineSimilarity ([float[]]$vector1, [float[]]$vector2) {
    $dot = 0
    $mag1 = 0
    $mag2 = 0

    $allkeys = 0..($vector1.Length-1)

    foreach ($key in $allkeys) {
        $dot  += $vector1[$key]  * $vector2[$key]
        $mag1 += ($vector1[$key] * $vector1[$key])
        $mag2 += ($vector2[$key] * $vector2[$key])
    }

    $mag1 = [Math]::Sqrt($mag1)
    $mag2 = [Math]::Sqrt($mag2)

    return [Math]::Round($dot / ($mag1 * $mag2), 3)
}

I comandi nell'esempio successivo esempligono tutte le righe in $Datatable e calcolano la somiglianza del coseno con la stringa di ricerca. I risultati vengono ordinati e i primi tre risultati vengono archiviati in una variabile denominata $topThree. L'esempio non restituisce l'output.

# Calculate cosine similarity for each row and select the top 3
$topThree = $Datatable | ForEach-Object {
    [PSCustomObject]@{
        title = $_.title
        similarity = Get-CosineSimilarity $_.vectors.split(',') $searchVectors.split(',')
    }
} | Sort-Object -property similarity -descending | Select-Object -First 3 | ForEach-Object {
    $title = $_.title
    $Datatable | Where-Object { $_.title -eq $title }
}

Esaminare l'output della $topThree variabile, con solo le proprietà title e URL , in gridview.

$topThree | Select "title", "uri" | Out-GridView

Output:

Screenshot dei risultati formattati al termine della query di ricerca.

La $topThree variabile contiene tutte le informazioni delle righe nella tabella dati. Ad esempio, la proprietà content contiene il formato originale del documento. Usare [0] per indicizzare nel primo elemento della matrice.

$topThree[0].content

Visualizzare il documento completo (troncato nel frammento di output per questa pagina).

---
external help file: Microsoft.PowerShell.Commands.Management.dll-Help.xml
Locale: en-US
Module Name: Microsoft.PowerShell.Management
ms.date: 07/03/2023
online version: https://learn.microsoft.com/powershell/module/microsoft.powershell.management/get-process?view=powershell-7.4&WT.mc_id=ps-gethelp
schema: 2.0.0
title: Get-Process
---

# Get-Process

## SYNOPSIS
Gets the processes that are running on the local computer.

## SYNTAX

### Name (Default)

Get-Process [[-Name] <String[]>] [-Module] [-FileVersionInfo] [<CommonParameters>]
# truncated example

Infine, invece di rigenerare gli incorporamenti ogni volta che è necessario eseguire query sul set di dati, è possibile archiviare i dati su disco e richiamarli in futuro. I WriteXML() metodi e ReadXML() dei tipi di oggetto DataTable nell'esempio successivo semplificano il processo. Lo schema del file XML richiede che la tabella dati abbia tableName.

Sostituire <YOUR-FULL-FILE-PATH> con il percorso completo in cui si vuole scrivere e leggere il file XML. Il percorso deve terminare con .xml.

# Set DataTable name
$Datatable.TableName = "MyDataTable"

# Writing DataTable to XML
$Datatable.WriteXml("<YOUR-FULL-FILE-PATH>", [System.Data.XmlWriteMode]::WriteSchema)

# Reading XML back to DataTable
$newDatatable = New-Object System.Data.DataTable
$newDatatable.ReadXml("<YOUR-FULL-FILE-PATH>")

Quando si riutilizzano i dati, è necessario ottenere i vettori di ogni nuova stringa di ricerca (ma non l'intera tabella dati). Come esercizio di apprendimento, provare a creare uno script di PowerShell per automatizzare il Invoke-RestMethod comando con la stringa di ricerca come parametro.

Usando questo approccio, è possibile usare gli incorporamenti come meccanismo di ricerca tra documenti in una knowledge base. L'utente può quindi accettare il risultato principale della ricerca e usarlo per l'attività downstream che ha richiesto la query iniziale.

Pulire le risorse

Se è stata creata una risorsa OpenAI di Azure esclusivamente per completare questa esercitazione e si vuole pulire e rimuovere una risorsa OpenAI di Azure, è necessario eliminare i modelli distribuiti e quindi eliminare la risorsa o il gruppo di risorse associato se è dedicato alla risorsa di test. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

Passaggi successivi

Ulteriori informazioni sui modelli di Azure OpenAI: