مشاركة عبر


الدرس التعليمي: استكشف Azure OpenAI في تضمين نماذج Microsoft Foundry والبحث عن المستندات

سيرشدك هذا البرنامج التعليمي خلال استخدام واجهة برمجة تطبيقات تضمين Azure OpenAI لإجراء البحث في المستندات حيث ستقوم بالاستعلام عن قاعدة المعارف (KB) للعثور على المستند الأكثر صلة.

في هذا البرنامج التعليمي، تتعلم كيفية:

  • قم بتنزيل عينة من مجموعة البيانات وإعدادها للتحليل.
  • إنشاء متغيرات البيئة لنقطة نهاية الموارد ومفتاح API.
  • استخدم أحد النماذج التالية: text-embedding-ada-002 (الإصدار 2)، ونماذج text-embedding-3-large، و text-embedding-3-small.
  • استخدم تشابه التمام لترتيب نتائج البحث.

المتطلبات الأساسية

الإعداد

مكتبات Python

إذا لم تكن قد قمت بالفعل، فستحتاج إلى تثبيت المكتبات التالية:

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

تنزيل مجموعة بيانات BillSum

BillSum هي مجموعة بيانات من فواتير الولايات المتحدة في الكونغرس وكاليفورنيا. لأغراض التوضيح، سننظر فقط في فواتير الولايات المتحدة. تتكون المجموعة من مشاريع قوانين من جلسات الكونغرس من 103 إلى 115 (1993-2018). وقسمت البيانات إلى 949 18 فاتورة قطار و 269 3 فاتورة اختبار. وتركز مجموعة بيلسوم على التشريع متوسط الطول من 000 5 إلى 000 20 حرف في الطول. يمكن العثور على مزيد من المعلومات حول المشروع والورقة الأكاديمية الأصلية حيث يتم اشتقاق مجموعة البيانات هذه في مستودع GitHub لمشروع BillSum

يستخدم bill_sum_data.csv هذا البرنامج التعليمي الملف الذي يمكن تنزيله من بيانات نموذج GitHub.

يمكنك أيضا تنزيل نموذج البيانات عن طريق تشغيل الأمر التالي على جهازك المحلي:

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

ملاحظة

لا يدعم حاليا المصادقة المعتمدة على معرف إنترا للتضمينات مع واجهة برمجة التطبيقات v1.

قم باسترداد المفتاح ونقطة النهاية

لإجراء مكالمة بنجاح مقابل Azure OpenAI، تحتاج إلى نقطة نهاية ومفتاح.

اسم المتغير القيمة‬
ENDPOINT يمكن العثور على نقطة نهاية الخدمة في قسم Keys & Endpoint عند فحص المورد الخاص بك من مدخل Microsoft Azure. بدلا من ذلك، يمكنك العثور على نقطة النهاية عبر صفحة النشر في بوابة Microsoft Foundry. مثال على نقطة النهاية هو: https://docs-test-001.openai.azure.com/.
API-KEY يمكن العثور على هذه القيمة في قسم المفاتيح ونقطة النهاية عند فحص المورد من مدخل Microsoft Azure. يمكنك استخدام إما KEY1 أو KEY2.

انتقل إلى مجموعة الموارد في مدخل Microsoft Azure. يمكن العثور على قسم Keys & Endpoint في قسم Resource Management . انسخ نقطة النهاية ومفتاح الوصول حيث ستحتاج إلى كليهما لمصادقة استدعاءات واجهة برمجة التطبيقات. يمكنك استخدام إما KEY1 أو KEY2. يسمح لك وجود مفتاحين دائماً بتدوير المفاتيح وإعادة إنشائها بأمان دون التسبب في تعطيل الخدمة.

لقطة شاشة لواجهة مستخدم النظرة العامة لمورد Azure OpenAI في مدخل Microsoft Azure مع وضع نقطة النهاية وموقع مفاتيح الوصول في دائرة باللون الأحمر.

متغيرات البيئة

قم بإنشاء متغيرات بيئة ثابتة وتعيينها لمفتاح واجهة برمجة التطبيقات الخاص بك.

هام

استخدم مفاتيح واجهة برمجة التطبيقات بحذر. لا تقم بتضمين مفتاح API مباشرة في التعليمات البرمجية الخاصة بك، ولا تنشره بشكل عام. إذا كنت تستخدم مفتاح API، فخزنه بأمان في Azure Key Vault. لمزيد من المعلومات حول استخدام مفاتيح واجهة برمجة التطبيقات بشكل آمن في تطبيقاتك، راجع مفاتيح واجهة برمجة التطبيقات باستخدام Azure Key Vault.

لمزيد من المعلومات حول أمان خدمات الذكاء الاصطناعي، راجع مصادقة الطلبات إلى خدمات Azure الذكاء الاصطناعي.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 

بعد تعيين متغيرات البيئة، قد تحتاج إلى إغلاق دفاتر ملاحظات Jupyter وإعادة فتحها أو أي IDE تستخدمه حتى يمكن الوصول إلى متغيرات البيئة. بينما نوصي بشدة باستخدام Jupyter Notebooks، إذا كان لسبب ما لا يمكنك تعديل أي تعليمة برمجية تقوم بإرجاع إطار بيانات Pandas باستخدام 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. بعد إنشاء 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

الناتج:

لقطة شاشة لنتائج جدول DataFrame الأولي من ملف csv.

يحتوي الجدول الأولي على أعمدة أكثر مما نحتاج إليه سنقوم بإنشاء DataFrame أصغر جديد يسمى df_bills والذي سيحتوي فقط على أعمدة و textsummaryوtitle.

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

الناتج:

لقطة شاشة لنتائج جدول DataFrame الأصغر مع عرض أعمدة النص والملخص والعنوان فقط.

بعد ذلك سنقوم بإجراء بعض تنظيف البيانات الخفيفة عن طريق إزالة المسافة البيضاء المكررة وتنظيف علامات الترقيم لإعداد البيانات للرمز المميز.

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

الناتج:

لقطة شاشة ل DataFrame مع عمود جديد يسمى n_tokens.

لفهم عمود 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 العمود هو ببساطة طريقة للتأكد من عدم تجاوز أي من البيانات التي نمررها إلى النموذج للرمز المميز والتضمين حد الرمز المميز للإدخال وهو 8192. عندما نمرر المستندات إلى نموذج التضمينات، فإنه سيتم تقسيم المستندات إلى رموز مميزة مشابهة (وإن لم تكن متطابقة بالضرورة) للأمثلة أعلاه ثم تحويل الرموز المميزة إلى سلسلة من أرقام النقاط العائمة التي يمكن الوصول إليها عبر البحث المتجه. يمكن تخزين هذه التضمينات محليا أو في قاعدة بيانات Azure لدعم البحث في المتجهات. ونتيجة لذلك، سيكون لكل فاتورة متجه تضمين مطابق لها في العمود الجديد ada_v2 على الجانب الأيسر من DataFrame.

في المثال أدناه، نستدعي نموذج التضمين مرة واحدة لكل عنصر نريد تضمينه. عند العمل مع مشاريع التضمين الكبيرة، يمكنك بدلا من ذلك تمرير النموذج مجموعة من المدخلات للتضمين بدلا من إدخال واحد في كل مرة. عند تمرير النموذج، يكون الحد الأقصى لعدد عناصر الإدخال لكل استدعاء إلى نقطة نهاية التضمين هو 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

الناتج:

لقطة شاشة للنتائج المنسقة من الأمر df_bills.

أثناء تشغيل كتلة التعليمات البرمجية للبحث أدناه، سنقوم بتضمين استعلام البحث "هل يمكنني الحصول على معلومات حول إيرادات ضريبة شركة الكابلات؟" بنفس نموذج 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)

إخراج:

لقطة شاشة لنتائج res المنسقة بمجرد تشغيل استعلام البحث.

وأخيرا، سنعرض النتيجة العليا من البحث في المستندات استنادا إلى استعلام المستخدم مقابل قاعدة المعارف (KB) بأكمله. يؤدي هذا إلى إرجاع النتيجة العليا ل "قانون حق دافعي الضرائب في الاطلاع لعام 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."

باستخدام هذا الأسلوب، يمكنك استخدام التضمينات كآلية بحث عبر المستندات في قاعدة المعارف (KB). يمكن للمستخدم بعد ذلك أخذ أعلى نتيجة بحث واستخدامها لمهمة انتقال البيانات من الخادم، والتي دفعت الاستعلام الأولي الخاص به.

تنظيف الموارد

إذا قمت بإنشاء مورد Azure OpenAI فقط لإكمال هذا البرنامج التعليمي وتريد تنظيف مورد Azure OpenAI وإزالته، فستحتاج إلى حذف النماذج المنشورة، ثم حذف المورد أو مجموعة الموارد المقترنة إذا كان مخصصا لمورد الاختبار الخاص بك. يؤدي حذف مجموعة الموارد إلى حذف أية موارد أخرى مقترنة بها أيضًا.

الخطوات التالية

تعرف على المزيد حول نماذج Azure OpenAI: