이 자습서에서는 Azure OpenAI 포함 API를 사용하여 문서 검색을 수행하는 과정을 안내합니다. 여기에서 기술 자료를 쿼리하여 가장 관련성이 높은 문서를 찾습니다.
이 튜토리얼에서는 다음을 배우게 됩니다:
- 샘플 데이터 세트를 다운로드하고 분석을 위해 준비합니다.
- 리소스 엔드포인트 및 API 키에 대한 환경 변수를 만듭니다.
- 다음 모델 중 하나를 사용합니다. text-embedding-ada-002(버전 2), text-embedding-3-large, text-embedding-3-small 모델.
- 코사인 유사성을 사용하여 검색 결과의 순위를 지정합니다.
필수 조건
- Azure 구독 - 무료로 생성하기
- text-embedding-ada-002(버전 2) 모델이 배포된 Microsoft Foundry 또는 Azure OpenAI 리소스입니다. 이 모델은 현재 특정 지역에서만 사용할 수 있습니다.
- 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 |
서비스 엔드포인트는 Azure Portal에서 리소스를 검사할 때 키 및 엔드포인트 섹션에서 찾을 수 있습니다. 또는 Microsoft Foundry 포털의 배포 페이지를 통해 엔드포인트를 찾을 수 있습니다. 예제 엔드포인트는 https://docs-test-001.openai.azure.com/입니다. |
API-KEY |
이 값은 Azure Portal에서 리소스를 검사할 때 키 및 엔드포인트 섹션에서 찾을 수 있습니다.
KEY1 또는 KEY2를 사용할 수 있습니다. |
Azure Portal에서 해당 리소스로 이동합니다.
키 및 엔드포인트 섹션은 리소스 관리 섹션에서 찾을 수 있습니다. 엔드포인트 및 액세스 키를 복사합니다. API 호출을 인증하는 데 모두 필요합니다.
KEY1 또는 KEY2를 사용할 수 있습니다. 항상 두 개의 키를 사용하면 서비스 중단 없이 키를 안전하게 회전하고 다시 생성할 수 있습니다.
환경 변수
API 키에 대한 영구 환경 변수를 만들고 할당합니다.
중요합니다
주의해서 API 키를 사용합니다. API 키를 코드에 직접 포함하지 말고, 공개적으로 게시하지 마세요. API 키를 사용하는 경우 Azure Key Vault에 안전하게 저장합니다. 앱에서 API 키를 안전하게 사용하는 방법에 대한 자세한 내용은 Azure Key Vault를 사용하여 API 키를 참조하세요.
AI 서비스 보안에 대한 자세한 내용은 Azure AI 서비스에 대한 요청 인증을 참조하세요.
setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE"
환경 변수를 설정한 후 환경 변수에 액세스하려면 Jupyter Notebooks 또는 사용 중인 IDE를 닫았다가 다시 열어야 할 수 있습니다. Jupyter Notebooks를 사용하는 것이 강력히 권장되지만, 어떤 이유로든 할 수 없는 경우 코드 블록의 끝에서 자주 수행되는 것처럼 print(dataframe_name)을 직접 호출하는 대신 dataframe_name을 사용하여 pandas 데이터 프레임을 반환하는 모든 코드를 수정해야 합니다.
기본 설정하는 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
출력:
초기 테이블에는 필요한 것보다 더 많은 열이 있습니다. df_bills, text 및 summary에 대한 열만 포함하는 title라는 더 작은 새 DataFrame을 만듭니다.
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
문서의 경우 의도적으로 출력을 자르지만 환경에서 이 명령을 실행하면 청크로 토큰화된 인덱스 0의 전체 텍스트가 반환됩니다. 어떤 경우에는 전체 단어가 단일 토큰으로 표시되는 반면 다른 경우에는 단어의 일부가 여러 토큰으로 분할되는 것을 볼 수 있습니다.
[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 데이터베이스에 저장하여 벡터 검색을 지원할 수 있습니다. 결과적으로 각 청구서에는 DataFrame의 오른쪽에 있는 새 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
출력:
아래의 검색 코드 블록을 실행할 때 동일한 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)
출력:
마지막으로 전체 기술 자료에 대한 사용자 쿼리를 기반으로 문서 검색의 최상위 결과를 표시합니다. "Taxpayer's Right to View Act of 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."
이 방식을 사용하면 기술 자료의 문서 전체에서 포함을 검색 메커니즘으로 사용할 수 있습니다. 그런 다음 사용자는 상위 검색 결과를 가져와 다운스트림 작업에 사용할 수 있으며 이로 인해 초기 쿼리가 표시됩니다.
자원을 정리하세요
이 자습서를 완료하기 위해서 Azure OpenAI 리소스만 만들었고 Azure OpenAI 리소스를 정리하고 제거하려는 경우 배포된 모델을 삭제한 다음 테스트 리소스 전용인 경우 리소스 또는 연결된 리소스 그룹을 삭제해야 합니다. 리소스 그룹을 삭제하면 해당 리소스 그룹에 연결된 다른 모든 리소스가 함께 삭제됩니다.
다음 단계
Azure OpenAI의 모델에 대해 자세히 알아봅니다.
- 선택한 Azure 서비스를 사용하여 포함을 저장하고 벡터(유사성) 검색을 수행합니다.