Zelfstudie: Azure OpenAI Service-insluitingen en documentzoekopdrachten verkennen

In deze zelfstudie leert u hoe u de Azure OpenAI embeddings-API gebruikt om documentzoekopdrachten uit te voeren waar u een query uitvoert op een knowledge base om het meest relevante document te vinden.

In deze zelfstudie leert u het volgende:

  • Installeer Azure OpenAI.
  • Download een voorbeeldgegevensset en bereid deze voor op analyse.
  • Maak omgevingsvariabelen voor uw resources-eindpunt en API-sleutel.
  • Het model text-embedding-ada-002 (versie 2) gebruiken
  • Gebruik cosinus-gelijkenis om zoekresultaten te rangschikken.

Vereisten

  • Een Azure-abonnement - Een gratis abonnement maken
  • Toegang verleend tot Azure OpenAI in het gewenste Azure abonnement. Op dit moment wordt alleen toegang tot deze service verleend door een aanvraag te doen. U kunt toegang tot Azure OpenAI aanvragen door het formulier in te vullen op https://aka.ms/oai/access. Open een probleem op deze opslagplaats om contact met ons op te stellen als u een probleem hebt.
  • Een Azure OpenAI-resource met het geïmplementeerde model text-embedding-ada-002 (versie 2 ). Dit model is momenteel alleen beschikbaar in bepaalde regio's. Als u geen resource hebt, wordt het proces voor het maken van een resource gedocumenteerd in onze handleiding voor resource-implementatie.
  • Python 3.8 of nieuwere versie
  • De volgende Python-bibliotheken: openai, num2words, matplotlib, plotly, scipy, scikit-learn, pandas, tiktoken.
  • Jupyter Notebooks

Instellingen

Python-bibliotheken

Als u dat nog niet hebt gedaan, moet u de volgende bibliotheken installeren:

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

De BillSum-gegevensset downloaden

BillSum is een gegevensset van Verenigde Staten staatsrekeningen van congressen en Californië. Ter illustratie kijken we alleen naar de Amerikaanse rekeningen. Het corpus bestaat uit rekeningen van de 103e-115e (1993-2018) sessies van congres. De gegevens zijn gesplitst in 18.949 treinfactuur en 3.269 testfactuur. De BillSum-verzameling richt zich op de mid-length wetgeving van 5.000 tot 20.000 tekens lang. Meer informatie over het project en het oorspronkelijke academische document waaruit deze gegevensset is afgeleid, vindt u in de GitHub-opslagplaats van het BillSum-project

In deze zelfstudie wordt het bill_sum_data.csv bestand gebruikt dat kan worden gedownload uit onze GitHub-voorbeeldgegevens.

U kunt de voorbeeldgegevens ook downloaden door de volgende opdracht uit te voeren op uw lokale computer:

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

Sleutel en eindpunt ophalen

Als u azure OpenAI wilt aanroepen, hebt u een eindpunt en een sleutel nodig.

Naam van de variabele Waarde
ENDPOINT Deze waarde vindt u in de sectie Sleutels en eindpunt bij het onderzoeken van uw resource vanuit de Azure Portal. U kunt ook de waarde vinden in de codeweergave van Azure OpenAI Studio>Playground>. Een voorbeeldeindpunt is: https://docs-test-001.openai.azure.com/.
API-KEY Deze waarde vindt u in de sectie Sleutels en eindpunt bij het onderzoeken van uw resource vanuit de Azure Portal. U kunt KEY1 of KEY2 gebruiken.

Ga naar uw resource in Azure Portal. De sectie Sleutels en eindpunt vindt u in de sectie Resourcebeheer . Kopieer uw eindpunt en toegangssleutel, omdat u beide nodig hebt voor het verifiëren van uw API-aanroepen. U kunt KEY1 of KEY2 gebruiken. Als u altijd twee sleutels hebt, kunt u sleutels veilig roteren en opnieuw genereren zonder een serviceonderbreking te veroorzaken.

Schermopname van de overzichtsgebruikersinterface voor een Azure OpenAI-resource in Azure Portal met het eindpunt en de locatie van toegangssleutels die rood zijn omcirkeld.

Omgevingsvariabelen

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Nadat u de omgevingsvariabelen hebt ingesteld, moet u mogelijk Jupyter-notebooks sluiten en opnieuw openen of welke IDE u gebruikt om de omgevingsvariabelen toegankelijk te maken. Hoewel we het gebruik van Jupyter Notebooks ten zeerste aanbevelen, moet u, om een of andere reden, geen code wijzigen die een pandas-dataframe retourneert door print(dataframe_name) het dataframe_name rechtstreeks aan te roepen, zoals vaak wordt gedaan aan het einde van een codeblok.

Voer de volgende code uit in de Python IDE van uw voorkeur:

Bibliotheken importeren

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

Nu moeten we ons CSV-bestand lezen en een Pandas DataFrame maken. Nadat het eerste DataFrame is gemaakt, kunnen we de inhoud van de tabel bekijken door deze uit te voeren 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

Uitvoer:

Schermopname van de eerste DataFrame-tabelresultaten uit het CSV-bestand.

De eerste tabel bevat meer kolommen dan we nodig hebben, we maken een nieuw kleiner DataFrame df_bills dat alleen de kolommen voor text, summaryen titlebevat.

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

Uitvoer:

Schermopname van de kleinere resultaten van de DataFrame-tabel met alleen tekst-, samenvattings- en titelkolommen weergegeven.

Vervolgens gaan we licht gegevens opschonen door redundante witruimte te verwijderen en de interpunctie op te schonen om de gegevens voor te bereiden op tokenisatie.

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

Nu moeten we alle facturen verwijderen die te lang zijn voor de tokenlimiet (8192 tokens).

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

Notitie

In dit geval vallen alle facturen onder de limiet voor invoertoken van het insluitmodel, maar u kunt de bovenstaande techniek gebruiken om vermeldingen te verwijderen die anders ertoe leiden dat insluiten mislukt. Wanneer u te maken hebt met inhoud die de limiet voor insluiten overschrijdt, kunt u de inhoud ook in kleinere stukken segmenteren en deze vervolgens één voor één insluiten.

We onderzoeken nogmaals df_bills.

df_bills

Uitvoer:

Schermopname van het DataFrame met een nieuwe kolom met de naam n_tokens.

Als u meer inzicht wilt in de n_tokens kolom en hoe tekst uiteindelijk wordt getokeniseerd, kan het handig zijn om de volgende code uit te voeren:

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

Voor onze documenten wordt de uitvoer opzettelijk afgekapt, maar als u deze opdracht uitvoert in uw omgeving, wordt de volledige tekst geretourneerd van index nultokenized in segmenten. In sommige gevallen ziet u dat een heel woord wordt weergegeven met één token, terwijl in andere delen van woorden meerdere tokens worden gesplitst.

[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',

Als u vervolgens de lengte van de decode variabele controleert, ziet u dat deze overeenkomt met het eerste getal in de kolom n_tokens.

len(decode)
1466

Nu we meer weten over hoe tokenisatie werkt, kunnen we doorgaan met insluiten. Het is belangrijk om te weten dat we de documenten nog niet hebben tokeneerd. De n_tokens kolom is gewoon een manier om ervoor te zorgen dat geen van de gegevens die we doorgeven aan het model voor tokenisatie en insluiten de limiet van het invoertoken van 8.192 overschrijdt. Wanneer we de documenten doorgeven aan het insluitingsmodel, worden de documenten opgesplitst in tokens die vergelijkbaar zijn (hoewel niet noodzakelijkerwijs identiek) aan de bovenstaande voorbeelden en worden de tokens vervolgens geconverteerd naar een reeks drijvendekommanummers die toegankelijk zijn via vectorzoekopdrachten. Deze insluitingen kunnen lokaal of in een Azure Database worden opgeslagen ter ondersteuning van Vector Search. Als gevolg hiervan heeft elke factuur een eigen bijbehorende insluitingsvector in de nieuwe ada_v2 kolom aan de rechterkant van het DataFrame.

In het onderstaande voorbeeld roepen we het insluitmodel één keer aan per item dat we willen insluiten. Wanneer u met grote insluitingsprojecten werkt, kunt u het model ook doorgeven aan een matrix met invoer die moet worden ingesloten in plaats van één invoer tegelijk. Wanneer u het model doorgeeft, is het maximum aantal invoeritems per aanroep naar het eindpunt voor insluiten 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

Uitvoer:

Schermopname van de opgemaakte resultaten van df_bills opdracht.

Terwijl we het onderstaande zoekcodeblok uitvoeren, sluiten we de zoekquery 'Kan ik informatie krijgen over belastingopbrengsten van kabelmaatschappij?' in. met hetzelfde model voor tekst-embedding-ada-002 (versie 2). Vervolgens vinden we het dichtstbijzijnde insluiten van facturen voor de zojuist ingesloten tekst uit onze query, gerangschikt op cosinus-gelijkenis.

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)

Uitvoer:

Schermopname van de opgemaakte resultaten van res zodra de zoekquery is uitgevoerd.

Ten slotte tonen we het belangrijkste resultaat van documentzoekopdrachten op basis van de gebruikersquery op basis van de hele Knowledge Base. Dit retourneert het belangrijkste resultaat van de "Belastingbetalerrecht om wet van 1993 te bekijken". Dit document heeft een cosinus-overeenkomstscore van 0,76 tussen de query en het document:

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."

Vereisten

  • Een Azure-abonnement - Een gratis abonnement maken

  • Toegang verleend tot Azure OpenAI in het gewenste Azure abonnement.

    Op dit moment wordt alleen toegang tot deze service verleend door een aanvraag te doen. U kunt toegang tot Azure OpenAI aanvragen door het formulier in te vullen op https://aka.ms/oai/access. Open een probleem op deze opslagplaats om contact met ons op te stellen als u een probleem hebt.

  • Een Azure OpenAI-resource met het geïmplementeerde model text-embedding-ada-002 (versie 2 ).

    Dit model is momenteel alleen beschikbaar in bepaalde regio's. Als u geen resource hebt, wordt het proces voor het maken van een resource gedocumenteerd in onze handleiding voor resource-implementatie.

  • PowerShell 7.4

Notitie

Veel voorbeelden in deze zelfstudie gebruiken variabelen van stap tot stap opnieuw. Houd dezelfde terminalsessie open. Als variabelen die u in een vorige stap hebt ingesteld, verloren gaan als gevolg van het sluiten van de terminal, moet u opnieuw beginnen vanaf het begin.

Sleutel en eindpunt ophalen

Als u azure OpenAI wilt aanroepen, hebt u een eindpunt en een sleutel nodig.

Naam van de variabele Waarde
ENDPOINT Deze waarde vindt u in de sectie Sleutels en eindpunt bij het onderzoeken van uw resource vanuit de Azure Portal. U kunt ook de waarde vinden in de codeweergave van Azure OpenAI Studio>Playground>. Een voorbeeldeindpunt is: https://docs-test-001.openai.azure.com/.
API-KEY Deze waarde vindt u in de sectie Sleutels en eindpunt bij het onderzoeken van uw resource vanuit de Azure Portal. U kunt KEY1 of KEY2 gebruiken.

Ga naar uw resource in Azure Portal. De sectie Sleutels en eindpunt vindt u in de sectie Resourcebeheer . Kopieer uw eindpunt en toegangssleutel, omdat u beide nodig hebt voor het verifiëren van uw API-aanroepen. U kunt KEY1 of KEY2 gebruiken. Als u altijd twee sleutels hebt, kunt u sleutels veilig roteren en opnieuw genereren zonder een serviceonderbreking te veroorzaken.

Schermopname van de overzichtsgebruikersinterface voor een Azure OpenAI-resource in Azure Portal met het eindpunt en de locatie van toegangssleutels die rood zijn omcirkeld.

Maak en wijs permanente omgevingsvariabelen toe voor uw sleutel en eindpunt.

Omgevingsvariabelen

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Voor deze zelfstudie gebruiken we de powerShell 7.4-referentiedocumentatie als een bekende en veilige voorbeeldgegevensset. U kunt er ook voor kiezen om de voorbeeldgegevenssets van Microsoft Research-hulpprogramma's te verkennen.

Maak een map waarin u uw project wilt opslaan. Stel uw locatie in op de projectmap. Download de gegevensset naar uw lokale computer met behulp van de Invoke-WebRequest opdracht en vouw vervolgens het archief uit. Stel ten slotte uw locatie in op de submap met referentiegegevens voor PowerShell versie 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 deze zelfstudie werken we met een grote hoeveelheid gegevens, dus we gebruiken een .NET-gegevenstabelobject voor efficiënte prestaties. De gegevenstabel heeft een kolomtitel, inhoud, voorbereiding, URI, bestand en vectoren. De titelkolom is de primaire sleutel.

In de volgende stap laden we de inhoud van elk Markdown-bestand in de gegevenstabel. We gebruiken ook de PowerShell-operator -match om bekende regels tekst title: vast te leggen en online version:om deze op te slaan in afzonderlijke kolommen. Sommige bestanden bevatten niet de metagegevensregels tekst, maar omdat ze overzichtspagina's zijn en geen gedetailleerde referentiedocumenten, sluiten we ze uit van de gegevenstabel.

# 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)
    }
}

Bekijk de gegevens met behulp van de out-gridview opdracht (niet beschikbaar in Cloud Shell).

$Datatable | out-gridview

Uitvoer:

Schermopname van de eerste gegevenstabelresultaten.

Voer vervolgens lichte gegevens op door extra tekens, lege ruimte en andere documentvermeldingen te verwijderen om de gegevens voor te bereiden op tokenisatie. De voorbeeldfunctie Invoke-DocPrep laat zien hoe u de PowerShell-operator -replace gebruikt om een lijst met tekens te doorlopen die u uit de inhoud wilt verwijderen.

# 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
}

Nadat u de functie hebt gemaakt, gebruikt u de Invoke-DocPrepForEach-Object opdracht om voorbereide inhoud op te slaan in de prepkolom , voor alle rijen in de gegevenstabel. We gebruiken een nieuwe kolom, zodat de oorspronkelijke opmaak beschikbaar is als we deze later willen ophalen.

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

Bekijk de gegevenstabel opnieuw om de wijziging te zien.

$Datatable | out-gridview

Wanneer we de documenten doorgeven aan het insluitingsmodel, worden de documenten gecodeerd in tokens en wordt vervolgens een reeks drijvendekommanummers geretourneerd die moeten worden gebruikt in een cosinus-zoekopdracht . Deze insluitingen kunnen lokaal of in een service zoals Vector Search in Azure AI Search worden opgeslagen. Elk document heeft een eigen bijbehorende insluitvector in de kolom nieuwe vectoren .

In het volgende voorbeeld wordt elke rij in de gegevenstabel doorlopen, worden de vectoren voor de vooraf verwerkte inhoud opgehaald en opgeslagen in de kolom vectoren . De OpenAI-service beperkt frequente aanvragen, dus het voorbeeld bevat een exponentiële back-off zoals wordt voorgesteld in de documentatie.

Nadat het script is voltooid, moet elke rij een door komma's gescheiden lijst met 1536 vectoren voor elk document hebben. Als er een fout optreedt en de statuscode is 400, worden het bestandspad, de titel en de foutcode toegevoegd aan een variabele met de naam $errorDocs voor probleemoplossing. De meest voorkomende fout treedt op wanneer het aantal tokens groter is dan de promptlimiet voor het model.

# 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."
}

U hebt nu een lokale in-memory databasetabel met PowerShell 7.4-referentiedocumenten.

Op basis van een zoekreeks moeten we een andere set vectoren berekenen, zodat PowerShell elk document op gelijkenis kan rangschikken.

In het volgende voorbeeld worden vectoren opgehaald voor de zoektekenreeks get a list of running processes.

$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 ','

Ten slotte voert de volgende voorbeeldfunctie, die een voorbeeld uit het voorbeeldscript Measure-VectorSimilarity dat is geschreven door Lee Holmes, een cosinus-gelijkenisberekening uit en rangschikt vervolgens elke rij in de gegevenstabel.

# 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)
}

De opdrachten in het volgende voorbeeld doorlopen alle rijen in $Datatable en berekenen de cosinus-gelijkenis met de zoekreeks. De resultaten worden gesorteerd en de drie belangrijkste resultaten worden opgeslagen in een variabele met de naam $topThree. Het voorbeeld retourneert geen uitvoer.

# 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 }
}

Controleer de uitvoer van de $topThree variabele, met alleen titel - en URL-eigenschappen , in gridview.

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

Uitvoer:

Schermopname van de opgemaakte resultaten zodra de zoekquery is voltooid.

De $topThree variabele bevat alle informatie uit de rijen in de gegevenstabel. De inhoudseigenschap bevat bijvoorbeeld de oorspronkelijke documentindeling. Gebruik [0] dit om te indexeren in het eerste item in de matrix.

$topThree[0].content

Bekijk het volledige document (afgekapt in het uitvoerfragment voor deze 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

Ten slotte kunt u, in plaats van de insluitingen opnieuw te genereren telkens wanneer u een query op de gegevensset moet uitvoeren, de gegevens opslaan op de schijf en deze in de toekomst intrekken. De WriteXML() en ReadXML() methoden van DataTable-objecttypen in het volgende voorbeeld vereenvoudigen het proces. Het schema van het XML-bestand vereist dat de gegevenstabel een TableName heeft.

Vervang <YOUR-FULL-FILE-PATH> door het volledige pad waar u het XML-bestand wilt schrijven en lezen. Het pad moet eindigen op .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>")

Wanneer u de gegevens opnieuw gebruikt, moet u de vectoren van elke nieuwe zoekreeks ophalen (maar niet de hele gegevenstabel). Probeer als leeroefening een PowerShell-script te maken om de Invoke-RestMethod opdracht te automatiseren met de zoekreeks als parameter.

Met deze methode kunt u insluitingen gebruiken als zoekmechanisme voor documenten in een knowledge base. De gebruiker kan vervolgens het bovenste zoekresultaat nemen en gebruiken voor hun downstream-taak, waardoor de eerste query is gevraagd.

Resources opschonen

Als u alleen een Azure OpenAI-resource hebt gemaakt voor het voltooien van deze zelfstudie en u een Azure OpenAI-resource wilt opschonen en verwijderen, moet u de geïmplementeerde modellen verwijderen en vervolgens de resource of de bijbehorende resourcegroep verwijderen als deze is toegewezen aan uw testresource. Als u de resourcegroep verwijdert, worden ook alle bijbehorende resources verwijderd.

Volgende stappen

Meer informatie over de modellen van Azure OpenAI: