Skip to content

Commit e332aac

Browse files
committed
Draft of relevance rag tutorial
1 parent 011fd91 commit e332aac

File tree

3 files changed

+224
-2
lines changed

3 files changed

+224
-2
lines changed

articles/search/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ items:
104104
href: tutorial-rag-build-solution-pipeline.md
105105
- name: Search and generate answers
106106
href: tutorial-rag-build-solution-query.md
107+
- name: Maximize relevance
108+
href: tutorial-rag-build-solution-maximize-relevance.md
107109
- name: Skills tutorials
108110
items:
109111
- name: C#
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
---
2+
title: 'RAG Tutorial: Relevance tuning'
3+
titleSuffix: Azure AI Search
4+
description: Learn how to use the relevance tuning capabilities to return high quality results for generative search.
5+
6+
manager: nitinme
7+
author: HeidiSteen
8+
ms.author: heidist
9+
ms.service: cognitive-search
10+
ms.topic: tutorial
11+
ms.date: 10/05/2024
12+
13+
---
14+
15+
# Tutorial: Maximize relevance (RAG in Azure AI Search)
16+
17+
In this tutorial, learn how to improve the relevance of search results used in RAG solutions. Relevance tuning can be an important factor in delivering a RAG solution that meets user expectations. In Azure AI Search, relevance tuning includes L2 semantic ranking, scoring profiles, vector query weighting and minimum thresholds, and other options.
18+
19+
To implement some of these technqiues, you revisit the index schema to add configurations for semantic ranking and scoring profiles. Other relevance tuning techniques apply to the queries themselves.
20+
21+
In this tutorial, you modify the existing search index and queries to use:
22+
23+
> [!div class="checklist"]
24+
> - L2 semantic ranking
25+
> - Scoring profile for document boosting
26+
> - Vector weighting
27+
> - Minimum thresholds on vector results
28+
29+
This tutorial updates the search index created by the [indexing pipeline](tutorial-rag-build-solution-pipeline.md). Updates don't affect the existing content, so no rebuild is necessary and you won't need to rerun the indexer.
30+
31+
## Prerequisites
32+
33+
- [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/).
34+
35+
- [Azure AI Search](search-create-service-portal.md), Basic tier or above for managed identity and semantic ranking, in the same region as Azure OpenAI and Azure AI Services.
36+
37+
- [Azure OpenAI](/azure/ai-services/openai/how-to/create-resource), with a deployment of text-embedding-002 and gpt-35-turbo, in the same region as Azure AI Search.
38+
39+
## Download the sample
40+
41+
The [sample notebook](https://github.com/Azure-Samples/azure-search-python-samples/blob/main/Tutorial-RAG/Tutorial-rag.ipynb) includes an updated index and query request.
42+
43+
## Update the index for semantic ranking and scoring profiles
44+
45+
In a previous tutorial, you [designed an index schema](tutorial-rag-build-solution-index-schema.md) for RAG workloads. We purposely omitted relevance enhancements from that schema so that you could focus on the fundamentals. Deferring relevance to a separate exercise also gives you a before-and-after comparison of the quality of search results after the updates are made.
46+
47+
1. Update the import statements to include classes for semantic ranking and scoring profiles.
48+
49+
```python
50+
from azure.identity import DefaultAzureCredential
51+
from azure.identity import get_bearer_token_provider
52+
from azure.search.documents.indexes import SearchIndexClient
53+
from azure.search.documents.indexes.models import (
54+
SearchField,
55+
SearchFieldDataType,
56+
VectorSearch,
57+
HnswAlgorithmConfiguration,
58+
VectorSearchProfile,
59+
AzureOpenAIVectorizer,
60+
AzureOpenAIVectorizerParameters,
61+
SearchIndex,
62+
SemanticConfiguration,
63+
SemanticPrioritizedFields,
64+
SemanticField,
65+
SemanticSearch,
66+
ScoringProfile,
67+
TagScoringFunction,
68+
TagScoringParameters
69+
)
70+
```
71+
72+
1. Add the following semantic configuration to the search index. This example can be found in the update schema step in the notebook.
73+
74+
```python
75+
# New semantic configuration
76+
semantic_config = SemanticConfiguration(
77+
name="my-semantic-config",
78+
prioritized_fields=SemanticPrioritizedFields(
79+
title_field=SemanticField(field_name="title"),
80+
keywords_fields=[SemanticField(field_name="locations")],
81+
content_fields=[SemanticField(field_name="chunk")]
82+
)
83+
)
84+
85+
# Create the semantic settings with the configuration
86+
semantic_search = SemanticSearch(configurations=[semantic_config])
87+
```
88+
89+
A semantic configuration has a name and a prioritized list of fields to help optimize the inputs to semantic ranker. For more information, see [Configure semantic ranking](/azure/search/semantic-how-to-configure).
90+
91+
1. Next, add a scoring profile definition. As with semantic configuration, a scoring profile can be added to an index schema at any time. This example is also in the update schema step in the notebook, following the semantic configuration.
92+
93+
```python
94+
# New scoring profile
95+
scoring_profiles = [
96+
ScoringProfile(
97+
name="my-scoring-profile",
98+
functions=[
99+
TagScoringFunction(
100+
field_name="locations",
101+
boost=5.0,
102+
parameters=TagScoringParameters(
103+
tags_parameter="tags",
104+
),
105+
)
106+
]
107+
)
108+
]
109+
```
110+
111+
This profile uses the tag function which boosts the scores of documents where a match was found in the locations field. Recall that the search index has a vector field, and multiple nonvector fields for title, chunks, and locations. The locations field is a string collection, and string collections can be boosted using the tags function in a scoring profile. For more information, see [Add a scoring profile](index-add-scoring-profiles.md) and [Enhancing Search Relevance with Document Boosting (blog post)](https://farzzy.hashnode.dev/enhance-azure-ai-search-document-boosting).
112+
113+
1. Update the index definition on the search service.
114+
115+
```python
116+
# Update the search index with the semantic configuration
117+
index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search, semantic_search=semantic_search, scoring_profiles=scoring_profiles)
118+
result = index_client.create_or_update_index(index)
119+
print(f"{result.name} updated")
120+
```
121+
122+
## Update queries for semantic ranking and scoring profiles
123+
124+
In a previous tutorial, you [ran queries](tutorial-rag-build-solution-query.md) that execute on the search engine, and pass the response and other information to an LLM for chat completion.
125+
126+
This example modifies the query request to include the semantic configuration and scoring profile.
127+
128+
```python
129+
# Import libraries
130+
from azure.search.documents import SearchClient
131+
from openai import AzureOpenAI
132+
133+
token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")
134+
openai_client = AzureOpenAI(
135+
api_version="2024-06-01",
136+
azure_endpoint=AZURE_OPENAI_ACCOUNT,
137+
azure_ad_token_provider=token_provider
138+
)
139+
140+
deployment_name = "gpt-35-turbo"
141+
142+
search_client = SearchClient(
143+
endpoint=AZURE_SEARCH_SERVICE,
144+
index_name=index_name,
145+
credential=credential
146+
)
147+
148+
# Prompt is unchanged in this update
149+
GROUNDED_PROMPT="""
150+
You are an AI assistant that helps users learn from the information found in the source material.
151+
Answer the query using only the sources provided below.
152+
Use bullets if the answer has multiple points.
153+
If the answer is longer than 3 sentences, provide a summary.
154+
Answer ONLY with the facts listed in the list of sources below.
155+
If there isn't enough information below, say you don't know.
156+
Do not generate answers that don't use the sources below.
157+
Query: {query}
158+
Sources:\n{sources}
159+
"""
160+
161+
# Queries are unchanged in this update
162+
query="how much of earth is covered by water"
163+
vector_query = VectorizableTextQuery(text=query, k_nearest_neighbors=1, fields="text_vector", exhaustive=True)
164+
165+
# Add query_type semantic and semantic_configuration_name
166+
# Add scoring_profile and scoring_parameters
167+
search_results = search_client.search(
168+
query_type="semantic",
169+
semantic_configuration_name="my-semantic-config",
170+
scoring_profile="my-scoring-profile",
171+
scoring_parameters=["tags-ocean, 'sea surface', seas, surface"],
172+
search_text=query,
173+
vector_queries= [vector_query],
174+
select="title, chunk, locations",
175+
top=5,
176+
)
177+
sources_formatted = "\n".join([f'{document["title"]}:{document["chunk"]}:{document["locations"]}' for document in search_results])
178+
179+
response = openai_client.chat.completions.create(
180+
messages=[
181+
{
182+
"role": "user",
183+
"content": GROUNDED_PROMPT.format(query=query, sources=sources_formatted)
184+
}
185+
],
186+
model=deployment_name
187+
)
188+
189+
print(response.choices[0].message.content)
190+
```
191+
192+
## Update queries for minimum thresholds
193+
194+
Keyword search only returns results if there's match found in the index, up to a maximum of 50 results by default. In contrast, vector search returns *k*-results every time, even if the matching vectors aren't a close match.
195+
196+
Using preview features, you can unpack a hybrid search score to review the individual component scores. Based on that information, you can set minimum thresholds to exclude any match that falls below it.
197+
198+
## Update queries for vector weighting
199+
200+
Semantic ranking and scoring profiles operate on nonvector content, but you can tune the vector portion of a hybrid query to amplify or diminish its importance based on how much value it adds to the results. For example, if you run keyword search and vector search independently and find that one of them is outperforming the other, you can adjust the weight on the vector side to higher or lower. This approach gives you more control over query processing.
201+
202+
203+
<!-- Key points:
204+
205+
- How to measure relevance (?) to determine if changes are improving results
206+
- Try different algorithms (HNSW vs eKnn)
207+
- Change query structure (hybrid with vector/non over same content (double-down), hybrid over multiple fields)
208+
- semantic ranking
209+
- scoring profiles
210+
- thresholds for minimum score
211+
- set weights
212+
- filters
213+
- analyzers and normalizers
214+
- advanced query formats (regular expressions, fuzzy search) -->
215+
216+
<!-- ## Next step
217+
218+
> [!div class="nextstepaction"]
219+
> [Reduce vector storage and costs](tutorial-rag-build-solution-minimize-storage.md)
220+
-->

articles/search/tutorial-rag-build-solution-query.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Tasks:
230230
- H2 Query using vectors and text-to-vector conversion at query time (not sure what the code looks like for this)
231231
- H2 Query parent-child two indexes (unclear how to do this, Carey said query on child, do a lookup query on parent) -->
232232

233-
<!-- ## Next step
233+
## Next step
234234

235235
> [!div class="nextstepaction"]
236-
> [Maximize relevance](tutorial-rag-build-solution-maximize-relevance.md) -->
236+
> [Maximize relevance](tutorial-rag-build-solution-maximize-relevance.md)

0 commit comments

Comments
 (0)