Поделиться через


Руководство: Изучение Azure OpenAI в Microsoft Foundry Models: встраивания и поиск документов

В этом руководстве вы узнаете, как использовать API внедрения Azure OpenAI для выполнения поиска документов, где будет запрашиваться база знаний, чтобы найти наиболее подходящий документ.

В этом руководстве вы узнаете, как:

  • Скачайте пример набора данных и подготовьте его к анализу.
  • Создайте переменные среды для конечной точки ресурсов и ключа API.
  • Используйте одну из следующих моделей: text-embedding-ada-002 (версия 2), text-embedding-3-large, text-embedding-3-small models.
  • Используйте косинусное сходство для ранжирования результатов поиска.

Предпосылки

Настройка

Библиотеки Python

Если вы еще не сделали этого, необходимо установить следующие библиотеки:

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

Скачивание набора данных BillSum

BillSum — это набор данных законопроектов Конгресса США и штата Калифорния. Для иллюстрации мы рассмотрим только счета США. Корпус состоит из законопроектов от 103-го-115-го (1993-2018) сессий Конгресса. Данные были разделены на 18 949 счетов за обучение и 3269 тестовых счетов. Корпус BillSum фокусируется на законодательных документах средней длины, от 5000 до 20 000 символов. Дополнительные сведения о проекте и исходном учебном документе, из которого получен этот набор данных, можно найти в репозитории 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

Замечание

Проверка подлинности на основе идентификатора Microsoft Entra в настоящее время не поддерживается для внедрения с помощью API версии 1.

Получение ключа и конечной точки

Чтобы успешно выполнить вызов к Azure OpenAI, вам потребуется конечная точка и ключ.

Имя переменной Ценность
ENDPOINT Конечную точку службы можно найти в разделе "Ключи и конечная точка" при изучении вашего ресурса в портале Azure. Кроме того, можно найти конечную точку на странице "Развертывания " на портале Microsoft Foundry. Пример конечной точки: https://docs-test-001.openai.azure.com/.
API-KEY Это значение можно найти в разделе Ключи и конечная точка при просмотре ресурса на портале Azure. Вы можете использовать KEY1 или KEY2.

Перейдите к своему ресурсу на портале Azure. Раздел "Ключи и конечная точка " можно найти в разделе "Управление ресурсами". Скопируйте конечную точку и ключ доступа, так как они потребуются для проверки подлинности вызовов API. Вы можете использовать KEY1 или KEY2. Наличие двух ключей позволяет безопасно менять и повторно создавать ключи без прерывания работы службы.

Снимок экрана пользовательского интерфейса обзора ресурса Azure OpenAI в портале Azure с конечной точкой и расположением ключей доступа, обведенные красным.

Переменные среды

Создайте и назначьте постоянные переменные среды для ключа API.

Это важно

Используйте ключи API с осторожностью. Не включайте ключ API непосредственно в код и никогда не публикуйте его. Если вы используете ключ API, сохраните его безопасно в Azure Key Vault. Дополнительные сведения об использовании ключей API безопасно в приложениях см. в разделе "Ключи API" с помощью Azure Key Vault.

Дополнительные сведения о безопасности служб ИИ см. в статье "Проверка подлинности запросов к службам ИИ Azure".

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 

После задания переменных среды может потребоваться закрыть и повторно открыть записные книжки Jupyter или любую интегрированную среду разработки, чтобы переменные среды были доступны. Хотя мы настоятельно рекомендуем использовать Jupyter Notebook, если по какой-то причине вы не можете, вам нужно будет изменить код, возвращающий pandas dataframe, использовав print(dataframe_name) вместо прямого вызова dataframe_name, как это часто делается в конце блока кода.

Запустите следующий код в предпочтительной интегрированной среде разработки Python:

Импорт библиотек

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

Выходные данные:

Снимок экрана: исходные результаты таблицы DataFrame (кадра данных) из CSV-файла.

Начальная таблица содержит больше столбцов, чем нам нужно, мы создадим новый меньший кадр df_bills данных, который будет содержать только столбцы для text, summaryи 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))

Теперь нам нужно удалить все документы, которые превышают ограничение в 8192 токена.

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.

Чтобы лучше понять столбец 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 столбец справа от кадра данных.

В приведенном ниже примере мы вызываем модель внедрения один раз на каждый элемент, который мы хотим внедрить. При работе с крупными проектами по встраиванию можно передать модели массив входных данных для встраивания, а не по одному вводу за раз. При передаче модели массива входных данных максимальное количество элементов на один вызов в конечную точку встраивания составляет 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 после запуска поискового запроса.

Наконец, будет показан лучший результат поиска документов на основе запроса пользователя по всей базе знаний. Это возвращает верхний результат "Право налогоплательщика на просмотр закона 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 соответствует имени развертывания.
  • Недопустимый URL-адрес: проверьте, является ли AZURE_OPENAI_ENDPOINT вашей конечной точкой ресурса, например https://<resource-name>.openai.azure.com.

Очистите ресурсы

Если вы создали ресурс Azure OpenAI исключительно для выполнения этого руководства и хотите очистить и удалить ресурс Azure OpenAI, необходимо удалить развернутые модели, а затем удалить ресурс или связанную группу ресурсов, если она выделена тестовым ресурсом. Удаление группы ресурсов также удаляет все другие ресурсы, связанные с ней.

Дальнейшие шаги

Дополнительные сведения о моделях Azure OpenAI: