Tutorial: Minimización del almacenamiento y los costos (RAG en Búsqueda de Azure AI)
Búsqueda de Azure AI ofrece varios enfoques para reducir el tamaño de los índices vectoriales. Estos enfoques van desde la compresión vectorial hasta ser más selectivos sobre lo que se almacena en el servicio de búsqueda.
En este tutorial, modificará el índice de búsqueda existente para usar lo siguiente:
- Tipos de datos estrechos
- Cuantificación escalar
- Almacenamiento reducido mediante la exclusión de vectores en los resultados de la búsqueda
En este tutorial se actualiza el índice de búsqueda creado por la canalización de indexación. Todas estas actualizaciones afectan al contenido existente, para lo que tiene que volver a ejecutar el indexador. Pero, en lugar de eliminar el índice de búsqueda, se crea un segundo para poder comparar las reducciones en el tamaño del índice vectorial después de agregar las nuevas funcionalidades.
En conjunto, las técnicas que se muestran en este tutorial pueden reducir el almacenamiento de vectores aproximadamente a la mitad.
En el recorte de pantalla siguiente se compara el primer índice de un tutorial anterior con el índice creado en este.
Requisitos previos
Este tutorial es básicamente una nueva ejecución de la canalización de indexación. Necesita todos los recursos y permisos de Azure descritos en ese tutorial.
Para la comparación, debe tener un índice py-rag-tutorial-idx existente en el servicio Búsqueda de Azure AI. Debe tener casi 2 MB de tamaño y la parte del índice vectorial debe ser de 348 KB.
También debe tener los siguientes objetos:
py-rag-tutorial-ds (origen de datos)
py-rag-tutorial-ss (conjunto de aptitudes)
Descarga del ejemplo
Descargue un Jupyter Notebook de GitHub para enviar las solicitudes a Búsqueda de Azure AI. Para obtener más información, consulte Descarga de archivos de GitHub.
Actualización del índice para reducir el almacenamiento
Búsqueda de Azure AI tiene varios enfoques para reducir el tamaño del vector, lo que disminuye el costo de las cargas de trabajo de vectores. En este paso, cree un índice que use las siguientes funcionalidades:
Índices vectoriales más pequeños mediante la compresión de los vectores usados durante la ejecución de la consulta. La cuantificación escalar proporciona esta funcionalidad.
Índices vectoriales más pequeños al no participar en el almacenamiento de vectores para los resultados de la búsqueda. Si solo necesita vectores para las consultas y no en la carga de respuesta, puede quitar la copia vectorial usada para los resultados de la búsqueda.
Campos vectoriales más pequeños por medio de tipos de datos estrechos. Puede especificar
Collection(Edm.Half)
en el campo text_vector para almacenar las dimensiones float32 entrantes como float16.
Todas estas funcionalidades se especifican en un índice de búsqueda. Después de cargar el índice, compare la diferencia entre el índice original y el nuevo.
Asigne el nombre
py-rag-tutorial-small-vectors-idx
al nuevo índice.Use la siguiente definición para el nuevo índice. La diferencia entre este esquema y las actualizaciones de esquema anteriores en Maximizar la relevancia son nuevas clases para la cuantificación escalar y una nueva sección de compresión, un nuevo tipo de datos (
Collection(Edm.Half)
) para el campo text_vector y una nueva propiedadstored
establecida en 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")
Creación o reutilización del origen de datos
Esta es la definición del origen de datos del tutorial anterior. Si ya tiene este origen de datos en el servicio de búsqueda, puede omitir la creación de uno.
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")
Creación o reutilización del conjunto de aptitudes
El conjunto de aptitudes tampoco cambia con respecto al tutorial anterior. Aquí está de nuevo para que pueda revisarlo.
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")
Creación de un indexador y carga del índice
Aunque podría restablecer y volver a ejecutar el indexador existente mediante el nuevo índice, es igual de fácil crear uno. Tener dos índices e indexadores conserva el historial de ejecución y permite comparaciones más precisas.
Este indexador es idéntico al anterior, salvo que especifica el nuevo índice de este tutorial.
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.')
Como último paso, cambie a Azure Portal para comparar los requisitos de almacenamiento vectorial de los dos índices. Debería ver resultados similares a los del recorte de pantalla siguiente.
El índice creado en este tutorial usa números de punto flotante de precisión media (float16) para los vectores de texto. Esto reduce los requisitos de almacenamiento de los vectores a la mitad en comparación con el índice anterior que usaba números de punto flotante de precisión sencilla (float32). La compresión escalar y la omisión de un conjunto de vectores suponen el ahorro de almacenamiento restante. Para más información sobre cómo reducir el tamaño del vector, vea Elección de un enfoque para optimizar el almacenamiento de vectores y el procesamiento.
Considere la posibilidad de volver a revisar las consultas del tutorial anterior para poder comparar la velocidad y la utilidad de las consultas. Debe esperar alguna variación en la salida de LLM cada vez que repita una consulta, pero en general las técnicas de ahorro de almacenamiento que ha implementado no deben degradar la calidad de los resultados de la búsqueda.
Paso siguiente
Hay ejemplos de código en todos los SDK de Azure que proporcionan la programación de Búsqueda de Azure AI. También puede revisar el código de ejemplo de vectores para casos de uso específicos y combinaciones de tecnología.