Skip to content

Commit 33e02cf

Browse files
committed
Draft of RAG quickstart
1 parent 70cdd78 commit 33e02cf

File tree

2 files changed

+299
-3
lines changed

2 files changed

+299
-3
lines changed

articles/search/TOC.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@
1515
items:
1616
- name: Vector search
1717
href: search-get-started-vector.md
18+
- name: Generative search (RAG)
19+
href: search-get-started-rag.md
1820
- name: Full text search
1921
href: search-get-started-text.md
20-
- name: Semantic reranking
22+
- name: Semantic ranking
2123
href: search-get-started-semantic.md
22-
- name: Chat with your data (Azure OpenAI Studio)
23-
href: /azure/ai-services/openai/use-your-data-quickstart?context=/azure/search/context/context
24+
- name: Azure OpenAI Studio
25+
items:
26+
- name: Chat with your data
27+
href: /azure/ai-services/openai/use-your-data-quickstart?context=/azure/search/context/context
2428
- name: Portal
2529
items:
2630
- name: Keyword search wizard
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
---
2+
title: Quickstart RAG
3+
titleSuffix: Azure AI Search
4+
description: In this quickstart, learn how to use grounding data from Azure AI Search with a chat model on Azure OpenAI.
5+
author: HeidiSteen
6+
ms.author: heidist
7+
ms.service: cognitive-search
8+
ms.topic: quickstart
9+
ms.date: 07/22/2024
10+
---
11+
12+
# Quickstart: Generative search (RAG) with grounding data from Azure AI Search
13+
14+
This quickstart shows you how to send queries to a Large Language Model (LLM) for a conversational search experience over your indexed content on Azure AI Search. You use the Azure portal to set up the resources, and then run Python code to call the APIs.
15+
16+
## Prerequisites
17+
18+
- An Azure subscription. [Create one for free](https://azure.microsoft.com/free/).
19+
20+
- [Azure AI Search](search-create-service-portal.md), on any tier. Region must be the same one used for Azure OpenAI.
21+
22+
- [Azure OpenAI](https://aka.ms/oai/access) resource with a deployment of `gpt-35-turbo`, `gpt-4`, or equivalent model, in the same region as Azure AI Search.
23+
24+
- [Visual Studio Code](https://code.visualstudio.com/download) with the [Python extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python) and the [Jupyter package](https://pypi.org/project/jupyter/). For more information, see [Python in Visual Studio Code](https://code.visualstudio.com/docs/languages/python).
25+
26+
## Download file
27+
28+
[Download a Jupyter notebook](https://github.com/Azure-Samples/azure-search-python-samples/tree/main/Quickstart-RAG) from GitHub to send the requests in this quickstart. For more information, see [Downloading files from GitHub](https://docs.github.com/get-started/start-your-journey/downloading-files-from-github).
29+
30+
You can also start a new file on your local system and create requests manually by using the instructions in this article.
31+
32+
## Configure access
33+
34+
Requests to the search endpoint must be authenticated and authorized. You can use API keys or roles for this task. Keys are easier to start with, but roles are more secure. This quickstart assumes roles.
35+
36+
1. Configure Azure OpenAI to use a system-assigned managed identity.
37+
1. In the Azure portal, find your Azure OpenAI resource.
38+
1. On the left menu, select **Resource management** > **Identity**.
39+
1. On the System assigned tab, set status to **On**.
40+
41+
1. Grant Azure OpenAI permission to access Azure AI Search:
42+
1. In the Azure portal, find your Azure AI Search service.
43+
1. On the left menu, select **Access control (IAM)**.
44+
1. Add the following role assignments for Azure OpenAI managed identity: Search Index Data Reader
45+
You only need data reader for this quickstart because this scenario is limited to query operations.
46+
47+
## Create an index
48+
49+
We recommend the hotels-sample-index, which can be created in minutes and runs on any search service tier. This index is created using built-in sample data.
50+
51+
1. In the Azure portal, find your search service.
52+
53+
1. On the **Overview** home page, select **Import data** at the top to start the wizard.
54+
55+
1. On the **Connect to your data** page, select **Samples** from the dropdown list.
56+
57+
1. Choose the **hotels-sample**.
58+
59+
1. Select **Next** through the remaining pages, accepting the default values.
60+
61+
1. Once the index is created, select **Search management** > **Indexes** from the left menu to open the index.
62+
63+
1. Select **Edit JSON**.
64+
65+
1. Search for "semantic" to find the section in the index for a semantic configuration. Replace the "semantic" line with the following semantic configuration. This example specifies a `"defaultConfiguration"`, which is important to the running of this quickstart.
66+
67+
```json
68+
"semantic": {
69+
"defaultConfiguration": "semantic-config",
70+
"configurations": [
71+
{
72+
"name": "semantic-config",
73+
"prioritizedFields": {
74+
"titleField": {
75+
"fieldName": "HotelName"
76+
},
77+
"prioritizedContentFields": [
78+
{
79+
"fieldName": "Description"
80+
}
81+
],
82+
"prioritizedKeywordsFields": [
83+
{
84+
"fieldName": "Category"
85+
},
86+
{
87+
"fieldName": "Tags"
88+
}
89+
]
90+
}
91+
}
92+
]
93+
},
94+
```
95+
96+
1. **Save** your changes.
97+
98+
1. Run the following query to test your index: `hotels near the ocean with beach access and good views`.
99+
100+
Output should look similar to the following partial example, trimmed here for brevity. The presence of `@search.rerankerScore` and `@search.captions` tells you that the semantic ranker is working.
101+
102+
```json
103+
"@search.score": 5.600783,
104+
"@search.rerankerScore": 2.4191176891326904,
105+
"@search.captions": [
106+
{
107+
"text": "Ocean Air Motel. Budget. pool\r\nair conditioning\r\nbar. Oceanfront hotel overlooking the beach features rooms with a private balcony and 2 indoor and outdoor pools. Various shops and art entertainment are on the boardwalk, just steps away..",
108+
"highlights": "Ocean Air Motel. Budget.<em> pool\r\nair conditioning\r\nbar. O</em>ceanfront hotel overlooking the beach features rooms with a private balcony and 2 indoor and outdoor pools. Various shops and art entertainment are on the boardwalk, just steps away.."
109+
}
110+
],
111+
"HotelId": "41",
112+
"HotelName": "Ocean Air Motel",
113+
"Description": "Oceanfront hotel overlooking the beach features rooms with a private balcony and 2 indoor and outdoor pools. Various shops and art entertainment are on the boardwalk, just steps away.",
114+
```
115+
116+
## Get service endpoints
117+
118+
1. Sign in to the [Azure portal](https://portal.azure.com).
119+
120+
1. [Find your search service](https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.Search%2FsearchServices).
121+
122+
1. On the **Overview** home page, copy the URL. An example endpoint might look like `https://mydemo.search.windows.net`.
123+
124+
:::image type="content" source="media/search-get-started-rest/get-endpoint.png" lightbox="media/search-get-started-rest/get-endpoint.png" alt-text="Screenshot of the URL property on the overview page.":::
125+
126+
1. [Find your Azure OpenAI service](https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.CognitiveServices%2Faccounts).
127+
128+
1. On the **Overview** home page, select the link to view the endpoints. Copy the URL.
129+
130+
## Set up the query and chat thread
131+
132+
This section uses Visual Studio Code and Python to call the chat APIs on Azure OpenAI.
133+
134+
1. Install the following Python packages.
135+
136+
```python
137+
! pip install azure-search-documents==11.6.0b4 --quiet
138+
! pip install azure-identity==1.16.0 --quiet
139+
! pip install openai --quiet
140+
```
141+
142+
1. Set the following variables, substituting placeholders with valid values.
143+
144+
```python
145+
AZURE_SEARCH_SERVICE: str = "PUT YOUR SEARCH SERVICE ENDPOINT HERE"
146+
AZURE_OPENAI_ACCOUNT: str = "PUT YOUR AZURE OPENAI ENDPOINT HERE"
147+
AZURE_DEPLOYMENT_MODEL: str = "gpt-35-turbo"
148+
```
149+
150+
1. Specify query parameters. The query is a keyword search using semantic ranking. The search engine returns up to 50 matches, but the model returns just the top 5 in the response.
151+
152+
```python
153+
# Set query parameters for grounding the conversation on your search index
154+
k=50
155+
search_type="text"
156+
use_semantic_reranker=True
157+
sources_to_include=5
158+
```
159+
160+
1. Set up clients, functions, prompts, and chat thread. The function retrieves selected fields from the search index.
161+
162+
```python
163+
# Set up the query for generating responses
164+
from azure.core.credentials_async import AsyncTokenCredential
165+
from azure.identity.aio import get_bearer_token_provider
166+
from azure.search.documents.aio import SearchClient
167+
from azure.search.documents.models import VectorizableTextQuery, HybridSearch
168+
from openai import AsyncAzureOpenAI
169+
from enum import Enum
170+
from typing import List, Optional
171+
172+
def create_openai_client(credential: AsyncTokenCredential) -> AsyncAzureOpenAI:
173+
token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")
174+
return AsyncAzureOpenAI(
175+
api_version="2024-04-01-preview",
176+
azure_endpoint=AZURE_OPENAI_ACCOUNT,
177+
azure_ad_token_provider=token_provider
178+
)
179+
180+
def create_search_client(credential: AsyncTokenCredential) -> SearchClient:
181+
return SearchClient(
182+
endpoint=AZURE_SEARCH_SERVICE,
183+
index_name="hotels-sample-index",
184+
credential=credential
185+
)
186+
187+
# This quickstart is only using text at the moment
188+
class SearchType(Enum):
189+
TEXT = "text"
190+
VECTOR = "vector"
191+
HYBRID = "hybrid"
192+
193+
# This function retrieves the selected fields from the search index
194+
async def get_sources(search_client: SearchClient, query: str, search_type: SearchType, use_semantic_reranker: bool = True, sources_to_include: int = 5, k: int = 50) -> List[str]:
195+
search_type == SearchType.TEXT,
196+
response = await search_client.search(
197+
search_text=query,
198+
query_type="semantic" if use_semantic_reranker else "simple",
199+
top=sources_to_include,
200+
select="Description,HotelName,Tags"
201+
)
202+
203+
return [ document async for document in response ]
204+
205+
GROUNDED_PROMPT="""
206+
You are a friendly assistant that recommends hotels based on activities and amenities.
207+
Answer the query using only the sources provided below in a friendly and concise bulleted manner.
208+
Answer ONLY with the facts listed in the list of sources below.
209+
If there isn't enough information below, say you don't know.
210+
Do not generate answers that don't use the sources below.
211+
Query: {query}
212+
Sources:\n{sources}
213+
"""
214+
class ChatThread:
215+
def __init__(self):
216+
self.messages = []
217+
self.search_results = []
218+
219+
def append_message(self, role: str, message: str):
220+
self.messages.append({
221+
"role": role,
222+
"content": message
223+
})
224+
225+
async def append_grounded_message(self, search_client: SearchClient, query: str, search_type: SearchType, use_semantic_reranker: bool = True, sources_to_include: int = 5, k: int = 50):
226+
sources = await get_sources(search_client, query, search_type, use_semantic_reranker, sources_to_include, k)
227+
sources_formatted = "\n".join([f'{document["HotelName"]}:{document["Description"]}:{document["Tags"]}' for document in sources])
228+
self.append_message(role="user", message=GROUNDED_PROMPT.format(query=query, sources=sources_formatted))
229+
self.search_results.append(
230+
{
231+
"message_index": len(self.messages) - 1,
232+
"query": query,
233+
"sources": sources
234+
}
235+
)
236+
237+
async def get_openai_response(self, openai_client: AsyncAzureOpenAI, model: str):
238+
response = await openai_client.chat.completions.create(
239+
messages=self.messages,
240+
model=model
241+
)
242+
self.append_message(role="assistant", message=response.choices[0].message.content)
243+
244+
def get_last_message(self) -> Optional[object]:
245+
return self.messages[-1] if len(self.messages) > 0 else None
246+
247+
def get_last_message_sources(self) -> Optional[List[object]]:
248+
return self.search_results[-1]["sources"] if len(self.search_results) > 0 else None
249+
```
250+
251+
1. Invoke the chat thread and call the query function, passing in a query string to search for.
252+
253+
```python
254+
import azure.identity.aio
255+
256+
chat_thread = ChatThread()
257+
chat_deployment = AZURE_DEPLOYMENT_MODEL
258+
259+
async with azure.identity.aio.DefaultAzureCredential() as credential, create_search_client(credential) as search_client, create_openai_client(credential) as openai_client:
260+
await chat_thread.append_grounded_message(
261+
search_client=search_client,
262+
query="Can you recommend a few hotels near the ocean with beach access and good views",
263+
search_type=SearchType(search_type),
264+
use_semantic_reranker=use_semantic_reranker,
265+
sources_to_include=sources_to_include,
266+
k=k)
267+
await chat_thread.get_openai_response(openai_client=openai_client, model=chat_deployment)
268+
269+
print(chat_thread.get_last_message()["content"])
270+
```
271+
272+
Output might look similar to the following example:
273+
274+
```bash
275+
Based on your request, here are a few hotel recommendations with beach access and good views:
276+
277+
1. Ocean Air Motel - oceanfront hotel with a private balcony and indoor and outdoor pools
278+
2. Marquis Plaza & Suites - offers a view, free Wi-Fi, and a pool
279+
3. Pull'r Inn Motel - offers a view, a pool, and free Wi-Fi
280+
281+
I hope this helps! Let me know if you need any further assistance.
282+
```
283+
284+
## Clean up
285+
286+
When you're working in your own subscription, it's a good idea at the end of a project to identify whether you still need the resources you created. Resources left running can cost you money. You can delete resources individually or delete the resource group to delete the entire set of resources.
287+
288+
You can find and manage resources in the portal by using the **All resources** or **Resource groups** link in the leftmost pane.
289+
290+
## Next steps
291+
292+
As a next step, we recommend that you review the demo code for [Python](https://github.com/Azure/azure-search-vector-samples/tree/main/demo-python), [C#](https://github.com/Azure/azure-search-vector-samples/tree/main/demo-dotnet), or [JavaScript](https://github.com/Azure/azure-search-vector-samples/tree/main/demo-javascript).

0 commit comments

Comments
 (0)