Freigeben über


Tutorial: Minimieren des Speicherbedarfs und der Kosten (RAG in Azure KI-Suche)

Azure KI-Suche bietet mehrere Ansätze zur Verringerung der Größe von Vektorindizes. Diese Ansätze reichen von der Vektorkomprimierung bis hin zur selektiveren Auswahl, was Sie in Ihrem Suchdienst speichern.

In diesem Tutorial ändern Sie den vorhandenen Suchindex, um Folgendes zu verwenden:

  • Schmale Datentypen
  • Skalare Quantisierung
  • Reduzierter Speicher durch Deaktivieren von Vektoren in Suchergebnissen

In diesem Tutorial wird der Suchindex wiederverwendet, der von der Indizierungspipeline erstellt wurde. Alle diese Updates wirken sich auf den vorhandenen Inhalt aus, sodass Sie den Indexer erneut ausführen müssen. Anstatt jedoch den Suchindex zu löschen, erstellen Sie einen zweiten, sodass Sie die Reduzierung der Vektorindexgröße nach dem Hinzufügen der neuen Funktionen vergleichen können.

Insgesamt können die in diesem Tutorial veranschaulichten Techniken den verwendeten Vektorspeicher um etwa die Hälfte reduzieren.

Der folgende Screenshot vergleicht den ersten Index aus einem vorherigen Tutorial mit dem in diesem Tutorial erstellten Index.

Screenshot des ursprünglichen Vektorindexes mit dem Index, der mit dem Schema in diesem Tutorial erstellt wurde.

Voraussetzungen

Dieses Tutorial ist im Wesentlichen eine erneute Ausführung der Indizierungspipeline. Sie benötigen alle im entsprechenden Tutorial beschriebenen Azure-Ressourcen und -Berechtigungen.

Zum Vergleich sollten Sie über einen vorhandenen py-rag-tutorial-idx-Index für Ihren Azure KI-Suche-Dienst verfügen. Er sollte fast 2 MB groß sein, und der Vektorindexteil sollte 348 KB groß sein.

Sie sollten auch über die folgenden Objekte verfügen:

  • py-rag-tutorial-ds (Datenquelle)

  • py-rag-tutorial-ss (Skillset)

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.

Aktualisieren des Indexes für reduzierten Speicher

Azure KI-Suche bietet mehrere Ansätze zum Reduzieren der Vektorgröße, wodurch die Kosten von Vektorworkloads gesenkt werden. Erstellen Sie in diesem Schritt einen neuen Index, der die folgenden Funktionen verwendet:

  • Kleinere Vektorindizes durch Komprimieren der während der Abfrageausführung verwendeten Vektoren. Skalare Quantisierung bietet diese Funktion.

  • Kleinere Vektorindizes durch Deaktivieren des Vektorspeichers für Suchergebnisse. Wenn Sie nur Vektoren für Abfragen und nicht in der Antwortnutzlast benötigen, können Sie die für Suchergebnisse verwendete Vektorkopie ablegen.

  • Kleinere Vektorfelder durch schmale Datentypen. Sie können Collection(Edm.Half) für das Feld „text_vector“ angeben, um eingehende float32-Dimensionen als float16 zu speichern.

Alle diese Funktionen werden in einem Suchindex angegeben. Vergleichen Sie nach dem Laden des Indexes den Unterschied zwischen dem ursprünglichen Index und dem neuen.

  1. Geben Sie dem neuen Index den Namen py-rag-tutorial-small-vectors-idx.

  2. Verwenden Sie die folgende Definition für den neuen Index. Der Unterschied zwischen diesem Schema und den vorherigen Schemaaktualisierungen in Maximieren der Relevanz sind neue Klassen für die skalare Quantisierung und ein neuer Komprimierungsbereich, ein neuer Datentyp (Collection(Edm.Half)) für das Feld „text_vector“ und eine neue Eigenschaft stored, die auf „false“ festgelegt ist.

    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,
        ScalarQuantizationCompression,
        ScalarQuantizationParameters,
        SearchIndex,
        SemanticConfiguration,
        SemanticPrioritizedFields,
        SemanticField,
        SemanticSearch,
        ScoringProfile,
        TagScoringFunction,
        TagScoringParameters
    )
    
    credential = DefaultAzureCredential()
    
    index_name = "py-rag-tutorial-small-vectors-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="Collection(Edm.Half)", vector_search_dimensions=1024, vector_search_profile_name="myHnswProfile", stored= False)
        ]  
    
    # Configure the vector search configuration  
    vector_search = VectorSearch(  
        algorithms=[  
            HnswAlgorithmConfiguration(name="myHnsw"),
        ],  
        profiles=[  
            VectorSearchProfile(  
                name="myHnswProfile",  
                algorithm_configuration_name="myHnsw",
                compression_name="myScalarQuantization",
                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"
                ),
            ),  
        ],
        compressions=[
            ScalarQuantizationCompression(
                compression_name="myScalarQuantization",
                rerank_with_original_vectors=True,
                default_oversampling=10,
                parameters=ScalarQuantizationParameters(quantized_data_type="int8"),
            )
        ]
    )
    
    semantic_config = SemanticConfiguration(
        name="my-semantic-config",
        prioritized_fields=SemanticPrioritizedFields(
            title_field=SemanticField(field_name="title"),
            keywords_fields=[SemanticField(field_name="locations")],
            content_fields=[SemanticField(field_name="chunk")]
        )
    )
    
    semantic_search = SemanticSearch(configurations=[semantic_config])
    
    scoring_profiles = [  
        ScoringProfile(  
            name="my-scoring-profile",
            functions=[
                TagScoringFunction(  
                    field_name="locations",  
                    boost=5.0,  
                    parameters=TagScoringParameters(  
                        tags_parameter="tags",  
                    ),  
                ) 
            ]
        )
    ]
    
    index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search, semantic_search=semantic_search, scoring_profiles=scoring_profiles)  
    result = index_client.create_or_update_index(index)  
    print(f"{result.name} created")
    

Erstellen oder Wiederverwenden der Datenquelle

Dies ist die Definition der Datenquelle aus dem vorherigen Tutorial. Wenn Sie diese Datenquelle bereits in Ihrem Suchdienst haben, können Sie das Erstellen einer neuen Datenquelle überspringen.

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

Erstellen oder Wiederverwenden des Skillsets

Das Skillset ist ebenfalls gegenüber dem vorherigen Lernprogramm unverändert. Hier ist es noch einmal, damit Sie es überprüfen können.

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 eines neuen Indexers und Laden des Indexes

Obwohl Sie den vorhandenen Indexer mithilfe des neuen Indexes zurücksetzen und erneut ausführen können, ist es genauso einfach, einen neuen Indexer zu erstellen. Mit zwei Indizes und Indexern wird der Ausführungsverlauf beibehalten und ein genauerer Vergleich ermöglicht.

Dieser Indexer ist identisch mit dem vorherigen Indexer, mit der Ausnahme, dass er den neuen Index aus diesem Tutorial angibt.

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

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

indexer_parameters = None

indexer = SearchIndexer(  
    name=indexer_name,  
    description="Indexer to index documents and generate embeddings",
    target_index_name="py-rag-tutorial-small-vectors-idx",
    skillset_name="py-rag-tutorial-ss", 
    data_source_name="py-rag-tutorial-ds",
    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.')

Wechseln Sie als letzten Schritt zum Azure-Portal, um die Vektorspeicheranforderungen für die beiden Indizes zu vergleichen. Die Ergebnisse sollten etwa wie auf dem folgenden Screenshot aussehen.

Screenshot des ursprünglichen Vektorindexes mit dem Index, der mit dem Schema in diesem Tutorial erstellt wurde.

Der in diesem Tutorial erstellte Index verwendet Gleitkommazahlen mit halber Genauigkeit (float16) für die Textvektoren. Dies reduziert die Speicheranforderungen für die Vektoren um die Hälfte im Vergleich zum vorherigen Index, der Gleitkommazahlen mit einfacher Genauigkeit (float32) verwendet hat. Skalare Komprimierung und das Weglassen eines Vektorsatzes tragen zu den verbleibenden Speichereinsparungen bei. Weitere Informationen zum Reduzieren der Vektorgröße finden Sie unter Auswählen eines Ansatzes zur Optimierung der Vektorspeicherung und -verarbeitung.

Erwägen Sie, die Abfragen aus dem vorherigen Tutorial noch einmal anzusehen, damit Sie die Abfragegeschwindigkeit und das Hilfsprogramm vergleichen können. Sie sollten bei jeder Wiederholung einer Abfrage leichte Abweichungen in der LLM-Ausgabe erwarten, aber im Allgemeinen sollten die implementierten Speicherspartechniken die Qualität Ihrer Suchergebnisse nicht beeinträchtigen.

Nächster Schritt

Es gibt Codebeispiele in allen Azure-SDKs, die Programmierbarkeit für Azure KI-Suche bereitstellen. Sie können auch Vektorbeispielcode für bestimmte Anwendungsfälle und Technologiekombinationen überprüfen.