Tutorial: Menjelajahi embedding model Microsoft Foundry dalam Azure OpenAI dan pencarian dokumen

Tutorial ini menunjukkan kepada Anda cara menggunakan AZURE OpenAI embeddings API untuk melakukan pencarian document. Anda meminta pangkalan pengetahuan untuk menemukan dokumen yang paling relevan.

Dalam tutorial ini, Anda mempelajari cara:

  • Unduh himpunan data sampel dan siapkan untuk analisis.
  • Buat variabel lingkungan untuk titik akhir sumber daya dan kunci API Anda.
  • Gunakan salah satu model berikut: text-embedding-ada-002 (Versi 2), text-embedding-3-large, atau text-embedding-3-small.
  • Gunakan kesamaan kosinus untuk memberi peringkat hasil pencarian.

Prasyarat

Pengaturan

perpustakaan 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 kumpulan data Rancangan Undang-Undang Kongres Amerika Serikat dan negara bagian California. Untuk tujuan ilustrasi, kita hanya akan melihat tagihan AS. Korpus terdiri dari RUU pada sesi Kongres ke-103 hingga ke-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 file bill_sum_data.csv yang dapat diunduh dari data sampel GitHub.

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

Catatan

autentikasi berbasis Microsoft Entra ID saat ini tidak didukung untuk penyematan dengan API v1.

Mengambil kunci dan titik akhir

Agar berhasil melakukan panggilan terhadap Azure OpenAI, Anda memerlukan endpoint dan key.

Nama variabel Nilai
ENDPOINT Titik akhir layanan dapat ditemukan di Bagian Kunci & Titik Akhir saat memeriksa sumber daya Anda dari portal Azure. Atau, Anda dapat menemukan titik akhir melalui halaman Deployments di portal Microsoft Foundry. Contoh titik akhir adalah: https://docs-test-001.openai.azure.com/.
API-KEY Nilai ini dapat ditemukan di Keys & Endpoint saat memeriksa sumber daya Anda dari portal 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 Anda memerlukan keduanya untuk mengautentikasi panggilan API Anda. Anda dapat menggunakan KEY1 atau KEY2. Selalu memiliki dua kunci memungkinkan Anda memutar dan meregenerasi kunci dengan aman tanpa menyebabkan gangguan layanan.

Screenshot dari antarmuka pengguna gambaran umum untuk resource Azure OpenAI di portal Azure dengan titik akhir dan lokasi kunci akses yang dilingkari dalam merah.

Variabel lingkungan

Buat dan tetapkan variabel lingkungan persisten untuk kunci API Anda.

Penting

Gunakan kunci API dengan hati-hati. Jangan sertakan kunci API langsung dalam kode Anda, dan jangan pernah mempostingnya secara publik. Jika Anda menggunakan kunci API, simpan dengan aman di Azure Key Vault. Untuk informasi selengkapnya tentang menggunakan kunci API dengan aman di aplikasi Anda, lihat kunci API dengan Azure Key Vault.

** Untuk informasi selengkapnya tentang keamanan layanan AI, lihat Authenticate requests ke layanan Azure AI.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_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 dapat, Anda perlu memodifikasi kode apa pun yang mengembalikan pandas dataframe dengan menggunakan print(dataframe_name) daripada hanya memanggil dataframe_name secara langsung, seperti yang sering dilakukan di akhir blok kode.

Jalankan kode berikut di ide Python 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 OpenAI

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 pembersihan data ringan dengan menghapus spasi berlebih dan merapikan tanda baca untuk menyiapkan data agar siap 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 (8.192 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 yang lebih kecil dan kemudian menyematkan potongan 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 dalam database Azure 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 memberikan model array berisi beberapa masukan untuk disematkan, bukannya memberikan satu masukan pada satu waktu. Saat Anda memberikan model kumpulan input, jumlah maksimum item input per panggilan ke terminal penyematan adalah 2048.

client = OpenAI(
  api_key = os.getenv("AZURE_OPENAI_API_KEY"),  
  base_url="https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/"
)

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 penyematan tagihan terdekat ke teks yang baru saja disematkan dari kueri kita, yang diurutkan berdasarkan 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 pangkalan 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."

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

Pemecahan masalah

  • 401/403: Pastikan AZURE_OPENAI_API_KEY diatur dan cocok dengan kunci sumber Anda.
  • 404: Pastikan AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT cocok dengan nama penyebaran Anda.
  • URL tidak valid: Verifikasi AZURE_OPENAI_ENDPOINT adalah titik akhir sumber daya Anda, seperti https://<resource-name>.openai.azure.com.

Membersihkan sumber daya

Jika Anda membuat sumber daya OpenAI Azure semaunya untuk menyelesaikan tutorial ini dan ingin membersihkan dan menghapus sumber daya OpenAI Azure, hapus model yang Anda sebarkan. Kemudian, hapus sumber daya atau grup sumber daya terkait jika didedikasikan untuk sumber daya pengujian Anda. Menghapus grup sumber daya juga menghapus sumber daya lain yang terkait dengannya.

Langkah berikutnya

Pelajari selengkapnya tentang model Azure OpenAI: