Share via


Självstudie: Utforska inbäddningar och dokumentsökning i Azure OpenAI-tjänsten

Den här självstudien beskriver hur du använder API:et för Inbäddning av Azure OpenAI för att utföra dokumentsökning där du frågar en kunskapsbas för att hitta det mest relevanta dokumentet.

I den här självstudien lär du dig att:

  • Installera Azure OpenAI.
  • Ladda ned en exempeldatauppsättning och förbered den för analys.
  • Skapa miljövariabler för dina resursers slutpunkt och API-nyckel.
  • Använd modellen text-embedding-ada-002 (version 2)
  • Använd cosinélikhet för att rangordna sökresultat.

Förutsättningar

  • En Azure-prenumeration – Skapa en kostnadsfritt
  • Åtkomst beviljad till Azure OpenAI i den önskade Azure-prenumerationen. För närvarande måste man ansöka om att få åtkomst till den här tjänsten. Du kan ansöka om åtkomst till Azure OpenAI genom att fylla i formuläret på https://aka.ms/oai/access. Öppna ett problem på den här lagringsplatsen för att kontakta oss om du har ett problem.
  • En Azure OpenAI-resurs med modellen text-embedding-ada-002 (version 2) distribuerad. Den här modellen är för närvarande endast tillgänglig i vissa regioner. Om du inte har en resurs dokumenteras processen för att skapa en i vår resursdistributionsguide.
  • Python 3.8 eller senare version
  • Följande Python-bibliotek: openai, num2words, matplotlib, plotly, scipy, scikit-learn, pandas, tiktoken.
  • Jupyter Notebook

Konfigurera

Python-bibliotek

Om du inte redan har gjort det måste du installera följande bibliotek:

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

Ladda ned BillSum-datauppsättningen

BillSum är en datamängd av USA kongress- och Kaliforniens delstatsräkningar. I illustrationssyfte tittar vi bara på de amerikanska räkningarna. Corpus består av räkningar från kongressens 103:e-115:e (1993-2018). Uppgifterna delades upp i 18 949 tågräkningar och 3 269 testräkningar. BillSum corpus fokuserar på mellanlängdslagstiftning från 5 000 till 20 000 tecken. Mer information om projektet och den ursprungliga akademiska uppsatsen där den här datamängden härleds från finns på BillSum-projektets GitHub-lagringsplats

I den här självstudien bill_sum_data.csv används filen som kan laddas ned från våra GitHub-exempeldata.

Du kan också ladda ned exempeldata genom att köra följande kommando på den lokala datorn:

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

Hämta nyckel och slutpunkt

Om du vill göra ett anrop mot Azure OpenAI behöver du en slutpunkt och en nyckel.

Variabelnamn Värde
ENDPOINT Det här värdet finns i avsnittet Nycklar och slutpunkt när du undersöker resursen från Azure-portalen. Du kan också hitta värdet i Azure OpenAI Studio>Playground Code>View. En exempelslutpunkt är: https://docs-test-001.openai.azure.com/.
API-KEY Det här värdet finns i avsnittet Nycklar och slutpunkt när du undersöker resursen från Azure-portalen. Du kan använda antingen KEY1 eller KEY2.

Gå till din resurs i Azure-portalen. Avsnittet Nycklar och slutpunkter finns i avsnittet Resurshantering . Kopiera slutpunkten och åtkomstnyckeln eftersom du behöver båda för att autentisera dina API-anrop. Du kan använda antingen KEY1 eller KEY2. Om du alltid har två nycklar kan du rotera och återskapa nycklar på ett säkert sätt utan att orsaka avbrott i tjänsten.

Skärmbild av översiktsgränssnittet för en Azure OpenAI-resurs i Azure-portalen med slutpunkten och åtkomstnycklarna inringade i rött.

Miljövariabler

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

När du har angett miljövariablerna kan du behöva stänga och öppna Jupyter Notebooks igen eller den IDE du använder för att miljövariablerna ska vara tillgängliga. Vi rekommenderar starkt att du använder Jupyter Notebooks, men om du av någon anledning inte kan behöva ändra någon kod som returnerar en Pandas-dataram med hjälp print(dataframe_name) av i stället för att bara anropa dataframe_name direkt som ofta görs i slutet av ett kodblock.

Kör följande kod i din föredragna Python IDE:

Importera bibliotek

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 måste vi läsa csv-filen och skapa en Pandas DataFrame. När den första DataFrame har skapats kan vi visa innehållet i tabellen genom att köra 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

Produktionen:

Skärmbild av de första DataFrame-tabellresultaten från csv-filen.

Den inledande tabellen har fler kolumner än vi behöver, vi skapar en ny mindre DataFrame med namnet df_bills som endast innehåller kolumnerna för text, summaryoch title.

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

Produktionen:

Skärmbild av de mindre DataFrame-tabellresultaten med endast text-, sammanfattnings- och rubrikkolumner.

Nu ska vi utföra viss rensning av lätta data genom att ta bort redundant tomt utrymme och rensa skiljetecken för att förbereda data för tokenisering.

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 måste vi ta bort alla fakturor som är för långa för tokengränsen (8 192 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

Kommentar

I det här fallet ligger alla fakturor under inbäddningsmodellens indatatokengräns, men du kan använda metoden ovan för att ta bort poster som annars skulle leda till att inbäddningen misslyckas. När du ställs inför innehåll som överskrider inbäddningsgränsen kan du även segmentera innehållet i mindre delar och sedan bädda in dem i taget.

Vi ska än en gång undersöka df_bills.

df_bills

Produktionen:

Skärmbild av DataFrame med en ny kolumn med namnet n_tokens.

För att förstå n_tokens kolumnen lite mer och hur texten i slutändan tokeniseras kan det vara bra att köra följande kod:

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

För våra dokument trunkerar vi avsiktligt utdata, men om du kör det här kommandot i din miljö returneras den fullständiga texten från indexet noll tokeniserat till segment. Du kan se att ett helt ord i vissa fall representeras med en enda token medan delar av ord i andra delar delas upp i flera 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',

Om du sedan kontrollerar längden på variabeln decode ser du att den matchar det första talet i kolumnen n_tokens.

len(decode)
1466

Nu när vi förstår mer om hur tokenisering fungerar kan vi gå vidare till inbäddning. Det är viktigt att notera att vi inte har tokeniserat dokumenten ännu. Kolumnen n_tokens är helt enkelt ett sätt att se till att ingen av de data som vi skickar till modellen för tokenisering och inbäddning överskrider gränsen för indatatoken på 8 192. När vi skickar dokumenten till inbäddningsmodellen delas dokumenten upp i token som liknar (men inte nödvändigtvis identiska) med exemplen ovan och konverterar sedan token till en serie flyttalsnummer som kan nås via vektorsökning. Dessa inbäddningar kan lagras lokalt eller i en Azure Database för att stödja Vector Search. Därför har varje faktura sin egen motsvarande inbäddningsvektor i den nya ada_v2 kolumnen till höger om DataFrame.

I exemplet nedan anropar vi inbäddningsmodellen en gång per varje objekt som vi vill bädda in. När du arbetar med stora inbäddningsprojekt kan du också skicka modellen en matris med indata för att bädda in i stället för en indata i taget. När du skickar modellen är en matris med indata det maximala antalet indataobjekt per anrop till inbäddningsslutpunkten 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

Produktionen:

Skärmbild av de formaterade resultaten från kommandot df_bills.

När vi kör sökkodsblocket nedan bäddar vi in sökfrågan "Kan jag få information om skatteintäkter från kabelföretag?" med samma modell för textinbäddning-ada-002 (version 2). Härnäst hittar vi den närmaste fakturainbäddningen till den nyligen inbäddade texten från vår fråga rangordnad efter cosinna likhet.

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)

Utdata:

Skärmbild av formaterade resultat av res när sökfrågan har körts.

Slutligen visar vi det översta resultatet från dokumentsökning baserat på användarfråga mot hela kunskapsbas. Detta returnerar det högsta resultatet av "Skattebetalarnas rätt att se lagen från 1993". Det här dokumentet har en samexisteringspoäng på 0,76 mellan frågan och dokumentet:

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

Förutsättningar

  • En Azure-prenumeration – Skapa en kostnadsfritt

  • Åtkomst beviljad till Azure OpenAI i den önskade Azure-prenumerationen.

    För närvarande måste man ansöka om att få åtkomst till den här tjänsten. Du kan ansöka om åtkomst till Azure OpenAI genom att fylla i formuläret på https://aka.ms/oai/access. Öppna ett problem på den här lagringsplatsen för att kontakta oss om du har ett problem.

  • En Azure OpenAI-resurs med modellen text-embedding-ada-002 (version 2) distribuerad.

    Den här modellen är för närvarande endast tillgänglig i vissa regioner. Om du inte har en resurs dokumenteras processen för att skapa en i vår resursdistributionsguide.

  • PowerShell 7.4

Kommentar

Många exempel i den här självstudien återanvänder variabler från steg till steg. Håll samma terminalsession öppen hela vägen. Om variabler som du angav i ett tidigare steg går förlorade på grund av att terminalen stängs måste du börja om från början.

Hämta nyckel och slutpunkt

Om du vill göra ett anrop mot Azure OpenAI behöver du en slutpunkt och en nyckel.

Variabelnamn Värde
ENDPOINT Det här värdet finns i avsnittet Nycklar och slutpunkt när du undersöker resursen från Azure-portalen. Du kan också hitta värdet i Azure OpenAI Studio>Playground Code>View. En exempelslutpunkt är: https://docs-test-001.openai.azure.com/.
API-KEY Det här värdet finns i avsnittet Nycklar och slutpunkt när du undersöker resursen från Azure-portalen. Du kan använda antingen KEY1 eller KEY2.

Gå till din resurs i Azure-portalen. Avsnittet Nycklar och slutpunkter finns i avsnittet Resurshantering . Kopiera slutpunkten och åtkomstnyckeln eftersom du behöver båda för att autentisera dina API-anrop. Du kan använda antingen KEY1 eller KEY2. Om du alltid har två nycklar kan du rotera och återskapa nycklar på ett säkert sätt utan att orsaka avbrott i tjänsten.

Skärmbild av översiktsgränssnittet för en Azure OpenAI-resurs i Azure-portalen med slutpunkten och åtkomstnycklarna inringade i rött.

Skapa och tilldela beständiga miljövariabler för din nyckel och slutpunkt.

Miljövariabler

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

I den här självstudien använder vi PowerShell 7.4-referensdokumentationen som en välkänd och säker exempeldatauppsättning. Som ett alternativ kan du välja att utforska exempeldatauppsättningar för Microsoft Research-verktyg .

Skapa en mapp där du vill lagra projektet. Ange din plats till projektmappen. Ladda ned datamängden till den lokala datorn med kommandot Invoke-WebRequest och expandera sedan arkivet. Senast anger du platsen till undermappen som innehåller referensinformation för PowerShell version 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/'

Vi arbetar med en stor mängd data i den här självstudien, så vi använder ett .NET-datatabellobjekt för effektiv prestanda. Datatabellen har kolumnernas rubrik, innehåll, förberedelse, URI, fil och vektorer. Rubrikkolumnen är den primära nyckeln.

I nästa steg läser vi in innehållet i varje markdown-fil i datatabellen. Vi använder också PowerShell-operatorn -match för att samla in kända textrader title: och online version:och lagra dem i distinkta kolumner. Vissa av filerna innehåller inte metadataraderna i text, men eftersom de är översiktssidor och inte detaljerade referensdokument utesluter vi dem från datatabellen.

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

Visa data med kommandot out-gridview (inte tillgängligt i Cloud Shell).

$Datatable | out-gridview

Utdata:

Skärmbild av de första DataTable-resultaten.

Utför sedan lite ljus datarensning genom att ta bort extra tecken, tomt utrymme och andra dokumentnotationer för att förbereda data för tokenisering. Exempelfunktionen Invoke-DocPrep visar hur du använder PowerShell-operatorn -replace för att iterera genom en lista med tecken som du vill ta bort från innehållet.

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

När du har skapat Invoke-DocPrep funktionen använder ForEach-Object du kommandot för att lagra förberett innehåll i förberedelsekolumnen för alla rader i datatabellen. Vi använder en ny kolumn så att den ursprungliga formateringen är tillgänglig om vi vill hämta den senare.

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

Visa datatabellen igen för att se ändringen.

$Datatable | out-gridview

När vi skickar dokumenten till inbäddningsmodellen kodas dokumenten till tokens och returnerar sedan en serie flyttalsnummer som ska användas i en cosinélikhetssökning . Dessa inbäddningar kan lagras lokalt eller i en tjänst, till exempel Vector Search i Azure AI Search. Varje dokument har en egen motsvarande inbäddningsvektor i den nya vektorkolumnen .

Nästa exempel loopar igenom varje rad i datatabellen, hämtar vektorerna för det förbearbetade innehållet och lagrar dem i vektorkolumnen. OpenAI-tjänsten begränsar frekventa begäranden, så exemplet innehåller en exponentiell back-off enligt vad som föreslås i dokumentationen.

När skriptet är klart ska varje rad ha en kommaavgränsad lista med 1 536 vektorer för varje dokument. Om ett fel inträffar och statuskoden är 400läggs filsökvägen, rubriken och felkoden till i en variabel med namnet $errorDocs för felsökning. Det vanligaste felet uppstår när antalet token är mer än promptgränsen för modellen.

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

Nu har du en lokal minnesintern databastabell med PowerShell 7.4-referensdokument.

Baserat på en söksträng måste vi beräkna en annan uppsättning vektorer så att PowerShell kan rangordna varje dokument efter likhet.

I nästa exempel hämtas vektorer för söksträngen 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 ','

Slutligen utför nästa exempelfunktion, som lånar ett exempel från exempelskriptet Measure-VectorSimilarity skrivet av Lee Holmes, en cosinuslikhetsberäkning och rangordnar sedan varje rad i datatabellen.

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

Kommandona i nästa exempel loopar igenom alla rader i $Datatable och beräknar cosinélikiteten för söksträngen. Resultaten sorteras och de tre främsta resultaten lagras i en variabel med namnet $topThree. Exemplet returnerar inte utdata.

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

Granska utdata för variabeln $topThree , med endast egenskaper för rubrik och URL , i gridview.

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

Produktionen:

Skärmbild av de formaterade resultaten när sökfrågan är klar.

Variabeln $topThree innehåller all information från raderna i datatabellen. Innehållsegenskapen innehåller till exempel det ursprungliga dokumentformatet. Använd [0] för att indexera till det första objektet i matrisen.

$topThree[0].content

Visa det fullständiga dokumentet (trunkerat i utdatafragmentet för den här sidan).

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

I stället för att återskapa inbäddningarna varje gång du behöver köra frågor mot datauppsättningen kan du lagra data på disken och återkalla dem i framtiden. Metoderna WriteXML() och ReadXML() för DataTable-objekttyper i nästa exempel förenklar processen. Schemat för XML-filen kräver att datatabellen har ett TableName.

Ersätt <YOUR-FULL-FILE-PATH> med den fullständiga sökvägen där du vill skriva och läsa XML-filen. Sökvägen ska sluta med .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>")

När du återanvänder data måste du hämta vektorerna för varje ny söksträng (men inte hela datatabellen). Som en inlärningsövning kan du prova att skapa ett PowerShell-skript för att automatisera Invoke-RestMethod kommandot med söksträngen som en parameter.

Med den här metoden kan du använda inbäddningar som en sökmekanism i dokument i en kunskapsbas. Användaren kan sedan ta det översta sökresultatet och använda det för sin underordnade uppgift, vilket föranledde deras första fråga.

Rensa resurser

Om du har skapat en Azure OpenAI-resurs enbart för att slutföra den här självstudien och vill rensa och ta bort en Azure OpenAI-resurs måste du ta bort dina distribuerade modeller och sedan ta bort resursen eller den associerade resursgruppen om den är dedikerad till testresursen. Om du tar bort resursgruppen tas även alla andra resurser som är associerade med den bort.

Nästa steg

Läs mer om Azure OpenAI:s modeller: