Esercitazione: Ridurre al minimo l'archiviazione e i costi (RAG in Ricerca di intelligenza artificiale di Azure)
Ricerca di intelligenza artificiale di Azure offre diversi approcci per ridurre le dimensioni degli indici vettoriali. Questi approcci variano dalla compressione vettoriale alla maggiore selettività rispetto a ciò che si archivia nel servizio di ricerca.
In questa esercitazione si modifica l'indice di ricerca esistente in modo da usare:
- Tipi di dati Narrow
- Quantizzazione scalare
- Riduzione dello spazio di archiviazione rifiutando esplicitamente i vettori nei risultati della ricerca
Questa esercitazione riprende l'indice di ricerca creato dalla pipeline di indicizzazione. Tutti questi aggiornamenti influiscono sul contenuto esistente, richiedendo di rieseguire l'indicizzatore. Tuttavia, invece di eliminare l'indice di ricerca, si crea un secondo in modo da poter confrontare le riduzioni delle dimensioni dell'indice vettoriale dopo aver aggiunto le nuove funzionalità.
Complessivamente, le tecniche illustrate in questa esercitazione possono ridurre l'archiviazione vettoriale di circa la metà.
Lo screenshot seguente confronta il primo indice di un'esercitazione precedente con l'indice compilato in questo.
Prerequisiti
Questa esercitazione è essenzialmente una riesecuzione della pipeline di indicizzazione. Tutte le risorse e le autorizzazioni di Azure sono necessarie in questa esercitazione.
Per un confronto, è necessario avere un indice py-rag-tutorial-idx esistente nel servizio di ricerca di Intelligenza artificiale di Azure. Dovrebbe essere di dimensioni pari a quasi 2 MB e la parte dell'indice vettoriale deve essere di 348 KB.
Dovrebbero essere presenti anche gli oggetti seguenti:
py-rag-tutorial-ds (origine dati)
py-rag-tutorial-ss (set di competenze)
Scaricare l'esempio
Scaricare un Jupyter Notebook da GitHub per inviare le richieste ad Azure AI Search. Per altre informazioni, vedere Download di file da GitHub.
Aggiornare l'indice per ridurre lo spazio di archiviazione
Ricerca di intelligenza artificiale di Azure prevede più approcci per ridurre le dimensioni del vettore, riducendo così il costo dei carichi di lavoro vettoriali. In questo passaggio creare un nuovo indice che usa le funzionalità seguenti:
Indici vettoriali più piccoli comprimendo i vettori usati durante l'esecuzione della query. La quantizzazione scalare offre questa funzionalità.
Indici vettoriali più piccoli rifiutando esplicitamente l'archiviazione vettoriale per i risultati della ricerca. Se sono necessari solo vettori per le query e non nel payload della risposta, è possibile eliminare la copia vettoriale usata per i risultati della ricerca.
Campi vettoriali più piccoli tramite tipi di dati stretti. È possibile specificare
Collection(Edm.Half)
nel campo text_vector per archiviare le dimensioni float32 in ingresso come float16.
Tutte queste funzionalità vengono specificate in un indice di ricerca. Dopo aver caricato l'indice, confrontare la differenza tra l'indice originale e quello nuovo.
Assegnare al nuovo indice
py-rag-tutorial-small-vectors-idx
il nome .Usare la definizione seguente per il nuovo indice. La differenza tra questo schema e gli aggiornamenti dello schema precedenti in Ottimizzare la pertinenza sono nuove classi per la quantizzazione scalare e una nuova sezione compressioni, un nuovo tipo di dati (
Collection(Edm.Half)
) per il campo text_vector e una nuova proprietàstored
impostata su false.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")
Creare o riutilizzare l'origine dati
Ecco la definizione dell'origine dati dell'esercitazione precedente. Se si dispone già di questa origine dati nel servizio di ricerca, è possibile ignorare la creazione di una nuova origine dati.
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")
Creare o riutilizzare il set di competenze
Anche il set di competenze è invariato rispetto all'esercitazione precedente. Qui è di nuovo in modo che sia possibile esaminarlo.
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")
Creare un nuovo indicizzatore e caricare l'indice
Anche se è possibile reimpostare ed eseguire di nuovo l'indicizzatore esistente usando il nuovo indice, è altrettanto semplice creare un nuovo indicizzatore. La presenza di due indici e indicizzatori mantiene la cronologia di esecuzione e consente confronti più stretti.
Questo indicizzatore è identico all'indicizzatore precedente, ad eccezione del fatto che specifica il nuovo indice di questa esercitazione.
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.')
Come passaggio finale, passare alla portale di Azure per confrontare i requisiti di archiviazione vettoriale per i due indici. I risultati dovrebbero essere simili allo screenshot seguente.
L'indice creato in questa esercitazione usa numeri a virgola mobile a metà precisione (float16) per i vettori di testo. Ciò riduce i requisiti di archiviazione per i vettori per metà rispetto all'indice precedente che usa numeri a virgola mobile a precisione singola (float32). La compressione scalare e l'omissione di un set di vettori rappresentano i risparmi di archiviazione rimanenti. Per altre informazioni sulla riduzione delle dimensioni del vettore, vedere Scegliere un approccio per ottimizzare l'archiviazione e l'elaborazione dei vettori.
È consigliabile rivedere le query dell'esercitazione precedente in modo da poter confrontare la velocità e l'utilità delle query. È consigliabile prevedere alcune variazioni nell'output LLM ogni volta che si ripete una query, ma in generale le tecniche di salvataggio dello spazio di archiviazione implementate non dovrebbero compromettere la qualità dei risultati della ricerca.
Passaggio successivo
Sono disponibili esempi di codice in tutti gli SDK di Azure che forniscono programmabilità di Ricerca intelligenza artificiale di Azure. È anche possibile esaminare il codice di esempio vettoriale per casi d'uso specifici e combinazioni tecnologiche.