Samouczek: tworzenie potoku indeksowania dla rozwiązania RAG w usłudze Azure AI Search
Dowiedz się, jak utworzyć zautomatyzowany potok indeksowania dla rozwiązania RAG w usłudze Azure AI Search. Automatyzacja indeksowania odbywa się za pomocą indeksatora, który napędza indeksowanie i wykonywanie zestawu umiejętności, zapewniając zintegrowane fragmentowanie i wektoryzacja danych jednorazowo lub cyklicznie na potrzeby aktualizacji przyrostowych.
W tym samouczku zostały wykonane następujące czynności:
- Podaj schemat indeksu z poprzedniego samouczka
- Tworzenie połączenia ze źródłem danych
- Tworzenie indeksatora
- Tworzenie zestawu umiejętności, który fragmentuje, wektoryzuje i rozpoznaje jednostki
- Uruchamianie indeksatora i sprawdzanie wyników
Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.
Napiwek
Aby utworzyć potok, możesz użyć kreatora Importowanie i wektoryzowanie danych. Wypróbuj kilka przewodników Szybki start: wyszukiwanie obrazów i wyszukiwanie wektorów.
Wymagania wstępne
Program Visual Studio Code z rozszerzeniem języka Python i pakietem Jupyter. Aby uzyskać więcej informacji, zobacz Python in Visual Studio Code (Język Python w programie Visual Studio Code).
Konto ogólnego przeznaczenia usługi Azure Storage . W tym ćwiczeniu pliki PDF są przekazywane do magazynu obiektów blob na potrzeby automatycznego indeksowania.
Usługa Azure AI Search, warstwa Podstawowa lub nowsza dla tożsamości zarządzanej i klasyfikacji semantycznej. Wybierz region udostępniony usługom Azure OpenAI i Azure AI Services.
Usługa Azure OpenAI z wdrożeniem funkcji osadzania tekstu —3—duży w tym samym regionie co usługa Azure AI Search. Aby uzyskać więcej informacji na temat osadzania modeli używanych w rozwiązaniach RAG, zobacz Wybieranie modeli osadzania dla rozwiązania RAG w usłudze Azure AI Search.
Konto wielousług usługi Azure AI Service w tym samym regionie co usługa Azure AI Search. Ten zasób jest używany do umiejętności rozpoznawania jednostek, która wykrywa lokalizacje w zawartości.
Pobierz przykład
Pobierz notes Jupyter z usługi GitHub, aby wysłać żądania do usługi Azure AI Search. Aby uzyskać więcej informacji, zobacz Pobieranie plików z usługi GitHub.
Podaj schemat indeksu
Otwórz lub utwórz notes Jupyter (.ipynb
) w programie Visual Studio Code, aby zawierał skrypty składające się na potok. Początkowe kroki instalują pakiety i zbierają zmienne dla połączeń. Po wykonaniu kroków konfiguracji możesz rozpocząć od składników potoku indeksowania.
Zacznijmy od schematu indeksu z poprzedniego samouczka. Jest on zorganizowany wokół wektoryzowanych i niewektorowych fragmentów. Zawiera on pole, które przechowuje zawartość wygenerowaną przez sztuczną locations
inteligencję utworzoną przez zestaw umiejętności.
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,
SearchIndex
)
credential = DefaultAzureCredential()
# Create a search index
index_name = "py-rag-tutorial-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=SearchFieldDataType.Collection(SearchFieldDataType.Single), vector_search_dimensions=1024, vector_search_profile_name="myHnswProfile")
]
# Configure the vector search configuration
vector_search = VectorSearch(
algorithms=[
HnswAlgorithmConfiguration(name="myHnsw"),
],
profiles=[
VectorSearchProfile(
name="myHnswProfile",
algorithm_configuration_name="myHnsw",
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"
),
),
],
)
# Create the search index
index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search)
result = index_client.create_or_update_index(index)
print(f"{result.name} created")
Tworzenie połączenia ze źródłem danych
W tym kroku skonfiguruj przykładowe dane i połączenie z usługą Azure Blob Storage. Indeksator pobiera pliki PDF z kontenera. W tym kroku utworzysz kontener i przekażesz pliki.
Oryginalny podręcznik jest duży, ponad 100 stron i 35 MB rozmiaru. Podzieliliśmy go na mniejsze pliki PDF, po jednym na stronę tekstu, aby zachować limit dokumentów dla indeksatorów 16 MB na wywołanie interfejsu API, a także limity danych wzbogacania sztucznej inteligencji. Dla uproszczenia pomijamy wektoryzacja obrazów w tym ćwiczeniu.
Zaloguj się do witryny Azure Portal i znajdź swoje konto usługi Azure Storage.
Utwórz kontener i przekaż pliki PDF z earth_book_2019_text_pages.
Upewnij się, że usługa Azure AI Search ma uprawnienia Czytelnik danych obiektu blob usługi Storage w zasobie.
Następnie w programie Visual Studio Code zdefiniuj źródło danych indeksatora, które udostępnia informacje o połączeniu podczas indeksowania.
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")
Jeśli skonfigurujesz tożsamość zarządzaną dla usługi Azure AI Search dla połączenia, parametry połączenia zawiera sufiksResourceId=
. Powinien on wyglądać podobnie do poniższego przykładu: "ResourceId=/subscriptions/FAKE-SUBCRIPTION=ID/resourceGroups/FAKE-RESOURCE-GROUP/providers/Microsoft.Storage/storageAccounts/FAKE-ACCOUNT;"
Tworzenie zestawu umiejętności
Umiejętności są podstawą zintegrowanego fragmentowania i wektoryzacji danych. Co najmniej chcesz, aby umiejętność dzielenia tekstu dzieliła zawartość oraz umiejętności osadzania, które tworzą wektorowe reprezentacje fragmentowanej zawartości.
W tym zestawie umiejętności jest używana dodatkowa umiejętność tworzenia danych ustrukturyzowanych w indeksie. Umiejętność rozpoznawania jednostek służy do identyfikowania lokalizacji, które mogą zawierać nazwy od odpowiednich nazw do ogólnych odwołań, takich jak "ocean" lub "góra". Posiadanie danych ustrukturyzowanych zapewnia więcej opcji tworzenia interesujących zapytań i zwiększania istotności.
AZURE_AI_MULTISERVICE_KEY jest potrzebny, nawet jeśli używasz kontroli dostępu opartej na rolach. Usługa Azure AI Search używa klucza do celów rozliczeniowych i jest wymagana, chyba że obciążenia pozostaną w ramach bezpłatnego limitu. Możesz również nawiązać połączenie bez klucza, jeśli używasz najnowszego interfejsu API w wersji zapoznawczej lub pakietów beta. Aby uzyskać więcej informacji, zobacz Attach an Azure AI multi-service resource to a skillset (Dołączanie zasobu wielosłużytowego usługi Azure AI do zestawu umiejętności).
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=1024,
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")
Tworzenie i uruchamianie indeksatora
Indeksatory są składnikiem, który ustawia wszystkie procesy w ruchu. Indeksator można utworzyć w stanie wyłączonym, ale ustawieniem domyślnym jest natychmiastowe uruchomienie go. W tym samouczku utwórz i uruchom indeksator, aby pobrać dane z usługi Blob Storage, wykonać umiejętności, w tym fragmentację i wektoryzację oraz załadować indeks.
Uruchomienie indeksatora trwa kilka minut. Gdy wszystko będzie gotowe, możesz przejść do ostatniego kroku: wykonywanie zapytań względem indeksu.
from azure.search.documents.indexes.models import (
SearchIndexer,
FieldMapping
)
# Create an indexer
indexer_name = "py-rag-tutorial-idxr"
indexer_parameters = None
indexer = SearchIndexer(
name=indexer_name,
description="Indexer to index documents and generate embeddings",
skillset_name=skillset_name,
target_index_name=index_name,
data_source_name=data_source.name,
# Map the metadata_storage_name field to the title field in the index to display the PDF title in the search results
field_mappings=[FieldMapping(source_field_name="metadata_storage_name", target_field_name="title")],
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.')
Uruchamianie zapytania w celu sprawdzenia wyników
Wyślij zapytanie, aby potwierdzić, że indeks działa. To żądanie konwertuje ciąg tekstowy "what's NASA's website?
" na wektor wyszukiwania wektorowego. Wyniki składają się z pól w instrukcji select, z których niektóre są drukowane jako dane wyjściowe.
W tym momencie nie ma czatu ani generowania sztucznej inteligencji. Wyniki są dosłowną zawartością z indeksu wyszukiwania.
from azure.search.documents import SearchClient
from azure.search.documents.models import VectorizableTextQuery
# Vector Search using text-to-vector conversion of the querystring
query = "what's NASA's website?"
search_client = SearchClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential, index_name=index_name)
vector_query = VectorizableTextQuery(text=query, k_nearest_neighbors=50, fields="text_vector")
results = search_client.search(
search_text=query,
vector_queries= [vector_query],
select=["chunk"],
top=1
)
for result in results:
print(f"Score: {result['@search.score']}")
print(f"Chunk: {result['chunk']}")
To zapytanie zwraca pojedyncze dopasowanie (top=1
) składające się z jednego fragmentu określonego przez wyszukiwarkę jako najbardziej istotne. Wyniki zapytania powinny wyglądać podobnie do poniższego przykładu:
Score: 0.01666666753590107
Chunk: national Aeronautics and Space Administration
earth Science
NASA Headquarters
300 E Street SW
Washington, DC 20546
www.nasa.gov
np-2018-05-2546-hQ
Spróbuj wykonać jeszcze kilka zapytań, aby uzyskać informacje o tym, co zwraca aparat wyszukiwania bezpośrednio, aby można było porównać je z odpowiedzią z włączoną funkcją LLM. Uruchom ponownie poprzedni skrypt za pomocą tego zapytania: "patagonia geography"
i ustaw wartość top
3, aby zwrócić więcej niż jedną odpowiedź.
Wyniki z tego drugiego zapytania powinny wyglądać podobnie do poniższych wyników, które są lekko edytowane pod kątem wstrząsu. Dane wyjściowe są kopiowane z notesu, co powoduje obcięcie odpowiedzi na to, co zobaczysz w tym przykładzie. Możesz rozwinąć dane wyjściowe komórki, aby przejrzeć pełną odpowiedź.
Score: 0.03306011110544205
Chunk:
Swirling Bloom off Patagonia
Argentina
Interesting art often springs out of the convergence of different ideas and influences.
And so it is with nature.
Off the coast of Argentina, two strong ocean currents converge and often stir up a colorful
brew, as shown in this Aqua image from
December 2010.
This milky green and blue bloom formed on the continental shelf off of Patagonia, where warmer,
saltier waters from the subtropics
meet colder, fresher waters flowing from the south. Where these currents collide, turbulent
eddies and swirls form, pulling nutrients
up from the deep ocean. The nearby Rio de la Plata also deposits nitrogen- and iron-laden
sediment into the sea. Add in some
...
while others terminate in water. The San Rafael and San Quintín glaciers (shown at the right)
are the icefield’s largest. Both have
been receding rapidly in the past 30 years.
W tym przykładzie łatwiej jest dostrzec, jak fragmenty są zwracane dosłownie oraz jak słowo kluczowe i wyszukiwanie podobieństwa identyfikują najlepsze dopasowania. Ten konkretny fragment zdecydowanie zawiera informacje o Patagonii i geografii, ale nie jest to dokładnie istotne dla zapytania. Semantyczny ranga będzie promować bardziej istotne fragmenty, aby uzyskać lepszą odpowiedź, ale w następnym kroku zobaczmy, jak połączyć usługę Azure AI Search z modułem LLM na potrzeby wyszukiwania konwersacyjnego.