Zelfstudie: Opslag en kosten minimaliseren (RAG in Azure AI Search)
Azure AI Search biedt verschillende benaderingen voor het verminderen van de grootte van vectorindexen. Deze benaderingen variëren van vectorcompressie tot selectiever zijn over wat u opslaat in uw zoekservice.
In deze zelfstudie wijzigt u de bestaande zoekindex voor gebruik:
- Smalle gegevenstypen
- Scalaire kwantisatie
- Beperkte opslag door geen vectoren in zoekresultaten te gebruiken
In deze zelfstudie wordt de zoekindex die door de indexeringspijplijn is gemaakt, opnieuw uitgevoerd. Al deze updates zijn van invloed op de bestaande inhoud, waardoor u de indexeerfunctie opnieuw moet uitvoeren. In plaats van de zoekindex te verwijderen, maakt u echter een tweede index, zodat u minder vectorindexgrootten kunt vergelijken nadat u de nieuwe mogelijkheden hebt toegevoegd.
De technieken die in deze zelfstudie worden geïllustreerd, kunnen vectoropslag met ongeveer de helft verminderen.
In de volgende schermopname wordt de eerste index uit een vorige zelfstudie vergeleken met de index die in deze zelfstudie is ingebouwd.
Vereisten
Deze zelfstudie is in feite een nieuwe uitvoering van de indexeringspijplijn. U hebt alle Azure-resources en -machtigingen nodig die in die zelfstudie worden beschreven.
Ter vergelijking moet u een bestaande py-rag-tutorial-idx-index hebben op uw Azure AI-Search-service. Het moet bijna 2 MB groot zijn en het vectorindexgedeelte moet 348 kB zijn.
U moet ook de volgende objecten hebben:
py-rag-tutorial-ds (gegevensbron)
py-rag-tutorial-ss (vaardighedenset)
Het voorbeeld downloaden
Download een Jupyter-notebook vanuit GitHub om de aanvragen naar Azure AI Search te verzenden. Zie Bestanden downloaden van GitHub voor meer informatie.
De index voor verminderde opslag bijwerken
Azure AI Search heeft meerdere benaderingen voor het verminderen van de vectorgrootte, waardoor de kosten van vectorworkloads worden verlaagd. In deze stap maakt u een nieuwe index die gebruikmaakt van de volgende mogelijkheden:
Kleinere vectorindexen door de vectoren te comprimeren die worden gebruikt tijdens het uitvoeren van query's. Scalaire kwantisatie biedt deze mogelijkheid.
Kleinere vectorindexen door geen vectoropslag meer te gebruiken voor zoekresultaten. Als u alleen vectoren nodig hebt voor query's en niet in de nettolading van de reactie, kunt u de vectorkopie verwijderen die wordt gebruikt voor zoekresultaten.
Kleinere vectorvelden via smalle gegevenstypen. U kunt opgeven
Collection(Edm.Half)
op het text_vector veld om binnenkomende float32-dimensies op te slaan als float16.
Al deze mogelijkheden worden opgegeven in een zoekindex. Nadat u de index hebt geladen, vergelijkt u het verschil tussen de oorspronkelijke index en de nieuwe index.
Geef de nieuwe index
py-rag-tutorial-small-vectors-idx
een naam.Gebruik de volgende definitie voor de nieuwe index. Het verschil tussen dit schema en de vorige schema-updates in Relevantie maximaliseren zijn nieuwe klassen voor scalaire kwantisatie en een nieuwe sectie met compressies, een nieuw gegevenstype (
Collection(Edm.Half)
) voor het text_vector veld en een nieuwe eigenschapstored
ingesteld op onwaar.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")
De gegevensbron maken of opnieuw gebruiken
Hier volgt de definitie van de gegevensbron uit de vorige zelfstudie. Als u deze gegevensbron al in uw zoekservice hebt, kunt u het maken van een nieuwe overslaan.
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")
De vaardighedenset maken of opnieuw gebruiken
De vaardighedenset is ook ongewijzigd ten opzichte van de vorige zelfstudie. Hier is het opnieuw, zodat u het kunt bekijken.
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")
Een nieuwe indexeerfunctie maken en de index laden
Hoewel u de bestaande indexeerfunctie opnieuw kunt instellen en opnieuw kunt uitvoeren met behulp van de nieuwe index, is het net zo eenvoudig om een nieuwe indexeerfunctie te maken. Twee indexen en indexeerfuncties behouden de uitvoeringsgeschiedenis en maken een betere vergelijking mogelijk.
Deze indexeerfunctie is identiek aan de vorige indexeerfunctie, behalve dat de nieuwe index uit deze zelfstudie wordt opgegeven.
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.')
Als laatste stap schakelt u over naar Azure Portal om de vereisten voor vectoropslag voor de twee indexen te vergelijken. De resultaten moeten er ongeveer uitzien als in de volgende schermopname.
De index die in deze zelfstudie is gemaakt, maakt gebruik van zwevende kommanummers (float16) voor de tekstvectoren. Dit vermindert de opslagvereisten voor de vectoren met de helft vergeleken met de vorige index die gebruik maakte van drijvendekommanummers (float32). Scalaire compressie en het weglaten van één set vectoren zijn verantwoordelijk voor de resterende opslagbesparingen. Zie Een methode kiezen voor het optimaliseren van vectoropslag en -verwerking voor meer informatie over het verkleinen van vectorgrootte.
Overweeg de query's uit de vorige zelfstudie opnieuw te bekijken, zodat u de querysnelheid en het hulpprogramma kunt vergelijken. U zou een aantal variaties in LLM-uitvoer moeten verwachten wanneer u een query herhaalt, maar in het algemeen moet de opslagopslagtechnieken die u hebt geïmplementeerd, de kwaliteit van uw zoekresultaten niet verminderen.
Volgende stap
Er zijn codevoorbeelden in alle Azure SDK's die programmeerbaarheid van Azure AI Search bieden. U kunt ook vectorvoorbeeldcode bekijken voor specifieke use cases en technologiecombinaties.