Bagikan melalui


Tutorial: Menjelajahi penyematan Layanan Azure OpenAI dan pencarian dokumen

Tutorial ini akan memandu Anda menggunakan AZURE OpenAI embeddings API untuk melakukan pencarian dokumen di mana Anda akan meminta basis pengetahuan untuk menemukan dokumen yang paling relevan.

Dalam tutorial ini, Anda akan mempelajari cara:

  • Instal Azure OpenAI.
  • Unduh himpunan data sampel dan siapkan untuk analisis.
  • Buat variabel lingkungan untuk titik akhir sumber daya dan kunci API Anda.
  • Menggunakan model text-embedding-ada-002 (Versi 2)
  • Gunakan kesamaan kosinus untuk memberi peringkat hasil pencarian.

Prasyarat

  • Langganan Azure - buat langganan gratis
  • Akses yang diberikan ke Azure OpenAI dalam langganan Azure yang diinginkan. Saat ini, akses ke layanan ini hanya diberikan oleh aplikasi. Anda dapat mengajukan permohonan akses ke Azure OpenAI dengan melengkapi formulir di https://aka.ms/oai/access. Buka masalah pada repositori ini untuk menghubungi kami jika Anda mengalami masalah.
  • Sumber daya Azure OpenAI dengan model text-embedding-ada-002 (Versi 2) disebarkan. Model ini saat ini hanya tersedia di wilayah tertentu. Jika Anda tidak memiliki sumber daya, proses pembuatan sumber daya didokumentasikan dalam panduan penyebaran sumber daya kami.
  • Python 3.8 atau versi yang lebih baru
  • Pustaka Python berikut: openai, num2words, matplotlib, plotly, scipy, scikit-learn, pandas, tiktoken.
  • Jupyter Notebooks

Penyiapan

Pustaka Python

Jika Anda belum melakukannya, Anda perlu menginstal pustaka berikut:

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

Mengunduh himpunan data BillSum

BillSum adalah himpunan data Amerika Serikat tagihan negara bagian Kongres dan California. Untuk tujuan ilustrasi, kita hanya akan melihat tagihan AS. Korpus terdiri dari tagihan dari sesi Kongres ke-103-115 (1993-2018). Data dibagi menjadi 18.949 tagihan kereta dan 3.269 tagihan pengujian. Korpus BillSum berfokus pada undang-undang menengah dari panjang 5.000 hingga 20.000 karakter. Informasi lebih lanjut tentang proyek dan makalah akademik asli tempat himpunan data ini berasal dapat ditemukan di repositori GitHub proyek BillSum

Tutorial ini menggunakan bill_sum_data.csv file yang dapat diunduh dari data sampel GitHub kami.

Anda juga dapat mengunduh data sampel dengan menjalankan perintah berikut di komputer lokal Anda:

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

Mengambil kunci dan titik akhir

Agar berhasil melakukan panggilan terhadap Azure OpenAI, Anda memerlukan titik akhir dan kunci.

Nama variabel Nilai
ENDPOINT Nilai ini dapat ditemukan di bagian Kunci & Titik Akhir saat memeriksa sumber daya Anda dari portal Microsoft Azure. Atau, Anda dapat menemukan nilainya di Azure OpenAI Studio>Playground>Tampilan Kode. Contoh titik akhir adalah: https://docs-test-001.openai.azure.com/.
API-KEY Nilai ini dapat ditemukan di bagian Kunci & Titik Akhir saat memeriksa sumber daya Anda dari portal Microsoft Azure. Anda dapat menggunakan KEY1 atau KEY2.

Buka sumber daya Anda di portal Azure. Bagian Kunci & Titik Akhir dapat ditemukan di bagian Manajemen Sumber Daya. Salin titik akhir dan kunci akses Anda karena keduanya diperlukan untuk mengautentikasi panggilan API Anda. Anda dapat menggunakan KEY1 atau KEY2. Selalu miliki dua kunci untuk memungkinkan Anda memutar dan meregenerasi kunci dengan aman tanpa menyebabkan gangguan layanan.

Cuplikan layar antarmuka pengguna gambaran umum untuk sumber daya Azure OpenAI di portal Azure dengan titik akhir dan lokasi kunci akses yang dilingkari dengan warna merah.

Variabel lingkungan

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Setelah mengatur variabel lingkungan, Anda mungkin perlu menutup dan membuka kembali notebook Jupyter atau IDE apa pun yang Anda gunakan agar variabel lingkungan dapat diakses. Meskipun kami sangat menyarankan untuk menggunakan Jupyter Notebooks, jika karena alasan tertentu Anda tidak perlu memodifikasi kode apa pun yang mengembalikan kerangka data panda dengan menggunakan print(dataframe_name) daripada hanya memanggil dataframe_name secara langsung seperti yang sering dilakukan di akhir blok kode.

Jalankan kode berikut di Python IDE pilihan Anda:

Mengimpor pustaka

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

Sekarang kita perlu membaca file csv kita dan membuat Pandas DataFrame. Setelah DataFrame awal dibuat, kita dapat melihat konten tabel dengan menjalankan 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:

Cuplikan layar hasil tabel DataFrame awal dari file csv.

Tabel awal memiliki lebih banyak kolom daripada yang kita butuhkan, kita akan membuat DataFrame baru yang lebih kecil yang disebut df_bills yang hanya akan berisi kolom untuk text, summary, dan title.

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

Output:

Cuplikan layar hasil tabel DataFrame yang lebih kecil hanya dengan kolom teks, ringkasan, dan judul yang ditampilkan.

Selanjutnya kita akan melakukan beberapa pembersihan data ringan dengan menghapus ruang putih redundan dan membersihkan tanda baca untuk menyiapkan data untuk tokenisasi.

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

Sekarang kita perlu menghapus tagihan apa pun yang terlalu panjang untuk batas 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

Catatan

Dalam hal ini semua tagihan berada di bawah batas token input model penyematan, tetapi Anda dapat menggunakan teknik di atas untuk menghapus entri yang sebaliknya akan menyebabkan penyematan gagal. Ketika dihadapkan dengan konten yang melebihi batas penyematan, Anda juga dapat memotong konten menjadi potongan-potongan yang lebih kecil dan kemudian menyematkannya satu per satu.

Kami akan sekali lagi memeriksa df_bills.

df_bills

Output:

Cuplikan layar DataFrame dengan kolom baru yang disebut n_tokens.

Untuk memahami kolom n_tokens sedikit lebih baik bagaimana teks pada akhirnya ditokenisasi, akan sangat membantu untuk menjalankan kode berikut:

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

Untuk dokumen kami, kami sengaja memotong output, tetapi menjalankan perintah ini di lingkungan Anda akan mengembalikan teks lengkap dari indeks nol yang ditokenisasi menjadi gugus. Anda dapat melihat bahwa dalam beberapa kasus seluruh kata diwakili dengan satu token sedangkan di bagian kata lain dibagi di beberapa 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',

Jika Anda kemudian memeriksa panjang decode variabel, Anda akan menemukannya cocok dengan angka pertama di kolom n_tokens.

len(decode)
1466

Sekarang setelah kita memahami lebih lanjut tentang cara kerja tokenisasi, kita dapat melanjutkan ke penyematan. Penting untuk dicatat, bahwa kami belum benar-benar tokenisasi dokumen. Kolom n_tokens hanyalah cara untuk memastikan tidak ada data yang kami teruskan ke model untuk tokenisasi dan penyematan melebihi batas token input 8.192. Ketika kita meneruskan dokumen ke model penyematan, itu akan memecah dokumen menjadi token yang serupa (meskipun belum tentu identik) ke contoh di atas dan kemudian mengonversi token menjadi serangkaian angka titik mengambang yang akan dapat diakses melalui pencarian vektor. Penyematan ini dapat disimpan secara lokal atau di Azure Database untuk mendukung Pencarian Vektor. Akibatnya, setiap tagihan akan memiliki vektor penyematan yang sesuai sendiri di kolom baru ada_v2 di sisi kanan DataFrame.

Dalam contoh di bawah ini kita memanggil model penyematan sekali per setiap item yang ingin kita sematkan. Saat bekerja dengan proyek penyematan besar, Anda dapat meneruskan model array input untuk menyematkan daripada satu input pada satu waktu. Saat Anda meneruskan model array input, jumlah maksimum item input per panggilan ke titik akhir penyematan adalah 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:

Cuplikan layar hasil yang diformat dari perintah df_bills.

Saat kami menjalankan blok kode pencarian di bawah ini, kami akan menyematkan kueri pencarian "Bisakah saya mendapatkan informasi tentang pendapatan pajak perusahaan kabel?" dengan model text-embedding-ada-002 (Versi 2) yang sama. Selanjutnya kita akan menemukan penagihan terdekat yang disematkan ke teks yang baru disematkan dari kueri kita yang diberi peringkat oleh kesamaan kosinus.

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:

Cuplikan layar hasil res yang diformat setelah kueri pencarian dijalankan.

Terakhir, kita akan menampilkan hasil teratas dari pencarian dokumen berdasarkan kueri pengguna terhadap seluruh basis pengetahuan. Ini mengembalikan hasil teratas dari "Undang-Undang Hak Wajib Pajak untuk Melihat tahun 1993". Dokumen ini memiliki skor kesamaan kosinus 0,76 antara kueri dan dokumen:

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

Prasyarat

  • Langganan Azure - buat langganan gratis

  • Akses yang diberikan ke Azure OpenAI dalam langganan Azure yang diinginkan.

    Saat ini, akses ke layanan ini hanya diberikan oleh aplikasi. Anda dapat mengajukan permohonan akses ke Azure OpenAI dengan melengkapi formulir di https://aka.ms/oai/access. Buka masalah pada repositori ini untuk menghubungi kami jika Anda mengalami masalah.

  • Sumber daya Azure OpenAI dengan model text-embedding-ada-002 (Versi 2) disebarkan.

    Model ini saat ini hanya tersedia di wilayah tertentu. Jika Anda tidak memiliki sumber daya, proses pembuatan sumber daya didokumentasikan dalam panduan penyebaran sumber daya kami.

  • PowerShell 7.4

Catatan

Banyak contoh dalam tutorial ini menggunakan kembali variabel dari langkah ke langkah. Biarkan sesi terminal yang sama terbuka di seluruh area. Jika variabel yang Anda tetapkan di langkah sebelumnya hilang karena menutup terminal, Anda harus memulai lagi dari awal.

Mengambil kunci dan titik akhir

Agar berhasil melakukan panggilan terhadap Azure OpenAI, Anda memerlukan titik akhir dan kunci.

Nama variabel Nilai
ENDPOINT Nilai ini dapat ditemukan di bagian Kunci & Titik Akhir saat memeriksa sumber daya Anda dari portal Microsoft Azure. Atau, Anda dapat menemukan nilainya di Azure OpenAI Studio>Playground>Tampilan Kode. Contoh titik akhir adalah: https://docs-test-001.openai.azure.com/.
API-KEY Nilai ini dapat ditemukan di bagian Kunci & Titik Akhir saat memeriksa sumber daya Anda dari portal Microsoft Azure. Anda dapat menggunakan KEY1 atau KEY2.

Buka sumber daya Anda di portal Azure. Bagian Kunci & Titik Akhir dapat ditemukan di bagian Manajemen Sumber Daya. Salin titik akhir dan kunci akses Anda karena keduanya diperlukan untuk mengautentikasi panggilan API Anda. Anda dapat menggunakan KEY1 atau KEY2. Selalu miliki dua kunci untuk memungkinkan Anda memutar dan meregenerasi kunci dengan aman tanpa menyebabkan gangguan layanan.

Cuplikan layar antarmuka pengguna gambaran umum untuk sumber daya Azure OpenAI di portal Azure dengan titik akhir dan lokasi kunci akses yang dilingkari dengan warna merah.

Buat dan tetapkan variabel lingkungan persisten untuk kunci dan titik akhir Anda.

Variabel lingkungan

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Untuk tutorial ini, kami menggunakan dokumentasi referensi PowerShell 7.4 sebagai himpunan data sampel yang terkenal dan aman. Sebagai alternatif, Anda dapat memilih untuk menjelajahi himpunan data sampel alat Microsoft Research.

Buat folder tempat Anda ingin menyimpan proyek Anda. Atur lokasi Anda ke folder proyek. Unduh himpunan data ke komputer lokal Anda menggunakan Invoke-WebRequest perintah lalu perluas arsip. Terakhir, atur lokasi Anda ke subfolder yang berisi informasi referensi untuk PowerShell versi 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/'

Kami bekerja dengan sejumlah besar data dalam tutorial ini, jadi kami menggunakan objek tabel data .NET untuk performa yang efisien. Datatable memiliki judul kolom, konten, persiapan, uri, file, dan vektor. Kolom judul adalah kunci utama.

Pada langkah berikutnya, kami memuat konten setiap file markdown ke dalam tabel data. Kami juga menggunakan operator PowerShell -match untuk mengambil baris teks title: yang diketahui dan online version:, dan menyimpannya dalam kolom yang berbeda. Beberapa file tidak berisi baris metadata teks, tetapi karena merupakan halaman gambaran umum dan bukan dokumen referensi terperinci, kami mengecualikannya dari 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)
    }
}

Lihat data menggunakan out-gridview perintah (tidak tersedia di Cloud Shell).

$Datatable | out-gridview

Output:

Cuplikan layar hasil DataTable awal.

Selanjutnya lakukan beberapa pembersihan data ringan dengan menghapus karakter tambahan, ruang kosong, dan notasi dokumen lainnya, untuk menyiapkan data untuk tokenisasi. Fungsi Invoke-DocPrep sampel menunjukkan cara menggunakan operator PowerShell -replace untuk melakukan iterasi melalui daftar karakter yang ingin Anda hapus dari konten.

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

Setelah Anda membuat Invoke-DocPrep fungsi, gunakan ForEach-Object perintah untuk menyimpan konten yang disiapkan di kolom persiapan , untuk semua baris dalam datatable. Kami menggunakan kolom baru sehingga pemformatan asli tersedia jika kami ingin mengambilnya nanti.

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

Lihat datatable lagi untuk melihat perubahan.

$Datatable | out-gridview

Ketika kita meneruskan dokumen ke model penyematan, dokumen tersebut mengodekan dokumen ke dalam token dan kemudian mengembalikan serangkaian angka titik mengambang untuk digunakan dalam pencarian kesamaan kosinus. Penyematan ini dapat disimpan secara lokal atau dalam layanan seperti Pencarian Vektor di Azure AI Search. Setiap dokumen memiliki vektor penyematan yang sesuai sendiri di kolom vektor baru.

Contoh berikutnya mengulang setiap baris dalam datatable, mengambil vektor untuk konten yang telah diproses sebelumnya, dan menyimpannya ke kolom vektor . Layanan OpenAI membatasi permintaan yang sering, sehingga contohnya menyertakan back-off eksponensial seperti yang disarankan oleh dokumentasi.

Setelah skrip selesai, setiap baris harus memiliki daftar vektor 1536 yang dibatasi koma untuk setiap dokumen. Jika terjadi kesalahan dan kode status adalah 400, jalur file, judul, dan kode kesalahan ditambahkan ke variabel bernama $errorDocs untuk pemecahan masalah. Kesalahan yang paling umum terjadi ketika jumlah token lebih dari batas perintah untuk 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."
}

Anda sekarang memiliki tabel database dalam memori lokal dokumen referensi PowerShell 7.4.

Berdasarkan string pencarian, kita perlu menghitung sekumpulan vektor lain sehingga PowerShell dapat memberi peringkat setiap dokumen berdasarkan kesamaan.

Dalam contoh berikutnya, vektor diambil untuk string get a list of running processespencarian .

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

Terakhir, fungsi sampel berikutnya, yang meminjam contoh dari contoh skrip Measure-VectorSimilarity yang ditulis oleh Lee Holmes, melakukan perhitungan kesamaan kosinus dan kemudian memberi peringkat setiap baris dalam datatable.

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

Perintah dalam contoh berikutnya mengulangi semua baris di $Datatable dan menghitung kesamaan kosinus dengan string pencarian. Hasilnya diurutkan dan tiga hasil teratas disimpan dalam variabel bernama $topThree. Contoh tidak mengembalikan 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 }
}

Tinjau output $topThree variabel, dengan hanya properti judul dan url , dalam gridview.

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

Output:

Cuplikan layar hasil yang diformat setelah kueri pencarian selesai.

Variabel $topThree berisi semua informasi dari baris dalam datatable. Misalnya, properti konten berisi format dokumen asli. Gunakan [0] untuk mengindeks ke dalam item pertama dalam array.

$topThree[0].content

Lihat dokumen lengkap (dipotong dalam cuplikan output untuk halaman ini).

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

Terakhir, daripada meregenerasi penyematan setiap kali Anda perlu mengkueri himpunan data, Anda dapat menyimpan data ke disk dan mengingatnya di masa mendatang. Metode WriteXML() dan ReadXML() tipe objek DataTable dalam contoh berikutnya menyederhanakan proses. Skema file XML mengharuskan datatable memiliki TableName.

Ganti <YOUR-FULL-FILE-PATH> dengan jalur lengkap tempat Anda ingin menulis dan membaca file XML. Jalur harus diakhir dengan .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>")

Saat Anda menggunakan kembali data, Anda perlu mendapatkan vektor dari setiap string pencarian baru (tetapi bukan seluruh datatable). Sebagai latihan pembelajaran, coba buat skrip PowerShell untuk mengotomatiskan Invoke-RestMethod perintah dengan string pencarian sebagai parameter.

Dengan menggunakan pendekatan ini, Anda dapat menggunakan penyematan sebagai mekanisme pencarian di seluruh dokumen dalam basis pengetahuan. Pengguna kemudian dapat mengambil hasil pencarian teratas dan menggunakannya untuk tugas hilir mereka, yang meminta kueri awal mereka.

Membersihkan sumber daya

Jika Anda membuat sumber daya Azure OpenAI hanya untuk menyelesaikan tutorial ini dan ingin membersihkan dan menghapus sumber daya Azure OpenAI, Anda harus menghapus model yang disebarkan, lalu menghapus sumber daya atau grup sumber daya terkait jika didedikasikan untuk sumber daya pengujian Anda. Menghapus grup sumber daya juga menghapus sumber daya apa pun yang terkait dengannya.

Langkah berikutnya

Pelajari selengkapnya tentang model Azure OpenAI: