Lernprogramm: Erforschen Sie das Azure OpenAI in den Microsoft Foundry Modelleinbettungen und der Dokumentsuche.

Dieses Lernprogramm führt Sie durch die Verwendung der Azure OpenAI embeddings-API zum Ausführen der document-Suche wo Sie eine Wissensdatenbank abfragen, um das relevanteste Dokument zu finden.

In diesem Lernprogramm erfahren Sie, wie Sie:

  • Laden Sie ein Beispieldatenset herunter, und bereiten Sie es für die Analyse vor.
  • Erstellen Sie Umgebungsvariablen für den Ressourcenendpunkt und den API-Schlüssel.
  • Verwenden Sie eines der folgenden Modelle: text-embedding-ada-002 (Version 2), text-embedding-3-large, text-embedding-3-small models.
  • Verwenden Sie kosinusgleichheit , um Suchergebnisse zu bewerten.

Voraussetzungen

Einrichten

Python-Bibliotheken

Falls noch nicht geschehen, müssen Sie die folgenden Bibliotheken installieren:

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

Herunterladen des BillSum-Datasets

BillSum ist ein Datensatz von Gesetzentwürfen des Kongresses der Vereinigten Staaten und des Staates Kalifornien. Zur Veranschaulichung betrachten wir nur die US-Rechnungen. Der Korpus besteht aus Gesetzesvorlagen der 103. bis 115. (1993-2018) Sitzung des Kongresses. Die Daten wurden in 18.949 Zugrechnungen und 3.269 Testrechnungen aufgeteilt. Der BillSum-Korpus konzentriert sich auf die Rechtsvorschriften der Mittleren Länge von 5.000 bis 20.000 Zeichen. Weitere Informationen zum Projekt und zum ursprünglichen akademischen Dokument, aus dem dieses Dataset abgeleitet ist, finden Sie im BillSum-Projekt GitHub Repository

In diesem Lernprogramm wird die datei bill_sum_data.csv verwendet, die aus unseren beispieldaten GitHub heruntergeladen werden kann.

Sie können die Beispieldaten auch herunterladen, indem Sie den folgenden Befehl auf Ihrem lokalen Computer ausführen:

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

Hinweis

Microsoft Entra-ID-basierte Authentifizierung ist derzeit für Embeddings mit der API v1 nicht unterstützt.

Abrufen von Schlüssel und Endpunkt

Um erfolgreich Azure OpenAI aufzurufen, benötigen Sie einen endpoint und einen key.

Variablenname Wert
ENDPOINT Der Dienstendpunkt befindet sich im Keys & Endpoint abschnitt beim Überprüfen Ihrer Ressource im Azure-Portal. Alternativ können Sie den Endpunkt über die Seite Deployments im Microsoft Foundry-Portal finden. Ein Beispielendpunkt ist: https://docs-test-001.openai.azure.com/.
API-KEY Dieser Wert befindet sich im Keys & Endpoint-Abschnitt, wenn Sie Ihre Ressource aus dem Azure-Portal überprüfen. Sie können entweder KEY1 oder KEY2.

Wechseln Sie im Azure-Portal zu Ihrer Ressource. Der Abschnitt "Keys & Endpoint " finden Sie im Abschnitt "Ressourcenverwaltung ". Kopieren Sie Ihren Endpunkt und den Zugriffsschlüssel, da Sie beide zum Authentifizieren Ihrer API-Aufrufe benötigen. Sie können entweder KEY1 oder KEY2. Das ständige Vorhandensein von zwei Schlüsseln ermöglicht es Ihnen, Schlüssel sicher zu wechseln und neu zu generieren, ohne dass eine Dienstunterbrechung verursacht wird.

Screenshot der Übersichts-UI für eine Azure OpenAI-Ressource im Azure-Portal mit dem Standort des Endpunkts und der Zugriffsschlüssel, in Rot eingekreist.

Umgebungsvariablen

Erstellen und Zuweisen persistenter Umgebungsvariablen für Ihren API-Schlüssel.

Wichtig

Verwenden Sie API-Schlüssel mit Vorsicht. Fügen Sie den API-Schlüssel nicht direkt in Ihren Code ein, und veröffentlichen Sie ihn nie öffentlich. Wenn Sie einen API-Schlüssel verwenden, speichern Sie ihn sicher in Azure Key Vault. Weitere Informationen zur sicheren Verwendung von API-Schlüsseln in Ihren Apps finden Sie unter API-Schlüssel mit Azure Key Vault.

Weitere Informationen zur Sicherheit von AI-Diensten finden Sie unter Authenticate-Anforderungen an Azure KI Services.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 

Nachdem Sie die Umgebungsvariablen festgelegt haben, müssen Sie möglicherweise Jupyter-Notizbücher schließen und erneut öffnen, oder eine beliebige IDE, die Sie verwenden, damit auf die Umgebungsvariablen zugegriffen werden kann. Es wird dringend empfohlen, Jupyter-Notizbücher zu verwenden. Wenn Sie jedoch aus irgendeinem Grund darauf verzichten müssen, sollten Sie den Code, der einen Pandas-Datenframe zurückgibt, so anpassen, dass er print(dataframe_name) verwendet anstatt dataframe_name direkt aufzurufen, wie es oft am Ende eines Codeblocks gemacht wird.

Führen Sie den folgenden Code in Ihrer bevorzugten Python IDE aus:

Importieren von Bibliotheken

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

Jetzt müssen wir unsere CSV-Datei lesen und einen Pandas DataFrame erstellen. Nachdem der ursprüngliche DataFrame erstellt wurde, können wir den Inhalt der Tabelle anzeigen, indem wir df ausführen.

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

Ausgabe:

Screenshot der anfänglichen DataFrame-Tabelle-Ergebnisse aus der CSV-Datei.

Wir werden einen neuen, kleineren DataFrame erstellen, da die erste Tabelle mehr Spalten enthält, als wir benötigen. Dieser DataFrame wird nur die Spalten für text, summary und title enthalten.

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

Ausgabe:

Screenshot der kleineren DataFrame-Tabellenergebnisse mit nur angezeigten Text-, Zusammenfassungs- und Titelspalten.

Als Nächstes führen wir eine leichte Datenreinigung durch Entfernen redundanter Leerzeichen und Bereinigen der Interpunktion aus, um die Daten für die Tokenisierung vorzubereiten.

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

Jetzt müssen wir alle Rechnungen entfernen, die für den Tokengrenzwert zu lang sind (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

Hinweis

In diesem Fall befinden sich alle Rechnungen unter dem Grenzwert für das Einbettungsmodelleingabetoken, aber Sie können die oben beschriebene Methode verwenden, um Einträge zu entfernen, die andernfalls dazu führen würden, dass ein Einbettungsfehler auftritt. Wenn Sie mit Inhalten konfrontiert sind, die den Einbettungsgrenzwert überschreiten, können Sie den Inhalt auch in kleinere Teile aufteilen und dann die Blöcke einzeln einbetten.

Wir werden df_bills erneut untersuchen.

df_bills

Ausgabe:

Screenshot des DataFrame mit einer neuen Spalte namens n_tokens.

Um die n_tokens Spalte etwas mehr zu verstehen und zu verstehen, wie Text letztendlich tokenisiert wird, kann es hilfreich sein, den folgenden Code auszuführen:

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

Für unsere Dokumentation wird die Ausgabe absichtlich abgeschnitten. Wenn Sie jedoch diesen Befehl in Ihrer Umgebung ausführen, wird der vollständige Text ab Index Null in Blöcke tokenisiert zurückgegeben. Sie können sehen, dass in einigen Fällen ein ganzes Wort mit einem einzelnen Token dargestellt wird, während in anderen Teilen von Wörtern mehrere Token aufgeteilt werden.

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

Wenn Sie dann die Länge der decode Variablen überprüfen, wird sie mit der ersten Zahl in der spalte n_tokens übereinstimmen.

len(decode)
1466

Jetzt, da wir mehr darüber wissen, wie die Tokenisierung funktioniert, können wir mit der Einbettung fortfahren. Es ist wichtig zu beachten, dass wir die Dokumente noch nicht tokenisiert haben. Die n_tokens Spalte ist einfach eine Möglichkeit, sicherzustellen, dass keine der Daten, die wir für die Tokenisierung an das Modell übergeben, und das Einbetten überschreitet den Eingabetokengrenzwert von 8.192. Wenn wir die Dokumente an das Einbettungsmodell übergeben, werden die Dokumente in token ähnlich (jedoch nicht unbedingt identisch) mit den obigen Beispielen aufgeteilt und dann die Token in eine Reihe von Gleitkommazahlen konvertiert, auf die über die Vektorsuche zugegriffen werden kann. Diese Einbettungen können lokal oder in einer Azure Datenbank gespeichert werden, um die Vektorsuche zu unterstützen. Daher verfügt jede Rechnung über einen eigenen entsprechenden Einbettungsvektor in der neuen ada_v2 Spalte auf der rechten Seite des DataFrames.

Im folgenden Beispiel rufen wir das Einbettungsmodell einmal pro Element auf, das wir einbetten möchten. Sie können beim Arbeiten mit großen Einbettungsprojekten alternativ dem Modell ein Array von Eingaben übergeben, um diese einzubetten, anstatt jeweils nur eine Eingabe. Wenn Sie dem Modell ein Array mit Eingabewerten übergeben, beträgt die maximale Anzahl von Eingabeelementen pro Aufruf des Einbettungsendpunktes 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

Ausgabe:

Screenshot der formatierten Ergebnisse aus df_bills Befehl.

Während wir den Suchcodeblock unten ausführen, betten wir die Suchabfrage "Kann ich Informationen zu Steuereinnahmen für Kabelunternehmen abrufen?" mit demselben Text-Embedding-ada-002 (Version 2)- Modell ein. Als Nächstes finden wir das nächstgelegene Embedding zum neu eingebetteten Text aus unserer Abfrage, das nach Kosinusähnlichkeit bewertet wird.

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)

Ausgabe:

Screenshot der formatierten Ergebnisse von

Schließlich zeigen wir das oberste Ergebnis aus der Dokumentsuche basierend auf der Benutzerabfrage für die gesamte Wissensbasis an. Dies gibt das beste Ergebnis des "Gesetzes über das Recht der Steuerzahler von 1993" zurück. Dieses Dokument weist eine Kosinus-Ähnlichkeitsbewertung von 0,76 zwischen der Abfrage und dem Dokument auf.

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

Mit diesem Ansatz können Sie Einbettungen als Suchmechanismus für Dokumente in einer Wissensbasis verwenden. Der Benutzer kann dann das oberste Suchergebnis übernehmen und es für die Aufgabe verwenden, die ihre ursprüngliche Abfrage ausgelöst hat.

Problembehandlung

  • 401/403: Überprüfen Sie, ob AZURE_OPENAI_API_KEY festgelegt ist und mit Ihrem Ressourcenschlüssel übereinstimmt.
  • 404: Überprüfen Sie AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT Ihren Bereitstellungsnamen.
  • Ungültige URL: Stellen Sie sicher, dass AZURE_OPENAI_ENDPOINT Ihr Ressourcenendpunkt ist, z. B. https://<resource-name>.openai.azure.com.

Bereinigen von Ressourcen

Wenn Sie eine Azure OpenAI-Ressource nur zum Abschließen dieses Lernprogramms erstellt haben und eine Azure OpenAI-Ressource bereinigen und entfernen möchten, müssen Sie die bereitgestellten Modelle löschen und dann die Ressource oder die zugeordnete Ressourcengruppe löschen, wenn sie ihrer Testressource zugeordnet ist. Durch das Löschen der Ressourcengruppe werden auch alle anderen ressourcen gelöscht, die ihr zugeordnet sind.

Nächste Schritte

Erfahren Sie mehr über Azure OpenAI Modelle: