Freigeben über


Tutorial: Erstellen einer Indizierungspipeline für RAG in Azure KI-Suche

Hier erfahren Sie, wie Sie eine automatisierte Indizierungspipeline für eine RAG-Lösung in Azure KI-Suche erstellen. Die Indizierungsautomatisierung erfolgt über einen Indexer, der die Indizierung und Skillset-Ausführung steuert und integrierte Datensegmentierung und Vektorisierung auf einmaliger oder wiederkehrender Basis für inkrementelle Updates bereitstellt.

In diesem Tutorial:

  • Bereitstellen des Indexschemas aus dem vorherigen Tutorial
  • Erstellen einer Datenquellenverbindung
  • Erstellen eines Indexers
  • Erstellen eines Skillsets, das Entitäten segmentiert, vektorisiert und erkennt
  • Ausführen des Indexers und Überprüfen der Ergebnisse

Wenn Sie kein Azure-Abonnement besitzen, können Sie ein kostenloses Konto erstellen, bevor Sie beginnen.

Tipp

Sie können den Assistenten zum Importieren und Vektorisieren von Daten verwenden, um Ihre Pipeline zu erstellen. Probieren Sie einige Schnellstarts aus: Bildsuche und Vektorsuche.

Voraussetzungen

Herunterladen des Beispiels

Laden Sie eine Jupyter Notebook-Instanz von GitHub herunter, um die Anforderungen an Azure KI-Suche zu senden. Weitere Informationen finden Sie unter Herunterladen von Dateien von GitHub.

Bereitstellen des Indexschemas

Öffnen oder erstellen Sie eine Jupyter Notebook-Instanz (.ipynb) in Visual Studio Code. Diese wird für die Skripts verwendet, aus denen sich die Pipeline zusammensetzt. In den ersten Schritten werden Pakete installiert und Variablen für die Verbindungen gesammelt. Nach Abschluss der Einrichtung können Sie mit den Komponenten der Indizierungspipeline beginnen.

Beginnen wir mit dem Indexschema aus dem vorherigen Tutorial. Seine Struktur basiert auf vektorisierten und nicht vektorisierten Blöcken. Es enthält ein locations-Feld, in dem KI-generierte, vom Skillset erstellte Inhalte gespeichert werden.

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

Erstellen einer Datenquellenverbindung

Richten Sie in diesem Schritt die Beispieldaten und eine Verbindung mit Azure Blob Storage ein. Der Indexer ruft PDF-Dateien aus einem Container ab. In diesem Schritt erstellen Sie den Container und laden Dateien hoch.

Das ursprüngliche E-Book ist groß, über 100 Seiten und 35 MB. Wir haben es in kleinere PDFs (eine pro Textseite) aufgeteilt, um unter dem Dokumentlimit für Indexer von 16 MB pro API-Aufruf und den Datenlimits für die KI-Anreicherung zu bleiben. Aus Gründen der Einfachheit wird die Bildvektorisierung für diese Übung weggelassen.

  1. Melden Sie sich beim Azure-Portal an, und navigieren Sie zu Ihrem Azure Storage-Konto.

  2. Erstellen Sie einen Container, und laden Sie die PDF-Dateien aus earth_book_2019_text_pages hoch.

  3. Stellen Sie sicher, dass Azure KI-Suche für die Ressource über Berechtigungen vom Typ Leser von Speicherblobdaten verfügt.

  4. Definieren Sie als Nächstes in Visual Studio Code eine Indexerdatenquelle, die während der Indizierung Verbindungsinformationen bereitstellt.

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

Wenn Sie eine verwaltete Identität für Azure KI-Suche für die Verbindung einrichten, enthält die Verbindungszeichenfolge ein Suffix ResourceId=. Sie sollte in etwa wie das folgende Beispiel aussehen: "ResourceId=/subscriptions/FAKE-SUBCRIPTION=ID/resourceGroups/FAKE-RESOURCE-GROUP/providers/Microsoft.Storage/storageAccounts/FAKE-ACCOUNT;"

Erstellen eines Skillsets

Skills sind die Grundlage für integrierte Datensegmentierung und Vektorisierung. Sie benötigen mindestens einen Textaufteilungsskill, um Ihre Inhalte zu segmentieren, und einen Einbettungsskill, um Vektordarstellungen Ihrer segmentierten Inhalte zu erstellen.

In diesem Skillset wird noch ein weiterer Skill verwendet, um strukturierte Daten im Index zu erstellen. Der Skill „Entitätserkennung“ wird verwendet, um Orte zu identifizieren, bei denen es sich um Eigennamen oder auch um allgemeine Begriffe wie „Meer“ oder „Berg“ handeln kann. Strukturierte Daten bieten mehr Möglichkeiten für die Erstellung interessanter Abfragen und zur Steigerung der Relevanz.

Der AZURE_AI_MULTISERVICE_KEY ist auch dann erforderlich, wenn Sie die rollenbasierte Zugriffssteuerung verwenden. Azure KI-Suche verwendet den Schlüssel zu Abrechnungszwecken. Er ist erforderlich, sofern Ihre Workloads nicht unter dem Limit für die kostenlose Nutzung bleiben. Sie können auch eine schlüssellose Verbindung herstellen, wenn Sie die neueste Vorschau-API oder Betapakete verwenden. Weitere Informationen finden Sie unter Anfügen einer Azure KI Multi-Service-Ressource an ein Skillset in Azure KI Search.

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

Erstellen und Ausführen des Indexers

Indexer sind die Komponente, die all die Prozesse in Gang bringen. Sie können zwar einen Indexer in einem deaktivierten Zustand erstellen, standardmäßig wird er jedoch sofort ausgeführt. Erstellen Sie in diesem Tutorial den Indexer, um die Daten aus Blob Storage abzurufen, führen Sie die Skills aus (einschließlich Segmentierung und Vektorisierung), und laden Sie den Index.

Die Ausführung des Indexers dauert mehrere Minuten. Nach Abschluss der Ausführung können Sie mit dem letzten Schritt fortfahren: dem Abfragen Ihres Indexes.

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

Ausführen einer Abfrage zur Überprüfung der Ergebnisse

Senden Sie eine Abfrage, um sich zu vergewissern, dass Ihr Index funktioniert. Diese Anforderung konvertiert die Textzeichenfolge what's NASA's website? in einen Vektor für eine Vektorsuche. Ergebnisse bestehen aus den Feldern in der select-Anweisung, von denen einige ausgegeben werden.

An diesem Punkt gibt es keine Chat- oder generative KI. Die Ergebnisse sind wortwörtlich aus Ihrem Suchindex übernommene Inhalte.

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']}")

Diese Abfrage gibt einen einzelnen Treffer (top=1) zurück, der aus dem einen Block besteht, der von der Suchmaschine als der relevanteste Block ermittelt wurde. Ergebnisse der Abfrage sollten in etwa wie im folgenden Beispiel aussehen:

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

Probieren Sie ein paar weitere Abfragen aus, um einen Eindruck davon zu bekommen, was die Suchmaschine direkt zurückgibt, damit Sie es mit einer Antwort mit LLM-Unterstützung vergleichen können. Führen Sie das vorherige Skript erneut mit dieser Abfrage aus: "patagonia geography". Legen Sie top dabei auf 3 fest, um mehr als eine Antwort zurückzugeben.

Ergebnisse aus dieser zweiten Abfrage sollten ähnlich wie die folgenden Ergebnisse aussehen. Diese wurden leicht bearbeitet, um sie klarer zu machen. Die Ausgabe wird aus dem Notebook kopiert, wodurch die Antwort wie im Beispiel gezeigt abgeschnitten wird. Sie können die Zellenausgabe erweitern, um die vollständige Antwort zu überprüfen.

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.

An diesem Beispiel ist besser zu sehen, wie Blöcke 1:1 zurückgegeben werden und wie die Schlüsselwort- und Ähnlichkeitssuche die besten Übereinstimmungen identifiziert. Dieser spezifische Block enthält zwar durchaus Informationen zu Patagonien und zur Geografie, ist aber nicht wirklich relevant für die Abfrage. Der semantische Sortierer würde relevantere Blöcke für eine bessere Antwort liefern. Im nächsten Schritt erfahren Sie jedoch, wie Sie Azure KI-Suche für eine unterhaltungsbasierte Suche mit einem LLM (Large Language Model) verbinden.

Nächster Schritt