Samouczek: eksplorowanie osadzania i wyszukiwania dokumentów w usłudze Azure OpenAI Service
Ten samouczek przeprowadzi Cię przez proces korzystania z interfejsu API osadzania usługi Azure OpenAI w celu przeprowadzenia wyszukiwania dokumentów, w którym wykonasz zapytanie dotyczące baza wiedzy w celu znalezienia najbardziej odpowiedniego dokumentu.
Z tego samouczka dowiesz się, jak wykonywać następujące czynności:
- Zainstaluj usługę Azure OpenAI.
- Pobierz przykładowy zestaw danych i przygotuj go do analizy.
- Utwórz zmienne środowiskowe dla punktu końcowego zasobów i klucza interfejsu API.
- Użyj jednego z następujących modeli: osadzanie tekstu-ada-002 (wersja 2), osadzanie tekstu-3-large, osadzanie tekstu-3-duże, osadzanie tekstu-3-małe modele.
- Użyj podobieństwa cosinus, aby sklasyfikować wyniki wyszukiwania.
Wymagania wstępne
- Subskrypcja platformy Azure — utwórz bezpłatnie
- Zasób usługi Azure OpenAI z wdrożonym modelem osadzania tekstu ada-002 (wersja 2). Ten model jest obecnie dostępny tylko w niektórych regionach. Jeśli nie masz zasobu, proces tworzenia zasobu jest udokumentowany w naszym przewodniku wdrażania zasobów.
- Środowisko Python w wersji 3.8 lub nowszej
- Następujące biblioteki języka Python: openai, num2words, matplotlib, plotly, scipy, scikit-learn, pandas, tiktoken.
- Notesy programu Jupyter
Konfiguruj
Biblioteki języka Python
Jeśli jeszcze tego nie zrobiono, musisz zainstalować następujące biblioteki:
pip install openai num2words matplotlib plotly scipy scikit-learn pandas tiktoken
Pobieranie zestawu danych BillSum
BillSum jest zestawem danych Stany Zjednoczone Kongresu i Kalifornii ustaw stanowych. W celach ilustracyjnych przyjrzymy się tylko rachunkom amerykańskim. Korpus składa się z rachunków z 103-115(1993-2018) sesji Kongresu. Dane zostały podzielone na 18 949 rachunków za pociągi i 3269 rachunków testowych. Korpus BillSum koncentruje się na średniej długości prawodawstwa z 5000 do 20 000 znaków długości. Więcej informacji na temat projektu i oryginalnego artykułu akademickiego, z którego pochodzi ten zestaw danych, można znaleźć w repozytorium GitHub projektu BillSum
W tym samouczku bill_sum_data.csv
jest używany plik, który można pobrać z przykładowych danych usługi GitHub.
Możesz również pobrać przykładowe dane, uruchamiając następujące polecenie na komputerze lokalnym:
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
Pobieranie klucza i punktu końcowego
Aby pomyślnie wykonać wywołanie usługi Azure OpenAI, potrzebujesz punktu końcowego i klucza.
Nazwa zmiennej | Wartość |
---|---|
ENDPOINT |
Punkt końcowy usługi można znaleźć w sekcji Klucze i punkt końcowy podczas badania zasobu w witrynie Azure Portal. Możesz też znaleźć punkt końcowy za pośrednictwem strony Wdrożenia w usłudze Azure AI Studio. Przykładowy punkt końcowy to: https://docs-test-001.openai.azure.com/ . |
API-KEY |
Tę wartość można znaleźć w sekcji Klucze i punkt końcowy podczas badania zasobu z poziomu witryny Azure Portal. Możesz użyć wartości KEY1 lub KEY2 . |
Przejdź do zasobu w witrynie Azure Portal. Sekcję Klucze i punkt końcowy można znaleźć w sekcji Zarządzanie zasobami. Skopiuj punkt końcowy i klucz dostępu, ponieważ będzie potrzebny zarówno do uwierzytelniania wywołań interfejsu API. Możesz użyć wartości KEY1
lub KEY2
. Zawsze posiadanie dwóch kluczy umożliwia bezpieczne obracanie i ponowne generowanie kluczy bez powodowania zakłóceń usługi.
Zmienne środowiskowe
Tworzenie i przypisywanie trwałych zmiennych środowiskowych dla klucza i punktu końcowego.
Ważne
Jeśli używasz klucza interfejsu API, zapisz go bezpiecznie w innym miejscu, na przykład w usłudze Azure Key Vault. Nie dołączaj klucza interfejsu API bezpośrednio do kodu i nigdy nie publikuj go publicznie.
Aby uzyskać więcej informacji na temat zabezpieczeń usług sztucznej inteligencji, zobacz Uwierzytelnianie żądań w usługach Azure AI.
setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE"
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE"
Po ustawieniu zmiennych środowiskowych może być konieczne zamknięcie i ponowne otwarcie notesów Jupyter lub dowolnego środowiska IDE, którego używasz, aby zmienne środowiskowe były dostępne. Zdecydowanie zalecamy korzystanie z notesów Jupyter Notebook, jeśli z jakiegoś powodu nie będzie trzeba modyfikować dowolnego kodu zwracającego ramkę print(dataframe_name)
danych biblioteki pandas, a nie tylko wywoływać dataframe_name
bezpośrednio, jak to często odbywa się na końcu bloku kodu.
Uruchom następujący kod w preferowanym środowisku IDE języka Python:
Importowanie 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
Teraz musimy odczytać nasz plik CSV i utworzyć ramkę danych biblioteki pandas. Po utworzeniu początkowej ramki danych możemy wyświetlić zawartość tabeli, uruchamiając polecenie 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
Wyjście:
Początkowa tabela zawiera więcej kolumn, niż potrzebujemy, utworzymy nową mniejszą ramkę danych o nazwie df_bills
, która będzie zawierać tylko kolumny dla text
, summary
i title
.
df_bills = df[['text', 'summary', 'title']]
df_bills
Wyjście:
Następnie przeprowadzimy czyszczenie lekkich danych przez usunięcie nadmiarowego odstępu i oczyszczenie interpunkcji w celu przygotowania danych do tokenizacji.
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))
Teraz musimy usunąć wszelkie rachunki, które są zbyt długie dla limitu tokenu (tokeny 8192).
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
Uwaga
W takim przypadku wszystkie rachunki znajdują się w ramach limitu tokenu wejściowego modelu osadzania, ale możesz użyć powyższej techniki, aby usunąć wpisy, które w przeciwnym razie spowodują niepowodzenie osadzania. W przypadku przekroczenia limitu osadzania zawartości można również podzielić zawartość na mniejsze elementy, a następnie osadzić je pojedynczo.
Ponownie zbadamy df_bills.
df_bills
Wyjście:
Aby lepiej zrozumieć kolumnę n_tokens, a także sposób, w jaki tekst ostatecznie jest tokenizowany, warto uruchomić następujący kod:
sample_encode = tokenizer.encode(df_bills.text[0])
decode = tokenizer.decode_tokens_bytes(sample_encode)
decode
W przypadku naszych dokumentacji celowo obcinamy dane wyjściowe, ale uruchomienie tego polecenia w środowisku zwróci pełny tekst z indeksu zero tokenizowanego na fragmenty. Widać, że w niektórych przypadkach całe słowo jest reprezentowane za pomocą jednego tokenu, podczas gdy w innych częściach wyrazów są podzielone na wiele tokenów.
[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',
Jeśli następnie sprawdzisz długość decode
zmiennej, znajdziesz ją zgodną z pierwszą liczbą w kolumnie n_tokens.
len(decode)
1466
Teraz, gdy dowiesz się więcej o sposobie działania tokenizacji, możemy przejść do osadzania. Należy pamiętać, że jeszcze nie tokenizowaliśmy dokumentów. Kolumna n_tokens
jest po prostu sposobem upewnienia się, że żadne dane przekazywane do modelu na potrzeby tokenizacji i osadzania przekraczają limit tokenu wejściowego 8192. Gdy przekażemy dokumenty do modelu osadzania, spowoduje to podzielenie dokumentów na tokeny podobne (choć niekoniecznie identyczne) do powyższych przykładów, a następnie przekonwertowanie tokenów na serię liczb zmiennoprzecinkowych, które będą dostępne za pośrednictwem wyszukiwania wektorowego. Te osadzania można przechowywać lokalnie lub w usłudze Azure Database w celu obsługi wyszukiwania wektorowego. W rezultacie każdy rachunek będzie miał własny wektor osadzania w nowej ada_v2
kolumnie po prawej stronie ramki danych.
W poniższym przykładzie wywołujemy model osadzania raz na każdy element, który chcemy osadzić. Podczas pracy z dużymi projektami osadzania można również przekazać modelowi tablicę danych wejściowych do osadzania, a nie jednego danych wejściowych naraz. Po przekazaniu modelu tablica danych wejściowych maksymalna liczba elementów wejściowych na wywołanie punktu końcowego osadzania wynosi 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
Wyjście:
Po uruchomieniu poniższego bloku kodu wyszukiwania osadzimy zapytanie wyszukiwania "Czy mogę uzyskać informacje na temat przychodów podatkowych firmy kablowej?" z tym samym modelem osadzania tekstu ada-002 (wersja 2). Następnie znajdziemy najbliższy rachunek osadzony w nowo osadzonym tekście z zapytania sklasyfikowanego według podobieństwa cosinus.
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)
Wyjście:
Na koniec pokażemy najlepszy wynik z wyszukiwania dokumentów na podstawie zapytania użytkownika względem całego baza wiedzy. Zwraca to najwyższy wynik ustawy "Prawo podatnika do poglądu ustawy z 1993 roku". Ten dokument ma wynik podobieństwa cosinus o wartości 0,76 między zapytaniem a dokumentem:
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."
Wymagania wstępne
Subskrypcja platformy Azure — utwórz bezpłatnie
Zasób usługi Azure OpenAI z wdrożonym modelem osadzania tekstu ada-002 (wersja 2).
Ten model jest obecnie dostępny tylko w niektórych regionach. Jeśli nie masz zasobu, proces tworzenia zasobu jest udokumentowany w naszym przewodniku wdrażania zasobów.
Uwaga
Wiele przykładów w tym samouczku ponownie używa zmiennych od kroku do kroku. Zachowaj tę samą sesję terminalu otwartą przez cały czas. Jeśli zmienne ustawione w poprzednim kroku zostaną utracone z powodu zamknięcia terminalu, należy zacząć ponownie od początku.
Pobieranie klucza i punktu końcowego
Aby pomyślnie wykonać wywołanie usługi Azure OpenAI, potrzebujesz punktu końcowego i klucza.
Nazwa zmiennej | Wartość |
---|---|
ENDPOINT |
Punkt końcowy usługi można znaleźć w sekcji Klucze i punkt końcowy podczas badania zasobu w witrynie Azure Portal. Możesz też znaleźć punkt końcowy za pośrednictwem strony Wdrożenia w usłudze Azure AI Studio. Przykładowy punkt końcowy to: https://docs-test-001.openai.azure.com/ . |
API-KEY |
Tę wartość można znaleźć w sekcji Klucze i punkt końcowy podczas badania zasobu z poziomu witryny Azure Portal. Możesz użyć wartości KEY1 lub KEY2 . |
Przejdź do zasobu w witrynie Azure Portal. Sekcję Klucze i punkt końcowy można znaleźć w sekcji Zarządzanie zasobami. Skopiuj punkt końcowy i klucz dostępu, ponieważ będzie potrzebny zarówno do uwierzytelniania wywołań interfejsu API. Możesz użyć wartości KEY1
lub KEY2
. Zawsze posiadanie dwóch kluczy umożliwia bezpieczne obracanie i ponowne generowanie kluczy bez powodowania zakłóceń usługi.
Zmienne środowiskowe
Tworzenie i przypisywanie trwałych zmiennych środowiskowych dla klucza i punktu końcowego.
Ważne
Jeśli używasz klucza interfejsu API, zapisz go bezpiecznie w innym miejscu, na przykład w usłudze Azure Key Vault. Nie dołączaj klucza interfejsu API bezpośrednio do kodu i nigdy nie publikuj go publicznie.
Aby uzyskać więcej informacji na temat zabezpieczeń usług sztucznej inteligencji, zobacz Uwierzytelnianie żądań w usługach Azure AI.
setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE"
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE"
Na potrzeby tego samouczka używamy dokumentacji referencyjnej programu PowerShell 7.4 jako dobrze znanego i bezpiecznego przykładowego zestawu danych. Alternatywnie możesz zapoznać się z przykładowymi zestawami danych narzędzi Microsoft Research Tools .
Utwórz folder, w którym chcesz przechowywać projekt. Ustaw lokalizację na folder projektu. Pobierz zestaw danych na komputer lokalny przy użyciu Invoke-WebRequest
polecenia , a następnie rozwiń archiwum. Na koniec ustaw lokalizację na podfolder zawierający informacje referencyjne dla programu PowerShell w wersji 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/'
W tym samouczku pracujemy z dużą ilością danych, dlatego do wydajnej wydajności używamy obiektu tabeli danych platformy .NET. Tabela danych zawiera tytuł kolumn, zawartość, przygotowanie, identyfikator URI, plik i wektory. Kolumna tytułu jest kluczem podstawowym.
W następnym kroku załadujemy zawartość każdego pliku markdown do tabeli danych. Używamy również operatora programu PowerShell -match
do przechwytywania znanych wierszy tekstu title:
i online version:
, i przechowywania ich w odrębnych kolumnach. Niektóre pliki nie zawierają wierszy metadanych tekstu, ale ponieważ są to strony przeglądu, a nie szczegółowe dokumenty referencyjne, wykluczamy je z tabeli datatable.
# 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)
}
}
Wyświetl dane przy użyciu out-gridview
polecenia (niedostępne w usłudze Cloud Shell).
$Datatable | out-gridview
Wyjście:
Następnie wykonaj czyszczenie lekkich danych, usuwając dodatkowe znaki, puste miejsce i inne notacje dokumentów, aby przygotować dane do tokenizacji. Przykładowa funkcja Invoke-DocPrep
pokazuje, jak używać operatora programu PowerShell -replace
do iterowania po liście znaków, które chcesz usunąć z zawartości.
# 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
}
Po utworzeniu Invoke-DocPrep
funkcji użyj ForEach-Object
polecenia , aby przechowywać przygotowaną zawartość w kolumnie przygotowywania dla wszystkich wierszy w tabeli danych. Używamy nowej kolumny, więc oryginalne formatowanie jest dostępne, jeśli chcemy go pobrać później.
$Datatable.rows | ForEach-Object { $_.prep = Invoke-DocPrep $_.content }
Ponownie wyświetl tabelę danych, aby zobaczyć zmianę.
$Datatable | out-gridview
Gdy przekazujemy dokumenty do modelu osadzania, koduje on dokumenty do tokenów, a następnie zwraca serię liczb zmiennoprzecinkowych do użycia w wyszukiwaniu podobieństwa cosinus. Te osadzania można przechowywać lokalnie lub w usłudze, takiej jak wyszukiwanie wektorowe w usłudze Azure AI Search. Każdy dokument ma swój własny wektor osadzania w nowej kolumnie wektorów .
Następny przykład wykonuje pętlę dla każdego wiersza w tabeli danych, pobiera wektory dla wstępnie przetworzonej zawartości i zapisuje je w kolumnie wektorów . Usługa OpenAI ogranicza częste żądania, więc w przykładzie znajduje się wykładne wycofywanie zgodnie z sugestią dokumentacji.
Po zakończeniu działania skryptu każdy wiersz powinien mieć rozdzielaną przecinkami listę 1536 wektorów dla każdego dokumentu. Jeśli wystąpi błąd, a kod stanu to 400
, ścieżka pliku, tytuł i kod błędu zostaną dodane do zmiennej o nazwie $errorDocs
na potrzeby rozwiązywania problemów. Najczęstszy błąd występuje, gdy liczba tokenów jest większa niż limit monitu dla modelu.
# 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."
}
Masz teraz lokalną tabelę bazy danych w pamięci zawierającą dokumentację referencyjną programu PowerShell 7.4.
Na podstawie ciągu wyszukiwania musimy obliczyć inny zestaw wektorów, aby program PowerShell mógł sklasyfikować każdy dokument według podobieństwa.
W następnym przykładzie wektory są pobierane dla ciągu get a list of running processes
wyszukiwania .
$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 ','
Na koniec kolejna przykładowa funkcja, która pożycza przykład z przykładowego skryptu Measure-VectorSimilarity napisanego przez Lee Holmes, wykonuje obliczenia podobieństwa cosinus, a następnie klasyfikuje każdy wiersz w tabeli danych.
# 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)
}
Polecenia w następnej pętli przykładu przechodzą przez wszystkie wiersze w $Datatable
obiekcie i obliczają podobieństwo cosinus do ciągu wyszukiwania. Wyniki są sortowane, a trzy pierwsze wyniki są przechowywane w zmiennej o nazwie $topThree
. Przykład nie zwraca danych wyjściowych.
# 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 }
}
Przejrzyj dane wyjściowe zmiennej $topThree
z tylko właściwościami tytułu i adresu URL w widoku gridview.
$topThree | Select "title", "uri" | Out-GridView
Wyjście:
Zmienna $topThree
zawiera wszystkie informacje z wierszy w tabeli danych. Na przykład właściwość content zawiera oryginalny format dokumentu. Użyj polecenia [0]
, aby zaindeksować do pierwszego elementu w tablicy.
$topThree[0].content
Wyświetl pełny dokument (obcięty we fragmencie kodu wyjściowego dla tej strony).
---
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
Na koniec zamiast ponownie wygenerować osadzanie za każdym razem, gdy musisz wykonać zapytanie dotyczące zestawu danych, możesz zapisać dane na dysku i odwołać je w przyszłości. Metody WriteXML()
i ReadXML()
typów obiektów DataTable w następnym przykładzie upraszczają proces. Schemat pliku XML wymaga, aby tabela datatable miała tabelę TableName.
Zastąp <YOUR-FULL-FILE-PATH>
ciąg pełną ścieżką, w której chcesz zapisać i odczytać plik XML. Ścieżka powinna kończyć się ciągiem .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>")
Podczas ponownego używania danych należy pobrać wektory każdego nowego ciągu wyszukiwania (ale nie całą tabelę danych). W ramach ćwiczenia szkoleniowego spróbuj utworzyć skrypt programu PowerShell, aby zautomatyzować Invoke-RestMethod
polecenie przy użyciu ciągu wyszukiwania jako parametru.
Korzystając z tego podejścia, można użyć osadzania jako mechanizmu wyszukiwania w dokumentach w baza wiedzy. Użytkownik może następnie pobrać górny wynik wyszukiwania i użyć go do zadania podrzędnego, które wyświetliło monit o początkowe zapytanie.
Czyszczenie zasobów
Jeśli utworzono zasób usługi Azure OpenAI wyłącznie na potrzeby ukończenia tego samouczka i chcesz wyczyścić i usunąć zasób usługi Azure OpenAI, musisz usunąć wdrożone modele, a następnie usunąć zasób lub skojarzona grupa zasobów, jeśli jest ona przeznaczona dla zasobu testowego. Usunięcie grupy zasobów powoduje również usunięcie wszelkich innych skojarzonych z nią zasobów.
Następne kroki
Dowiedz się więcej o modelach usługi Azure OpenAI:
- Zapisz osadzanie i przeprowadź wyszukiwanie wektorów (podobieństwa) przy użyciu wybranej usługi platformy Azure: