這個教學將帶你使用Azure OpenAI
在這個教學中,你會學到如何:
- 下載範例資料集並準備分析。
- 為你的資源端點和 API 金鑰建立環境變數。
- 使用以下模型之一:text-embedding-ada-002(版本2)、text-embedding-3-large、text-embedding-3-small模型。
- 利用 餘弦相似度 來排序搜尋結果。
先決條件
- Azure訂閱 - 免費建立
- Microsoft Foundry 或 Azure OpenAI 資源,部署了 text-embedding-ada-002(版本 2) 模型。 此型號目前僅在 特定地區販售。
- Python 3.10 或更新版本
- 以下函式庫Python:
openai、num2words、matplotlib、plotly、scipy、scikit-learn、pandas、tiktoken。 - Jupyter 筆記本
設定
Python 函式庫
如果你還沒安裝,你需要安裝以下函式庫:
pip install openai num2words matplotlib plotly scipy scikit-learn pandas tiktoken
下載 BillSum 資料集
BillSum 是一個包含美國國會及加州州法案的資料集。 為了說明,我們只看美國鈔票。 該文庫包含第103至115屆國會(1993-2018)會期的法案。 數據分為18,949張鐵路帳單和3,269筆測試帳單。 BillSum 語料庫聚焦於中長 5,000 至 20,000 字元的立法。 關於該計畫及原始學術論文的更多資訊,可參考 BillSum 專案的GitHub資料庫
本教學使用可從我們的bill_sum_data.csv下載的檔案。
您也可以在本地機器執行以下指令下載範例資料:
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
註
目前 Microsoft Entra ID 的嵌入式認證在 v1 API 中不受支援。
取得金鑰與端點
要成功地進行對 Azure OpenAI 的呼叫,你需要一個 endpoint 和一個 key。
| 變數名稱 | 價值 |
|---|---|
ENDPOINT |
服務端點可以在檢視您在 Azure 入口網站中的資源時,於金鑰和端點區段中找到。 或者,你也可以透過 Microsoft Foundry 入口網站的 Deployments頁面找到該端點。 端點範例為: https://docs-test-001.openai.azure.com/ |
API-KEY |
此值可以在檢視 Azure 入口網站中的資源時的 金鑰及端點 區塊中找到。 你可以使用其中一種 KEY1 或 KEY2。 |
請前往 Azure 入口網站的資源。
「金鑰與端點」部分可在資源管理區找到。 複製你的端點和存取金鑰,因為你在驗證 API 呼叫時都需要兩者。 你可以使用其中一種 KEY1 或 KEY2。 隨時有兩把金鑰,可以安全地輪換和重新生成金鑰,不會造成服務中斷。
環境變數
建立並指派持久化的環境變數給你的 API 金鑰。
重要
使用 API 金鑰時要小心。 不要直接把 API 金鑰放進程式碼裡,也絕對不要公開發佈。 如果你使用 API 金鑰,請將其安全地存放在 Azure Key Vault。 欲了解更多如何在應用程式中安全使用 API 金鑰的資訊,請參見 API 金鑰搭配 Azure Key Vault。
如需了解更多有關 AI 服務安全性的資訊,請參閱 驗證對 Azure AI 服務的請求。
setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE"
設定好環境變數後,你可能需要關閉並重新開啟 Jupyter 筆記本或你正在使用的 IDE,才能讓環境變數被存取。 雖然我們強烈建議使用 Jupyter Notebooks,但如果因某些原因無法使用,您需要修改回傳 pandas DataFrame 的程式碼,應使用 print(dataframe_name),而非像通常在程式碼區塊末尾那樣直接呼叫 dataframe_name。
請在你偏好的 Python IDE 中執行以下程式碼:
匯入函式庫
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
現在我們需要讀取 csv 檔案並建立 pandas DataFrame。 初始資料框建立後,我們可以透過執行 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
輸出:
初始表格的欄位比我們需要的還多,我們會建立一個較小的資料框架,該df_bills框架只包含 、 text、 summary和 的欄位title。
df_bills = df[['text', 'summary', 'title']]
df_bills
輸出:
接下來我們會進行一些輕度的資料清理,移除冗餘的空白並清理標點符號,為資料做標記化準備。
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))
現在我們需要移除任何超過代幣上限(8,192 代幣)的鈔票。
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
註
在這種情況下,所有鈔票都低於嵌入模型輸入令牌限制,但你可以利用上述技術移除可能導致嵌入失敗的條目。 當內容超過嵌入限制時,你也可以將內容分成較小的部分,然後一個一個嵌入。
我們會再次檢視 df_bills。
df_bills
輸出:
為了更了解n_tokens欄以及文字最終如何被標記化,執行以下程式碼會很有幫助:
sample_encode = tokenizer.encode(df_bills.text[0])
decode = tokenizer.decode_tokens_bytes(sample_encode)
decode
我們的文件刻意截斷輸出,但在你的環境中執行這個指令,會將索引零的完整文字分成區塊回傳。 你可以看到,有些情況下整個單字可以用單個詞元表示,而在其他情況下,單字的部分則被拆分成多個詞元。
[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',
接著檢查變數的長度 decode ,你會發現它和n_tokens欄的第一個數字相符。
len(decode)
1466
現在我們更了解代幣化的運作方式,就可以進入嵌入了。 值得注意的是,我們其實還沒有把文件標記化。 欄位 n_tokens 只是確保我們傳遞給模型用於分詞化和嵌入的資料不會超過輸入的 8,192 個標記限制。 當我們將文件交給嵌入模型時,它會將文件拆分成類似(但不一定相同)的標記,然後將標記轉換成一系列浮點數,這些數字可透過向量搜尋存取。 這些嵌入可儲存在本地或 Azure資料庫中,以支援向量搜尋。 因此,每個帳單在資料框右側的新 ada_v2 欄位中都會有對應的嵌入向量。
在下面的範例中,我們每一個想要嵌入的項目就呼叫一次嵌入模型。 在處理大型嵌入專案時,你可以將一組輸入傳給模型進行嵌入,而非一次只輸入一個。 當你傳入一個輸入陣列給模型時,每次呼叫嵌入端點的最大輸入項目數是 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
輸出:
當我們執行下方的搜尋碼區塊時,會將搜尋查詢「Can I get information on cable company tax revenue?」嵌入到相同的文字嵌入模型 text-embedding-ada-002(版本 2)。 接著我們會找到與查詢中新嵌入文本最接近的帳單嵌入,並依 餘弦相似度排名。
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)
輸出:
最後,我們將根據使用者查詢,將文件搜尋的最高結果與整個知識庫對照顯示。 此報告顯示《1993年納稅人閱覽權法案》的最高結果。本文件查詢與文件的餘弦相似度分數為 0.76:
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."
透過這種方法,你可以在知識庫中跨文件使用嵌入作為搜尋機制。 使用者接著可以選取最上方的搜尋結果,並將其用於觸發他們最初查詢的下游任務。
故障排除
-
401/403:驗證
AZURE_OPENAI_API_KEY已設定並符合你的資源金鑰。 -
404:驗證
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT與你的部署名稱相符。 -
網址無效:Verify
AZURE_OPENAI_ENDPOINT是你的資源端點,例如https://<resource-name>.openai.azure.com。
清理資源
如果你是為了完成這個教學而建立 Azure OpenAI 資源,並且想清理並移除 Azure OpenAI 資源,你需要刪除已部署的模型,然後刪除該資源或相關資源群組(如果它是專門用於你的測試資源的話)。 刪除資源群組也會刪除與之相關的其他資源。
下一步
了解更多關於 Azure OpenAI 模型的資訊:
- 儲存你的嵌入,並使用你選擇的 Azure 服務進行向量(相似度)搜尋: