Kurz: Minimalizace úložiště a nákladů (RAG ve službě Azure AI Search)
Azure AI Search nabízí několik přístupů ke zmenšení velikosti vektorových indexů. Tyto přístupy se liší od komprese vektorů až po selektivní přes to, co ukládáte ve vyhledávací službě.
V tomto kurzu upravíte existující index vyhledávání tak, aby používal:
- Úzké datové typy
- Skalární kvantování
- Omezené úložiště odhlášením z vektorů ve výsledcích hledání
V tomto kurzu se znovu zobrazí index vyhledávání vytvořený kanálem indexování. Všechny tyto aktualizace mají vliv na existující obsah a vyžadují opětovné spuštění indexeru. Místo odstranění indexu vyhledávání ale vytvoříte druhý index, abyste mohli porovnat snížení velikosti vektorového indexu po přidání nových funkcí.
Techniky ilustrované v tomto kurzu mohou zcela snížit velikost úložiště vektorů přibližně o polovinu.
Následující snímek obrazovky porovnává první index z předchozího kurzu s indexem vytvořeným v tomto kurzu.
Požadavky
Tento kurz je v podstatě opětovným spuštěním kanálu indexování. Potřebujete všechny prostředky a oprávnění Azure popsané v tomto kurzu.
Pro porovnání byste měli mít ve svém Search Azure AI existující index py-rag-tutorial-idx. Měla by mít velikost téměř 2 MB a část vektorového indexu by měla být 348 kB.
Měli byste mít také následující objekty:
py-rag-tutorial-ds (zdroj dat)
py-rag-tutorial-ss (sada dovedností)
Stažení ukázky
Stáhněte si poznámkový blok Jupyter z GitHubu a odešlete žádosti do služby Azure AI Search. Další informace najdete v tématu Stahování souborů z GitHubu.
Aktualizace indexu pro omezené úložiště
Azure AI Search nabízí několik přístupů ke snížení velikosti vektorů, což snižuje náklady na úlohy vektorů. V tomto kroku vytvořte nový index, který používá následující funkce:
Menší vektorové indexy komprimací vektorů použitých během provádění dotazu. Skalární kvantování poskytuje tuto funkci.
Menší vektorové indexy tím, že se odhlásíte z úložiště vektorů pro výsledky hledání. Pokud potřebujete jenom vektory pro dotazy a ne v datové části odpovědi, můžete vypustit kopii vektoru použitou pro výsledky hledání.
Menší vektorová pole prostřednictvím úzkých datových typů U pole text_vector můžete zadat
Collection(Edm.Half)
, aby se příchozí dimenze float32 ukládaly jako float16.
Všechny tyto funkce jsou zadané v indexu vyhledávání. Po načtení indexu porovnejte rozdíl mezi původním indexem a novým indexem.
Pojmenujte nový index
py-rag-tutorial-small-vectors-idx
.Pro nový index použijte následující definici. Rozdíl mezi tímto schématem a předchozími aktualizacemi schématu v maximalizaci relevance jsou nové třídy pro skalární kvantování a nový oddíl komprese, nový datový typ (
Collection(Edm.Half)
) pro pole text_vector a nová vlastnoststored
nastavená na 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")
Vytvoření nebo opětovné použití zdroje dat
Tady je definice zdroje dat z předchozího kurzu. Pokud už tento zdroj dat ve vyhledávací službě máte, můžete přeskočit vytvoření nového zdroje dat.
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")
Vytvoření nebo opětovné použití sady dovedností
Sada dovedností se také nezměnila z předchozího kurzu. Tady je to znovu, abyste si ho mohli prohlédnout.
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")
Vytvoření nového indexeru a načtení indexu
I když byste stávající indexer mohli resetovat a znovu spustit pomocí nového indexu, je stejně snadné vytvořit nový indexer. Když máte dva indexy a indexery, zachová se historie spouštění a umožní se blíže porovnávat.
Tento indexer je stejný jako předchozí indexer s tím rozdílem, že určuje nový index z tohoto kurzu.
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.')
V posledním kroku přepněte na web Azure Portal a porovnejte požadavky na vektorové úložiště pro oba indexy. Výsledky by se měly podobat následujícímu snímku obrazovky.
Index vytvořený v tomto kurzu používá čísla s plovoucí desetinnou čárkou s poloviční přesností (float16) pro textové vektory. Tím se sníží požadavky na úložiště vektorů o polovinu oproti předchozímu indexu, který používal čísla s plovoucí desetinnou čárkou s jednoduchou přesností (float32). Skalární komprese a vynechání jedné sady vektorů představují zbývající úspory úložiště. Další informace o zmenšení velikosti vektoru naleznete v tématu Volba přístupu pro optimalizaci úložiště a zpracování vektorů.
Zvažte odvolání dotazů z předchozího kurzu , abyste mohli porovnat rychlost a nástroj dotazů. Při každém opakování dotazu byste měli očekávat určité variace ve výstupu LLM, ale obecně byste měli implementovat techniky ukládání úložiště, které jste implementovali, nezhoršovat kvalitu výsledků hledání.
Další krok
Ve všech sadách Azure SDK existují ukázky kódu, které poskytují programovatelnost služby Azure AI Search. Můžete také zkontrolovat vzorový kód vektoru pro konkrétní případy použití a kombinace technologií.