다음을 통해 공유


자습서: Azure AI 검색에서 RAG에 대한 인덱싱 파이프라인 빌드

Azure AI 검색에서 RAG 솔루션에 대한 자동화된 인덱싱 파이프라인을 빌드하는 방법을 알아봅니다. 인덱싱 자동화는 인덱싱 및 기술 세트 실행을 구동하는 인덱서를 통해 이루어지며, 증분 업데이트를 위해 일회성 또는 반복적으로 통합 데이터 청크 및 벡터화를 제공합니다.

이 자습서에서는 다음을 수행합니다.

  • 이전 자습서의 인덱스 스키마 제공
  • 데이터 원본 연결 만들기
  • 인덱서 만들기
  • 엔터티를 청크화, 벡터화 및 인식하는 기술 세트를 만듭니다.
  • 인덱서 실행 및 결과 확인

Azure 구독이 없는 경우 시작하기 전에 체험 계정을 만듭니다.

데이터 가져오기 및 벡터화 마법사를 사용하여 파이프라인을 만들 수 있습니다. 이미지 검색 및 벡터 검색같은 몇 가지 빠른 시작을 사용해 보세요.

필수 조건

샘플 다운로드

GitHub에서 Jupyter Notebook을 다운로드하여 Azure AI 검색으로 요청을 보냅니다. 자세한 내용은 GitHub에서 파일 다운로드를 참조하세요.

인덱스 스키마 제공

Visual Studio Code에서 Jupyter Notebook(.ipynb)을 열거나 만들어 파이프라인을 구성하는 스크립트를 포함합니다. 초기 단계에서는 패키지를 설치하고 연결에 대한 변수를 수집합니다. 설치 단계를 완료하면 인덱싱 파이프라인의 구성 요소로 시작할 준비가 된 것입니다.

이전 자습서의 인덱스 스키마부터 살펴보겠습니다. 벡터화된 청크 및 비벡터화 청크를 중심으로 구성됩니다. 여기에는 기술 세트에서 만든 AI 생성 콘텐츠를 저장하는 locations 필드가 포함됩니다.

from azure.identity import DefaultAzureCredential
from azure.identity import get_bearer_token_provider
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents.indexes.models import (
    SearchField,
    SearchFieldDataType,
    VectorSearch,
    HnswAlgorithmConfiguration,
    VectorSearchProfile,
    AzureOpenAIVectorizer,
    AzureOpenAIVectorizerParameters,
    SearchIndex
)

credential = DefaultAzureCredential()

# Create a search index  
index_name = "py-rag-tutorial-idx"
index_client = SearchIndexClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential)  
fields = [
    SearchField(name="parent_id", type=SearchFieldDataType.String),  
    SearchField(name="title", type=SearchFieldDataType.String),
    SearchField(name="locations", type=SearchFieldDataType.Collection(SearchFieldDataType.String), filterable=True),
    SearchField(name="chunk_id", type=SearchFieldDataType.String, key=True, sortable=True, filterable=True, facetable=True, analyzer_name="keyword"),  
    SearchField(name="chunk", type=SearchFieldDataType.String, sortable=False, filterable=False, facetable=False),  
    SearchField(name="text_vector", type=SearchFieldDataType.Collection(SearchFieldDataType.Single), vector_search_dimensions=1024, vector_search_profile_name="myHnswProfile")
    ]  
  
# Configure the vector search configuration  
vector_search = VectorSearch(  
    algorithms=[  
        HnswAlgorithmConfiguration(name="myHnsw"),
    ],  
    profiles=[  
        VectorSearchProfile(  
            name="myHnswProfile",  
            algorithm_configuration_name="myHnsw",  
            vectorizer_name="myOpenAI",  
        )
    ],  
    vectorizers=[  
        AzureOpenAIVectorizer(  
            vectorizer_name="myOpenAI",  
            kind="azureOpenAI",  
            parameters=AzureOpenAIVectorizerParameters(  
                resource_url=AZURE_OPENAI_ACCOUNT,  
                deployment_name="text-embedding-3-large",
                model_name="text-embedding-3-large"
            ),
        ),  
    ], 
)  
  
# Create the search index
index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search)  
result = index_client.create_or_update_index(index)  
print(f"{result.name} created")  

데이터 원본 연결 만들기

이 단계에서는 샘플 데이터와 Azure Blob Storage에 대한 연결을 설정합니다. 인덱서는 컨테이너에서 PDF를 검색합니다. 이 단계에서 컨테이너를 만들고 파일을 업로드합니다.

원본 전자책은 100페이지가 넘고 크기는 35MB가 넘는 대용량입니다. API 호출당 16MB의 인덱서 및 AI 보강 데이터 제한에 대한 문서 제한을 유지하기 위해 텍스트 페이지당 하나씩 더 작은 PDF로 분할했습니다. 간단한 설명을 위해 이 연습에서는 이미지 벡터화를 생략합니다.

  1. Azure Portal에 로그인하고 Azure Storage 계정을 찾습니다.

  2. 컨테이너를 만들고 earth_book_2019_text_pages PDF를 업로드합니다.

  3. Azure AI Search에 리소스에 대한 Storage Blob 데이터 판독 기 권한이 있는지 확인합니다 .

  4. 다음으로, Visual Studio Code에서 인덱싱 중에 연결 정보를 제공하는 인덱서 데이터 원본을 정의합니다.

    from azure.search.documents.indexes import SearchIndexerClient
    from azure.search.documents.indexes.models import (
        SearchIndexerDataContainer,
        SearchIndexerDataSourceConnection
    )
    
    # Create a data source 
    indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential)
    container = SearchIndexerDataContainer(name="nasa-ebooks-pdfs-all")
    data_source_connection = SearchIndexerDataSourceConnection(
        name="py-rag-tutorial-ds",
        type="azureblob",
        connection_string=AZURE_STORAGE_CONNECTION,
        container=container
    )
    data_source = indexer_client.create_or_update_data_source_connection(data_source_connection)
    
    print(f"Data source '{data_source.name}' created or updated")
    

연결에 대한 Azure AI Search에 대한 관리 ID를 설정하는 경우 연결 문자열 접미사가 포함됩니다ResourceId=. 다음 예제와 유사하게 표시됩니다. "ResourceId=/subscriptions/FAKE-SUBCRIPTION=ID/resourceGroups/FAKE-RESOURCE-GROUP/providers/Microsoft.Storage/storageAccounts/FAKE-ACCOUNT;"

기술 세트 만들기

기술은 통합 데이터 청크 및 벡터화의 기초입니다. 최소한 텍스트 분할 기술이 콘텐츠를 청크로 만들고 청크 분할된 콘텐츠의 벡터 표현을 만드는 포함 기술을 원합니다.

이 기술 세트에서는 인덱스로 구조화된 데이터를 만드는 데 추가 기술이 사용됩니다. 엔터티 인식 기술은 적절한 이름에서 "바다" 또는 "산"과 같은 일반 참조에 이르기까지 다양한 위치를 식별하는 데 사용됩니다. 구조화된 데이터를 사용하면 흥미로운 쿼리를 만들고 관련성을 높일 수 있는 더 많은 옵션을 제공합니다.

역할 기반 액세스 제어를 사용하는 경우에도 AZURE_AI_MULTISERVICE_KEY 필요합니다. Azure AI Search는 청구 목적으로 키를 사용하며 워크로드가 무료 한도를 유지하지 않는 한 필요합니다. 최신 미리 보기 API 또는 베타 패키지를 사용하는 경우 키 없는 연결을 사용할 수도 있습니다. 자세한 내용은 기술 세트에 Azure AI 다중 서비스 리소스 연결을 참조 하세요.

from azure.search.documents.indexes.models import (
    SplitSkill,
    InputFieldMappingEntry,
    OutputFieldMappingEntry,
    AzureOpenAIEmbeddingSkill,
    EntityRecognitionSkill,
    SearchIndexerIndexProjection,
    SearchIndexerIndexProjectionSelector,
    SearchIndexerIndexProjectionsParameters,
    IndexProjectionMode,
    SearchIndexerSkillset,
    CognitiveServicesAccountKey
)

# Create a skillset  
skillset_name = "py-rag-tutorial-ss"

split_skill = SplitSkill(  
    description="Split skill to chunk documents",  
    text_split_mode="pages",  
    context="/document",  
    maximum_page_length=2000,  
    page_overlap_length=500,  
    inputs=[  
        InputFieldMappingEntry(name="text", source="/document/content"),  
    ],  
    outputs=[  
        OutputFieldMappingEntry(name="textItems", target_name="pages")  
    ],  
)  
  
embedding_skill = AzureOpenAIEmbeddingSkill(  
    description="Skill to generate embeddings via Azure OpenAI",  
    context="/document/pages/*",  
    resource_url=AZURE_OPENAI_ACCOUNT,  
    deployment_name="text-embedding-3-large",  
    model_name="text-embedding-3-large",
    dimensions=1536,
    inputs=[  
        InputFieldMappingEntry(name="text", source="/document/pages/*"),  
    ],  
    outputs=[  
        OutputFieldMappingEntry(name="embedding", target_name="text_vector")  
    ],  
)

entity_skill = EntityRecognitionSkill(
    description="Skill to recognize entities in text",
    context="/document/pages/*",
    categories=["Location"],
    default_language_code="en",
    inputs=[
        InputFieldMappingEntry(name="text", source="/document/pages/*")
    ],
    outputs=[
        OutputFieldMappingEntry(name="locations", target_name="locations")
    ]
)
  
index_projections = SearchIndexerIndexProjection(  
    selectors=[  
        SearchIndexerIndexProjectionSelector(  
            target_index_name=index_name,  
            parent_key_field_name="parent_id",  
            source_context="/document/pages/*",  
            mappings=[  
                InputFieldMappingEntry(name="chunk", source="/document/pages/*"),  
                InputFieldMappingEntry(name="text_vector", source="/document/pages/*/text_vector"),
                InputFieldMappingEntry(name="locations", source="/document/pages/*/locations"),  
                InputFieldMappingEntry(name="title", source="/document/metadata_storage_name"),  
            ],  
        ),  
    ],  
    parameters=SearchIndexerIndexProjectionsParameters(  
        projection_mode=IndexProjectionMode.SKIP_INDEXING_PARENT_DOCUMENTS  
    ),  
) 

cognitive_services_account = CognitiveServicesAccountKey(key=AZURE_AI_MULTISERVICE_KEY)

skills = [split_skill, embedding_skill, entity_skill]

skillset = SearchIndexerSkillset(  
    name=skillset_name,  
    description="Skillset to chunk documents and generating embeddings",  
    skills=skills,  
    index_projection=index_projections,
    cognitive_services_account=cognitive_services_account
)
  
client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential)  
client.create_or_update_skillset(skillset)  
print(f"{skillset.name} created")

인덱서 만들기 및 실행

인덱서는 동작 중인 모든 프로세스를 설정하는 구성 요소입니다. 비활성화된 상태에서 인덱서를 만들 수 있지만 기본값은 즉시 실행하는 것입니다. 이 자습서에서는 인덱서를 만들고 실행하여 Blob Storage에서 데이터를 검색하고, 청크 및 벡터화를 비롯한 기술을 실행하고, 인덱스 로드를 수행합니다.

인덱서는 실행하는 데 몇 분 정도 걸립니다. 완료되면 인덱스 쿼리의 마지막 단계로 이동할 수 있습니다.

from azure.search.documents.indexes.models import (
    SearchIndexer,
    FieldMapping
)

# Create an indexer  
indexer_name = "py-rag-tutorial-idxr" 

indexer_parameters = None

indexer = SearchIndexer(  
    name=indexer_name,  
    description="Indexer to index documents and generate embeddings",  
    skillset_name=skillset_name,  
    target_index_name=index_name,  
    data_source_name=data_source.name,
    # Map the metadata_storage_name field to the title field in the index to display the PDF title in the search results  
    field_mappings=[FieldMapping(source_field_name="metadata_storage_name", target_field_name="title")],
    parameters=indexer_parameters
)  

# Create and run the indexer  
indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential)  
indexer_result = indexer_client.create_or_update_indexer(indexer)  

print(f' {indexer_name} is created and running. Give the indexer a few minutes before running a query.')    

쿼리를 실행하여 결과 확인

쿼리를 보내 인덱스가 작동하는지 확인합니다. 이 요청은 텍스트 문자열 "what's NASA's website?"을 벡터 검색을 위한 벡터로 변환합니다. 결과는 select 문의 필드로 구성되며, 그 중 일부는 출력으로 인쇄됩니다.

현재 채팅 또는 생성 AI는 없습니다. 결과는 검색 인덱스에서 축자 콘텐츠입니다.

from azure.search.documents import SearchClient
from azure.search.documents.models import VectorizableTextQuery

# Vector Search using text-to-vector conversion of the querystring
query = "what's NASA's website?"  

search_client = SearchClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential, index_name=index_name)
vector_query = VectorizableTextQuery(text=query, k_nearest_neighbors=50, fields="text_vector")
  
results = search_client.search(  
    search_text=query,  
    vector_queries= [vector_query],
    select=["chunk"],
    top=1
)  
  
for result in results:  
    print(f"Score: {result['@search.score']}")
    print(f"Chunk: {result['chunk']}")

이 쿼리는 검색 엔진이 가장 관련성이 있다고 판단한 하나의 청크로 구성된 단일 일치 항목(top=1)을 반환합니다. 쿼리의 결과는 다음 예제와 유사해야 합니다.

Score: 0.01666666753590107
Chunk: national Aeronautics and Space Administration

earth Science

NASA Headquarters 

300 E Street SW 

Washington, DC 20546

www.nasa.gov

np-2018-05-2546-hQ

몇 가지 쿼리를 더 시도하여 검색 엔진이 직접 반환하는 내용을 파악하여 LLM 사용 응답과 비교할 수 있습니다. 이 쿼리 "patagonia geography" 를 사용하여 이전 스크립트를 다시 실행하고 3으로 설정 top 하여 둘 이상의 응답을 반환합니다.

이 두 번째 쿼리의 결과는 간결하게 편집되는 다음 결과와 유사해야 합니다. 출력은 Notebook에서 복사되어 이 예제에 표시된 내용에 대한 응답을 자른다. 셀 출력을 확장하여 전체 답변을 검토할 수 있습니다.

Score: 0.03306011110544205
Chunk: 

Swirling Bloom off Patagonia
Argentina

Interesting art often springs out of the convergence of different ideas and influences. 
And so it is with nature. 

Off the coast of Argentina, two strong ocean currents converge and often stir up a colorful 
brew, as shown in this Aqua image from 

December 2010. 

This milky green and blue bloom formed on the continental shelf off of Patagonia, where warmer, 
saltier waters from the subtropics 

meet colder, fresher waters flowing from the south. Where these currents collide, turbulent 
eddies and swirls form, pulling nutrients 

up from the deep ocean. The nearby Rio de la Plata also deposits nitrogen- and iron-laden 
sediment into the sea. Add in some 
...

while others terminate in water. The San Rafael and San Quintín glaciers (shown at the right) 
are the icefield’s largest. Both have 

been receding rapidly in the past 30 years.

이 예제에서는 청크가 축자식으로 반환되는 방법과 키워드 및 유사성 검색에서 상위 일치 항목을 식별하는 방법을 더 쉽게 파악할 수 있습니다. 이 특정 청크에는 확실히 파타고니아 및 지리에 대한 정보가 있지만 쿼리와 정확히 관련이 없습니다. 의미 체계 순위는 더 나은 답변을 위해 더 관련성이 높은 청크를 승격하지만, 다음 단계로 대화형 검색을 위해 Azure AI Search를 LLM에 연결하는 방법을 살펴보겠습니다.

다음 단계