Skip to content

Commit eaa4e42

Browse files
authored
Merge pull request #124 from HeidiSteen/main
Revised script for RAG tutorial
2 parents f2643e6 + 0b5f4ad commit eaa4e42

File tree

1 file changed

+183
-56
lines changed

1 file changed

+183
-56
lines changed

Tutorial-RAG/Tutorial-rag.ipynb

Lines changed: 183 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66
"source": [
77
"# Build a RAG solution in Azure AI Search\n",
88
"\n",
9-
"This notebook builds an indexing pipeline in Azure AI Search for RAG scenarios. \n",
9+
"This notebook provides sample script for the indexing pipeline in [Build a RAG solution in Azure AI Search](https://learn.microsoft.com/azure/search/tutorial-rag-build-solution). If you need more information than the readme provides, you can refer to that article.\n",
1010
"\n",
11-
"The scripts rely on API keys for most of the connections, with the exception of Microsoft Entra ID authentication and role authorization for Azure AI Search connections to Azure Blob Storage. For the data connection to blob storage:\n",
11+
"Steps in this notebook include:\n",
1212
"\n",
13-
"+ Azure AI Search must have a system-assigned managed identity.\n",
14-
"+ The system identity must have Storage Blob Data Reader rights on Azure Storage.\n",
13+
"- Set up the environment\n",
14+
"- Set up the Azure resources used in the pipeline\n",
15+
"- Create an index, data source, skillset, and indexer on Azure AI Search\n",
16+
"- Send a query to the search engine to check results\n",
17+
"- Send a query to an LLM to chat with your data\n",
18+
"- Revisit the index schema and query logic to improve relevance\n",
1519
"\n",
16-
"In a future update, this notebook will use Microsoft Entra ID and role assignments for all connections.\n",
20+
"Sample data is a collection of PDF pages from the NASA's Earth Book that you load into Azure Storage and retrieve during indexing.\n",
1721
"\n",
18-
"The scripts and steps in this notebook are fully documented in [Tutorial: Build a RAG solution in Azure AI Search](https://learn.microsoft.com/azure/search/tutorial-rag-build-solution). If you need more guidance than the readme provides, please refer to the article."
22+
"This tutorial assumes embedding and chat models on Azure OpenAI so that you can use the integrated vectorization capabilities of Azure AI Search. You can use a different provider but you might need custom skills or a different approach for indexing and embedding your content."
1923
]
2024
},
2125
{
@@ -24,59 +28,129 @@
2428
"source": [
2529
"## Prerequisites\n",
2630
"\n",
27-
"- [Azure Storage](https://learn.microsoft.com/azure/storage/common/storage-account-create), with a blob container named \"nasa-ebook-pdfs-all\", containing PDFs that originate from the NASA Earth Book. Upload the [PDFs from this folder](https://github.com/Azure-Samples/azure-search-sample-data/tree/main/nasa-e-book/earth_book_2019_text_pages) into a container on Azure Storage.\n",
31+
"You need the following Azure resources to run all of the script in this notebook.\n",
2832
"\n",
29-
"- [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/how-to/create-resource)\n",
33+
"- [Azure Storage](https://learn.microsoft.com/azure/storage/common/storage-account-create), general purpose account, used for providing the PDFs.\n",
3034
"\n",
31-
" - Deploy a chat model (GPT-3.5-Turbo, GPT-4, or equivalent LLM).\n",
32-
" - Deploy an embedding model (text-embedding-ada-002, text-embedding-3-large, text-embedding-3-small)\n",
35+
"- [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/how-to/create-resource) provides the embedding and chat models.\n",
3336
"\n",
34-
"- [Azure AI Services multiservice account](https://learn.microsoft.com/azure/ai-services/multi-service-resource), in the same region as Azure AI Search. This resource is used for the Entity Recognition skill that detects locations in your content.\n",
37+
"- [Azure AI Services multiservice account](https://learn.microsoft.com/azure/ai-services/multi-service-resource), in the same region as Azure AI Search, used for recognizing location entities in the Earth Book.\n",
3538
"\n",
36-
"- [Azure AI Search](https://learn.microsoft.com/azure/search/search-create-service-portal)\n",
37-
"\n",
38-
" - Basic tier or higher is recommended.\n",
39-
" - Choose the same region as Azure OpenAI.\n",
40-
" - Enable semantic ranking.\n",
41-
" - Enable role-based access control.\n",
42-
" - Enable a system identity for Azure AI Search.\n",
43-
" \n",
44-
"Make sure you know the name of the deployed models, and have the endpoints for all Azure resources at hand. You will provide this information in the steps that follow."
39+
"- [Azure AI Search](https://learn.microsoft.com/azure/search/search-create-service-portal), basic tier or higher is recommended. Choose the same region as Azure OpenAI and Azure AI multiservice.\n"
4540
]
4641
},
4742
{
48-
"cell_type": "code",
49-
"execution_count": 77,
43+
"cell_type": "markdown",
5044
"metadata": {},
51-
"outputs": [],
5245
"source": [
53-
"! pip install -r tutorial-rag-requirements.txt --quiet"
46+
"## Sign in to Azure\n",
47+
"\n",
48+
"You might not need this step, but if downstream connections fail with a 401 during indexer pipeline execution, it could be because you're using the wrong tenant or subscription. You can avoid this issue by signing in from the command line, explicitly setting the tenant ID and choosing the right subscription.\n",
49+
"\n",
50+
"This section assumes you have the [Azure CLI](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).\n",
51+
"\n",
52+
"1. Open a command line prompt.\n",
53+
"\n",
54+
"1. Run this command to get a list of Azure tenants: `az account tenant list`\n",
55+
"\n",
56+
"1. If you have multiple tenants, set the tenant: `az login --tenant <YOUR-TENANT_ID> `\n",
57+
"\n",
58+
"If you have multiple subscriptions, a list is provided so that you can select one."
5459
]
5560
},
5661
{
57-
"cell_type": "code",
58-
"execution_count": 96,
62+
"cell_type": "markdown",
5963
"metadata": {},
60-
"outputs": [],
6164
"source": [
62-
"# Set endpoints and API keys for Azure services\n",
63-
"AZURE_SEARCH_SERVICE: str = \"PUT YOUR SEARCH SERVICE URL HERE\"\n",
64-
"AZURE_SEARCH_KEY: str = \"PUT YOUR SEARCH SERVICE ADMIN KEY HERE\"\n",
65-
"AZURE_OPENAI_ACCOUNT: str = \"PUT YOUR AZURE OPENAI ACCOUNT URL HERE\"\n",
66-
"AZURE_OPENAI_KEY: str = \"PUT YOUR AZURE OPENAI KEY HERE\"\n",
67-
"AZURE_AI_MULTISERVICE_ACCOUNT: str = \"PUT YOUR AZURE AI MULTISERVICE ACCOUNT URL HERE\"\n",
68-
"AZURE_AI_MULTISERVICE_KEY: str = \"PUT YOUR AZURE AI MULTISERVICE KEY HERE\"\n",
69-
"AZURE_STORAGE_CONNECTION: str = \"PUT YOUR AZURE STORAGE CONNECTION STRING HERE\"\n",
65+
"## Set up Azure resources using the Azure portal\n",
7066
"\n",
71-
"# Example connection string for a search service managed identity connection:\n",
72-
"# \"ResourceId=/subscriptions/FAKE-SUBCRIPTION=ID/resourceGroups/FAKE-RESOURCE-GROUP/providers/Microsoft.Storage/storageAccounts/FAKE-ACCOUNT;\""
67+
"We recommend using the Azure portal for setting up resources.\n",
68+
"\n",
69+
"You must be a subscription **Owner** or **User Access Administrator** to create roles. If you don't have permission to create roles, you can use API keys instead. If you're using keys, you can skip the steps that enable system assigned managed identities.\n",
70+
"\n",
71+
"1. Download the sample PDF files from [nasa-e-book/earth_book_2019_text_pages](https://github.com/Azure-Samples/azure-search-sample-data/tree/main/nasa-e-book/earth_book_2019_text_pages).\n",
72+
"\n",
73+
"1. Sign in to the [Azure portal](https://portal.azure.com).\n",
74+
"\n",
75+
"1. Make sure Azure AI Search, Azure OpenAI, and Azure AI multiservice resources are in the same region.\n",
76+
"\n",
77+
"### Configure Azure Storage\n",
78+
"\n",
79+
"1. On the Azure Storage left menu, select **Storage browser** > **Blob containers**, and then **Add container**.\n",
80+
"\n",
81+
"1. Name the container *nasa-ebooks-pdfs-all*.\n",
82+
"\n",
83+
"1. Upload the PDFs to the container.\n",
84+
"\n",
85+
"1. On the left menu, select **Settings** > **Identity** and turn on system assigned managed identity.\n",
86+
"\n",
87+
"### Configure Azure AI Search\n",
88+
"\n",
89+
"1. On the Azure AI Search left menu, select **Settings** > **Semantic ranker** and enable the free plan that authorizes 1,000 requests at no charge.\n",
90+
"\n",
91+
"1. On the left menu, select **Settings** > **Keys** and turn on role-based access control or \"both\".\n",
92+
"\n",
93+
"1. On the left menu, select **Settings** > **Identity** and turn on system assigned managed identity.\n",
94+
"\n",
95+
"### Configure Azure OpenAI\n",
96+
"\n",
97+
"Deploy the following models on Azure OpenAI:\n",
98+
"\n",
99+
"- Text-embedding-ada-02 on Azure OpenAI for embeddings\n",
100+
"- GPT-35-Turbo on Azure OpenAI for chat completion\n",
101+
"\n",
102+
"You must have [**Cognitive Services OpenAI Contributor**]( /azure/ai-services/openai/how-to/role-based-access-control#cognitive-services-openai-contributor) or higher to deploy models in Azure OpenAI.\n",
103+
"\n",
104+
"1. Go to [Azure OpenAI Studio](https://oai.azure.com/).\n",
105+
"\n",
106+
"1. Select **Deployments** on the left menu.\n",
107+
"\n",
108+
"1. Select **Deploy model** > **Deploy base model**.\n",
109+
"\n",
110+
"1. Select **text-embedding-ada-02** from the dropdown list and confirm the selection.\n",
111+
"\n",
112+
"1. Specify a deployment name. We recommend \"text-embedding-ada-002\".\n",
113+
"\n",
114+
"1. Accept the defaults.\n",
115+
"\n",
116+
"1. Select **Deploy**.\n",
117+
"\n",
118+
"1. Repeat the previous steps for **gpt-35-turbo**.\n",
119+
"\n",
120+
"Make a note of the model names and endpoint. Embedding skills and vectorizers assemble the full endpoint internally, so you only need the resource URI. For example, given `https://MY-FAKE-ACCOUNT.openai.azure.com/openai/deployments/text-embedding-ada-002/embeddings?api-version=2023-05-15`, the endpoint you should provide in skill and vectorizer definitions is `https://MY-FAKE-ACCOUNT.openai.azure.com`.\n",
121+
"\n",
122+
"### Configure search engine role-based access to Azure Storage\n",
123+
"\n",
124+
"1. Sign in to the [Azure portal](https://portal.azure.com) and find your storage account.\n",
125+
"\n",
126+
"1. On the left menu, select **Access control (IAM)**.\n",
127+
"\n",
128+
"1. Add a role for **Storage Blob Data Reader**, assigned to the search service system-managed identity.\n",
129+
"\n",
130+
"### Configure search engine role-based access to Azure models\n",
131+
"\n",
132+
"Assign yourself *and* the search service identity permissions on Azure OpenAI. The code for this tutorial runs locally. Requests to Azure OpenAI originate from your system. Also, embedding requests and query reponses from the search engine are passed to Azure OpenAI. For these reasons, both you and the search service need permissions on Azure OpenAI.\n",
133+
"\n",
134+
"1. Sign in to the [Azure portal](https://portal.azure.com) and find your Azure OpenAI resource.\n",
135+
"\n",
136+
"1. On the left menu, select **Access control (IAM)**.\n",
137+
"\n",
138+
"1. Add a role for [**Cognitive Services OpenAI User**](/azure/ai-services/openai/how-to/role-based-access-control#cognitive-services-openai-userpermissions).\n",
139+
"\n",
140+
"1. Select **Managed identity** and then select **Members**. Find the system-managed identity for your search service in the dropdown list.\n",
141+
"\n",
142+
"1. Next, select **User, group, or service principal** and then select **Members**. Search for your user account and then select it from the dropdown list.\n",
143+
"\n",
144+
"1. Select **Review and Assign** to create the role assignments.\n",
145+
"\n",
146+
"This step concludes provisioning services in the Azure portal. Continuing to the next section, you switch to Visual Studio Code and a local environment."
73147
]
74148
},
75149
{
76150
"cell_type": "markdown",
77151
"metadata": {},
78152
"source": [
79-
"## Create a virtual environment\n",
153+
"## Create a virtual environment in Visual Studio Code\n",
80154
"\n",
81155
"Create a virtual environment so that you can install the dependencies in isolation.\n",
82156
"\n",
@@ -93,7 +167,25 @@
93167
"cell_type": "markdown",
94168
"metadata": {},
95169
"source": [
96-
"## Create an index"
170+
"## Install packages"
171+
]
172+
},
173+
{
174+
"cell_type": "code",
175+
"execution_count": null,
176+
"metadata": {},
177+
"outputs": [],
178+
"source": [
179+
"! pip install -r tutorial-rag-requirements.txt --quiet"
180+
]
181+
},
182+
{
183+
"cell_type": "markdown",
184+
"metadata": {},
185+
"source": [
186+
"## Set endpoints\n",
187+
"\n",
188+
"Provide the endpoints you collected in a previous step. You can leave the API keys empty if you enabled role-based authentication. Otherwise, if you can't use roles, provide API keys for each resource."
97189
]
98190
},
99191
{
@@ -102,7 +194,36 @@
102194
"metadata": {},
103195
"outputs": [],
104196
"source": [
105-
"from azure.core.credentials import AzureKeyCredential\n",
197+
"# Set endpoints and API keys for Azure services\n",
198+
"AZURE_SEARCH_SERVICE: str = \"PUT YOUR SEARCH SERVICE URL HERE\"\n",
199+
"AZURE_SEARCH_KEY: str = \"DELETE IF USING ROLES, OTHERWISE PUT YOUR SEARCH SERVICE ADMIN KEY HERE\"\n",
200+
"AZURE_OPENAI_ACCOUNT: str = \"PUT YOUR AZURE OPENAI ACCOUNT URL HERE\"\n",
201+
"AZURE_OPENAI_KEY: str = \"DELETE IF USING ROLES, OTHERWISE PUT YOUR AZURE OPENAI KEY HERE\"\n",
202+
"AZURE_AI_MULTISERVICE_ACCOUNT: str = \"PUT YOUR AZURE AI MULTISERVICE ACCOUNT URL HERE\"\n",
203+
"AZURE_AI_MULTISERVICE_KEY: str = \"PUT YOUR AZURE AI MULTISERVICE KEY HERE. ROLES ARE USED TO CONNECT. KEY IS USED FOR BILLING.\"\n",
204+
"AZURE_STORAGE_CONNECTION: str = \"PUT YOUR AZURE STORAGE CONNECTION STRING HERE (see example below for syntax)\"\n",
205+
"\n",
206+
"# Example connection string for a search service managed identity connection:\n",
207+
"# \"ResourceId=/subscriptions/FAKE-SUBCRIPTION=ID/resourceGroups/FAKE-RESOURCE-GROUP/providers/Microsoft.Storage/storageAccounts/FAKE-ACCOUNT;\""
208+
]
209+
},
210+
{
211+
"cell_type": "markdown",
212+
"metadata": {},
213+
"source": [
214+
"## Create an index\n",
215+
"\n",
216+
"This is index schema used for [Build a RAG solution in Azure AI Search](https://learn.microsoft.com/azure/search/tutorial-rag-build-solution)."
217+
]
218+
},
219+
{
220+
"cell_type": "code",
221+
"execution_count": null,
222+
"metadata": {},
223+
"outputs": [],
224+
"source": [
225+
"from azure.identity import DefaultAzureCredential\n",
226+
"from azure.identity import get_bearer_token_provider\n",
106227
"from azure.search.documents.indexes import SearchIndexClient\n",
107228
"from azure.search.documents.indexes.models import (\n",
108229
" SearchField,\n",
@@ -115,11 +236,11 @@
115236
" SearchIndex\n",
116237
")\n",
117238
"\n",
118-
"AZURE_SEARCH_CREDENTIAL = AzureKeyCredential(AZURE_SEARCH_KEY)\n",
239+
"credential = DefaultAzureCredential()\n",
119240
"\n",
120241
"# Create a search index \n",
121242
"index_name = \"py-rag-tutorial-idx\"\n",
122-
"index_client = SearchIndexClient(endpoint=AZURE_SEARCH_SERVICE, credential=AZURE_SEARCH_CREDENTIAL) \n",
243+
"index_client = SearchIndexClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential) \n",
123244
"fields = [\n",
124245
" SearchField(name=\"parent_id\", type=SearchFieldDataType.String), \n",
125246
" SearchField(name=\"title\", type=SearchFieldDataType.String),\n",
@@ -148,8 +269,7 @@
148269
" parameters=AzureOpenAIVectorizerParameters( \n",
149270
" resource_url=AZURE_OPENAI_ACCOUNT, \n",
150271
" deployment_name=\"text-embedding-ada-002\",\n",
151-
" model_name=\"text-embedding-ada-002\",\n",
152-
" api_key=AZURE_OPENAI_KEY\n",
272+
" model_name=\"text-embedding-ada-002\"\n",
153273
" ),\n",
154274
" ), \n",
155275
" ], \n",
@@ -183,7 +303,7 @@
183303
")\n",
184304
"\n",
185305
"# Create a data source \n",
186-
"indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=AZURE_SEARCH_CREDENTIAL)\n",
306+
"indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential)\n",
187307
"container = SearchIndexerDataContainer(name=\"nasa-ebooks-pdfs-all\")\n",
188308
"data_source_connection = SearchIndexerDataSourceConnection(\n",
189309
" name=\"py-rag-tutorial-ds\",\n",
@@ -200,7 +320,9 @@
200320
"cell_type": "markdown",
201321
"metadata": {},
202322
"source": [
203-
"## Create a skillset"
323+
"## Create a skillset\n",
324+
"\n",
325+
"This skillset chunks and embeds data. It also uses entity recognition to detect location entities."
204326
]
205327
},
206328
{
@@ -299,7 +421,7 @@
299421
" cognitive_services_account=cognitive_services_account\n",
300422
")\n",
301423
" \n",
302-
"client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=AZURE_SEARCH_CREDENTIAL) \n",
424+
"client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential) \n",
303425
"client.create_or_update_skillset(skillset) \n",
304426
"print(f\"{skillset.name} created\") "
305427
]
@@ -308,7 +430,9 @@
308430
"cell_type": "markdown",
309431
"metadata": {},
310432
"source": [
311-
"## Create an indexer"
433+
"## Create an indexer\n",
434+
"\n",
435+
"The indexer drives the pipeline. You can create an indexer in a disabled state, but the default is for the indexer to run as soon as you send the request."
312436
]
313437
},
314438
{
@@ -339,7 +463,7 @@
339463
") \n",
340464
"\n",
341465
"# Create and run the indexer \n",
342-
"indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=AZURE_SEARCH_CREDENTIAL) \n",
466+
"indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential) \n",
343467
"indexer_result = indexer_client.create_or_update_indexer(indexer) \n",
344468
"\n",
345469
"print(f' {indexer_name} is created and running. Give the indexer a few minutes before running a query.') "
@@ -349,7 +473,9 @@
349473
"cell_type": "markdown",
350474
"metadata": {},
351475
"source": [
352-
"## Check results"
476+
"## Check results\n",
477+
"\n",
478+
"After waiting several minutes, send a request to the search engine. There is no chat or generative AI at this point. The results are verbatim content from your search index."
353479
]
354480
},
355481
{
@@ -364,7 +490,7 @@
364490
"# Vector Search using text-to-vector conversion of the querystring\n",
365491
"query = \"where are NASA's headquarters located?\" \n",
366492
"\n",
367-
"search_client = SearchClient(endpoint=AZURE_SEARCH_SERVICE, credential=AZURE_SEARCH_CREDENTIAL, index_name=index_name)\n",
493+
"search_client = SearchClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential, index_name=index_name)\n",
368494
"vector_query = VectorizableTextQuery(text=query, k_nearest_neighbors=1, fields=\"text_vector\", exhaustive=True)\n",
369495
" \n",
370496
"results = search_client.search( \n",
@@ -385,7 +511,9 @@
385511
"cell_type": "markdown",
386512
"metadata": {},
387513
"source": [
388-
"## Search using a chat model"
514+
"## Search using a chat model\n",
515+
"\n",
516+
"This script sends a query, the query response, and a prompt to an LLM for chat completion. This time, the response is created using generative AI."
389517
]
390518
},
391519
{
@@ -396,22 +524,21 @@
396524
"source": [
397525
"# Import libraries\n",
398526
"from azure.search.documents import SearchClient\n",
399-
"from azure.core.credentials import AzureKeyCredential\n",
400527
"from openai import AzureOpenAI\n",
401528
"\n",
402-
"# Set up clients and specify the chat model\n",
529+
"token_provider = get_bearer_token_provider(credential, \"https://cognitiveservices.azure.com/.default\")\n",
403530
"openai_client = AzureOpenAI(\n",
404531
" api_version=\"2024-06-01\",\n",
405532
" azure_endpoint=AZURE_OPENAI_ACCOUNT,\n",
406-
" api_key=AZURE_OPENAI_KEY\n",
533+
" azure_ad_token_provider=token_provider\n",
407534
" )\n",
408535
"\n",
409536
"deployment_name = \"gpt-35-turbo\"\n",
410537
"\n",
411538
"search_client = SearchClient(\n",
412539
" endpoint=AZURE_SEARCH_SERVICE,\n",
413540
" index_name=index_name,\n",
414-
" credential=AZURE_SEARCH_CREDENTIAL\n",
541+
" credential=credential\n",
415542
" )\n",
416543
"\n",
417544
"# Provide instructions to the model\n",

0 commit comments

Comments
 (0)