Zelfstudie: Ontdek Azure OpenAI en Microsoft Foundry Model-embeddings en documentzoekopdrachten.

In deze zelfstudie wordt u begeleid bij het gebruik van de API Azure OpenAI embeddings API voor het uitvoeren van documentzoekopdrachten waar u een query uitvoert op een knowledge base om het meest relevante document te vinden.

In deze zelfstudie leert u het volgende:

  • Download een voorbeeldgegevensset en bereid deze voor op analyse.
  • Maak omgevingsvariabelen voor uw resources-eindpunt en API-sleutel.
  • Gebruik een van de volgende modellen: text-embedding-ada-002 (versie 2), text-embedding-3-large, text-embedding-3-small.
  • Gebruik cosinus-gelijkenis om zoekresultaten te rangschikken.

Voorwaarden

Instellen

Python bibliotheken

Als u dat nog niet hebt gedaan, moet u de volgende bibliotheken installeren:

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

BillSum-gegevensset downloaden

BillSum is een gegevensset met wetsvoorstellen van het Amerikaanse Congres en de staat Californië. Ter illustratie kijken we alleen naar de Amerikaanse rekeningen. Het corpus bestaat uit rekeningen van de 103e-115e (1993-2018) sessies van congres. De gegevens zijn gesplitst in 18.949 treinfactuur en 3.269 testfactuur. Het BillSum-corpus richt zich op wetgeving van gemiddelde lengte, van 5.000 tot 20.000 tekens. Meer informatie over het project en het oorspronkelijke academische document waaruit deze gegevensset is afgeleid, vindt u in de GitHub BillSum-projectopslagplaats

In deze zelfstudie wordt het bill_sum_data.csv-bestand gebruikt dat kan worden gedownload van onze GitHub-samplegegevens.

U kunt de voorbeeldgegevens ook downloaden door de volgende opdracht uit te voeren op uw lokale computer:

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

Opmerking

Microsoft Entra ID gebaseerde verificatie wordt momenteel niet ondersteund voor insluitingen met de v1-API.

Sleutel en eindpunt ophalen

Als u Azure OpenAI wilt aanroepen, hebt u een endpoint en een key nodig.

Variabelenaam Waarde
ENDPOINT Het service-eindpunt vindt u in de Keys & Endpoint-sectie bij het onderzoeken van uw resource vanuit de Azure-portal. U kunt het eindpunt ook vinden via de pagina Deployments in Microsoft Foundry-portal. Een voorbeeldeindpunt is: https://docs-test-001.openai.azure.com/.
API-KEY Deze waarde vindt u in de Sleutels & Eindpunt sectie bij het onderzoeken van uw resource vanuit de Azure-portal. U kunt KEY1 of KEY2 gebruiken.

Ga naar uw resource in de Azure-portal. De sectie Sleutels en eindpunt vindt u in de sectie Resourcebeheer . Kopieer uw eindpunt en toegangssleutel, omdat u beide nodig hebt voor het verifiëren van uw API-aanroepen. U kunt KEY1 of KEY2 gebruiken. Als u altijd twee sleutels hebt, kunt u sleutels veilig roteren en opnieuw genereren zonder een serviceonderbreking te veroorzaken.

Schermopname van de overzichtsinterface voor een Azure OpenAI-resource in de Azure-portal met het eindpunt en de toegangssleutels omcirkeld in red.

Omgevingsvariabelen

Maak en wijs permanente omgevingsvariabelen toe voor uw API-sleutel.

Belangrijk

Gebruik API-sleutels met voorzichtigheid. Neem de API-sleutel niet rechtstreeks in uw code op en plaats deze nooit openbaar. Als u een API-sleutel gebruikt, slaat u deze veilig op in Azure Key Vault. Zie API-sleutels met Azure Key Vault voor meer informatie over het veilig gebruiken van API-sleutels in uw apps.

Zie Authenticate requests to Azure AI-services voor meer informatie over beveiliging van AI-services.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 

Nadat u de omgevingsvariabelen hebt ingesteld, moet u mogelijk Jupyter-notebooks sluiten en opnieuw openen of welke IDE u gebruikt om de omgevingsvariabelen toegankelijk te maken. Hoewel we het gebruik van Jupyter Notebooks ten zeerste aanbevelen, als u om een of andere reden ze niet kunt gebruiken, moet u de code die een pandas-dataframe retourneert aanpassen door print(dataframe_name) te gebruiken in plaats van simpelweg dataframe_name direct aan te roepen, zoals vaak wordt gedaan aan het einde van een codeblok.

Voer de volgende code uit in de Python IDE van uw voorkeur:

Bibliotheken importeren

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

Nu moeten we ons CSV-bestand lezen en een Pandas DataFrame maken. Nadat het eerste DataFrame is gemaakt, kunnen we de inhoud van de tabel bekijken door deze uit te voeren 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:

Schermopname van de eerste DataFrame-tabelresultaten uit het CSV-bestand.

De eerste tabel bevat meer kolommen dan we nodig hebben, we maken een nieuw kleiner DataFrame df_bills dat alleen de kolommen voor text, summaryen titlebevat.

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

Output:

Schermopname van de kleinere resultaten van de DataFrame-tabel met alleen tekst-, samenvattings- en titelkolommen weergegeven.

Vervolgens gaan we een lichte gegevensopschoning uitvoeren door redundante witruimte te verwijderen en de interpunctie schoon te maken om de gegevens voor te bereiden op de tokenisatie.

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

Nu moeten we alle facturen verwijderen die te lang zijn voor de tokenlimiet (8.192 tokens).

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

Opmerking

In dit geval vallen alle facturen onder de limiet voor invoertoken van het insluitmodel, maar u kunt de bovenstaande techniek gebruiken om vermeldingen te verwijderen die anders ertoe leiden dat insluiten mislukt. Wanneer u te maken hebt met inhoud die de insluitingslimiet overschrijdt, kunt u de inhoud ook opdelen in kleinere stukken en vervolgens de segmenten één voor één insluiten.

We onderzoeken opnieuw df_bills.

df_bills

Output:

Schermopname van het DataFrame met een nieuwe kolom met de naam n_tokens.

Als u meer inzicht wilt in de n_tokens kolom en hoe tekst uiteindelijk wordt getokeniseerd, kan het handig zijn om de volgende code uit te voeren:

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

Voor onze documentatie wordt de uitvoer opzettelijk afgekapt, maar als u deze opdracht uitvoert in uw omgeving, wordt de volledige tekst geretourneerd van index nul tokenized in delen. In sommige gevallen ziet u dat een heel woord wordt weergegeven met één token, terwijl in andere delen van woorden meerdere tokens worden gesplitst.

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

Als u vervolgens de lengte van de decode variabele controleert, ziet u dat deze overeenkomt met het eerste getal in de kolom n_tokens.

len(decode)
1466

Nu we meer weten over hoe tokenisatie werkt, kunnen we doorgaan met insluiten. Het is belangrijk om te weten dat we de documenten nog niet hebben tokeneerd. De n_tokens kolom is gewoon een manier om ervoor te zorgen dat geen van de gegevens die we doorgeven aan het model voor tokenisatie en insluiten de limiet van het invoertoken van 8.192 overschrijdt. Wanneer we de documenten doorgeven aan het insluitingsmodel, worden de documenten opgesplitst in tokens die vergelijkbaar zijn (hoewel niet noodzakelijkerwijs identiek) aan de bovenstaande voorbeelden en worden de tokens vervolgens geconverteerd naar een reeks drijvendekommanummers die toegankelijk zijn via vectorzoekopdrachten. Deze insluitingen kunnen lokaal of in een Azure Database worden opgeslagen ter ondersteuning van Vector Search. Als gevolg hiervan heeft elke factuur een eigen bijbehorende insluitingsvector in de nieuwe ada_v2 kolom aan de rechterkant van het DataFrame.

In het onderstaande voorbeeld roepen we het insluitmodel één keer aan per item dat we willen insluiten. Wanneer u met grote insluitingsprojecten werkt, kunt u het model ook een array met invoer aanbieden om in te sluiten, in plaats van één invoer tegelijk. Wanneer u het model een reeks invoeritems doorgeeft, is het maximale aantal invoeritems per oproep naar het ingesloten eindpunt 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:

Schermopname van de opgemaakte resultaten van df_bills opdracht.

Terwijl we het onderstaande zoekcodeblok uitvoeren, sluiten we de zoekquery 'Kan ik informatie krijgen over belastingopbrengst van kabelbedrijf?' in met hetzelfde model voor tekst-embedding-ada-002 (versie 2). Vervolgens vinden we de dichtstbijzijnde embedding van facturen voor de nieuw ingesloten tekst uit onze query, gerangschikt op cosinus-gelijkenis.

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)

Uitvoer:

Schermopname van de opgemaakte resultaten van res zodra de zoekquery is uitgevoerd.

Ten slotte tonen we het belangrijkste resultaat van een documentzoekopdracht, gebaseerd op de gebruikersquery tegen de volledige Knowledge Base. Dit geeft het belangrijkste resultaat van de "Wet op het recht van de belastingbetaler om in te zien, 1993." Dit document heeft een cosine similariteitsscore van 0,76 tussen de query en het document.

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

Met deze methode kunt u insluitingen gebruiken als zoekmechanisme voor documenten in een knowledge base. De gebruiker kan vervolgens het bovenste zoekresultaat nemen en gebruiken voor hun downstream-taak, die hun eerste query heeft aangestuurd.

Probleemoplossing

  • 401/403: Controleer of AZURE_OPENAI_API_KEY is ingesteld en overeenkomt met uw resource-sleutel.
  • 404: Controleer of AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT deze overeenkomt met uw implementatienaam.
  • Ongeldige URL: Controleer AZURE_OPENAI_ENDPOINT of uw resource-eindpunt is, bijvoorbeeld https://<resource-name>.openai.azure.com.

Resources opschonen

Als u een Azure OpenAI-resource hebt gemaakt om deze zelfstudie te voltooien en een Azure OpenAI-resource wilt verwijderen, moet u de geïmplementeerde modellen verwijderen en vervolgens de resource of de bijbehorende resourcegroep verwijderen als deze is toegewezen aan uw testresource. Als u de resourcegroep verwijdert, worden ook alle andere resources verwijderd die eraan zijn gekoppeld.

Volgende stappen

Meer informatie over de modellen van Azure OpenAI: