Partager via


Tutoriel : Optimiser la pertinence (RAG dans Recherche Azure AI)

Dans ce tutoriel, découvrez comment améliorer la pertinence des résultats de recherche utilisés dans les solutions RAG. Le réglage de la pertinence peut être un facteur important dans la création d’une solution RAG qui répond aux attentes des utilisateurs. Dans Recherche Azure AI, le réglage de la pertinence comprend le classement sémantique L2 et les profils de scoring.

Pour implémenter ces fonctionnalités, vous revisitez le schéma d’index pour ajouter des configurations pour le classement sémantique et les profils de scoring. Vous réexécutez ensuite les requêtes à l’aide des nouvelles constructions.

Dans ce tutoriel, vous modifiez l’index de recherche et les requêtes existants à utiliser :

  • Classement sémantique L2
  • Profil de scoring pour l’amélioration des documents

Ce tutoriel met à jour l’index de recherche créé par le pipeline d’indexation. Les mises à jour n’affectent pas le contenu existant. Par conséquent, aucune reconstruction n’est nécessaire et vous n’avez pas besoin de réexécuter l’indexeur.

Remarque

Il existe d’autres fonctionnalités de pertinence en préversion, notamment la pondération des requêtes vectorielles et la définition des seuils minimaux, mais nous ne les abordons pas dans ce tutoriel parce qu’elles sont en préversion.

Prérequis

Télécharger l’exemple

L’exemple de notebook contient un index et une demande de requête mis à jour.

Exécuter une requête de référence pour la comparaison

Commençons par une nouvelle requête : « Existe-t-il des formations de nuages spécifiques aux océans et aux grandes étendues d’eau ? ».

Pour comparer les résultats après l’ajout de fonctionnalités de pertinence, exécutez la requête sur le schéma d’index existant avant d’ajouter un classement sémantique ou un profil de scoring.

Pour le cloud Azure Government, modifiez le point de terminaison d’API sur le fournisseur de jetons en "https://cognitiveservices.azure.us/.default".

from azure.search.documents import SearchClient
from openai import AzureOpenAI

token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")
openai_client = AzureOpenAI(
     api_version="2024-06-01",
     azure_endpoint=AZURE_OPENAI_ACCOUNT,
     azure_ad_token_provider=token_provider
 )

deployment_name = "gpt-4o"

search_client = SearchClient(
     endpoint=AZURE_SEARCH_SERVICE,
     index_name=index_name,
     credential=credential
 )

GROUNDED_PROMPT="""
You are an AI assistant that helps users learn from the information found in the source material.
Answer the query using only the sources provided below.
Use bullets if the answer has multiple points.
If the answer is longer than 3 sentences, provide a summary.
Answer ONLY with the facts listed in the list of sources below. Cite your source when you answer the question
If there isn't enough information below, say you don't know.
Do not generate answers that don't use the sources below.
Query: {query}
Sources:\n{sources}
"""

# Focused query on cloud formations and bodies of water
query="Are there any cloud formations specific to oceans and large bodies of water?"
vector_query = VectorizableTextQuery(text=query, k_nearest_neighbors=50, fields="text_vector")

search_results = search_client.search(
    search_text=query,
    vector_queries= [vector_query],
    select=["title", "chunk", "locations"],
    top=5,
)

sources_formatted = "=================\n".join([f'TITLE: {document["title"]}, CONTENT: {document["chunk"]}, LOCATIONS: {document["locations"]}' for document in search_results])

response = openai_client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": GROUNDED_PROMPT.format(query=query, sources=sources_formatted)
        }
    ],
    model=deployment_name
)

print(response.choices[0].message.content)

La sortie de cette demande pourrait ressembler à l’exemple suivant.

Yes, there are cloud formations specific to oceans and large bodies of water. 
A notable example is "cloud streets," which are parallel rows of clouds that form over 
the Bering Strait in the Arctic Ocean. These cloud streets occur when wind blows from 
a cold surface like sea ice over warmer, moister air near the open ocean, leading to 
the formation of spinning air cylinders. Clouds form along the upward cycle of these cylinders, 
while skies remain clear along the downward cycle (Source: page-21.pdf).

Mettre à jour l’index pour le classement sémantique et les profils de scoring

Dans un tutoriel précédent, vous avez conçu un schéma d’index pour les charges de travail RAG. Nous avons omis volontairement les améliorations de pertinence de ce schéma afin que vous puissiez vous concentrer sur les bases. Le report de la pertinence sur un exercice distinct vous donne une comparaison avant-après de la qualité des résultats de recherche une fois les mises à jour effectuées.

  1. Mettez à jour les instructions d’importation afin d’inclure des classes pour le classement sémantique et les profils de scoring.

     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,
         SemanticConfiguration,
         SemanticPrioritizedFields,
         SemanticField,
         SemanticSearch,
         ScoringProfile,
         TagScoringFunction,
         TagScoringParameters
     )
    
  2. Ajoutez la configuration sémantique suivante à l’index de recherche. Cet exemple se trouve dans l’étape de mise à jour du schéma dans le notebook.

    # New semantic configuration
    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")]
        )
    )
    
    # Create the semantic settings with the configuration
    semantic_search = SemanticSearch(configurations=[semantic_config])
    

    Une configuration sémantique a un nom et une liste hiérarchisée de champs pour optimiser les entrées dans le classeur sémantique. Pour plus d’informations, consultez Configurer le classement sémantique.

  3. Ensuite, ajoutez une définition de profil de scoring. Comme avec la configuration sémantique, un profil de scoring peut être ajouté à un schéma d’index à tout moment. Cet exemple figure également dans l’étape de mise à jour du schéma dans le notebook, après la configuration sémantique.

    # New scoring profile
    scoring_profiles = [  
        ScoringProfile(  
            name="my-scoring-profile",
            functions=[
                TagScoringFunction(  
                    field_name="locations",  
                    boost=5.0,  
                    parameters=TagScoringParameters(  
                        tags_parameter="tags",  
                    ),  
                ) 
            ]
        )
    ]
    

    Ce profil utilise la fonction tag qui améliore les scores des documents où une correspondance a été trouvée dans le champ locations. Rappelez-vous que l’index de recherche a un champ vectoriel et plusieurs champs non vectoriels pour le titre (title), les blocs (chunks) et les emplacements (locations). Le champ location est une collection de chaînes, et les collections de chaînes peuvent être boostées à l’aide de la fonction tags dans un profil de scoring. Pour plus d’informations, consultez Ajouter un profil de scoring et Amélioration de la pertinence de la recherche avec l’amélioration de documents (billet de blog).

  4. Mettez à jour la définition d’index sur le service de recherche.

    # Update the search index with the semantic configuration
     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} updated")  
    

Mettre à jour les requêtes pour le classement sémantique et les profils de scoring

Dans un tutoriel précédent, vous avez exécuté des requêtes qui s’exécutent sur le moteur de recherche, en passant la réponse et d’autres informations à un LLM pour la complétion de la conversation.

Cet exemple modifie la demande de requête pour inclure la configuration sémantique et le profil de scoring.

Pour le cloud Azure Government, modifiez le point de terminaison d’API sur le fournisseur de jetons en "https://cognitiveservices.azure.us/.default".

# Import libraries
from azure.search.documents import SearchClient
from openai import AzureOpenAI

token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")
openai_client = AzureOpenAI(
     api_version="2024-06-01",
     azure_endpoint=AZURE_OPENAI_ACCOUNT,
     azure_ad_token_provider=token_provider
 )

deployment_name = "gpt-4o"

search_client = SearchClient(
     endpoint=AZURE_SEARCH_SERVICE,
     index_name=index_name,
     credential=credential
 )

# Prompt is unchanged in this update
GROUNDED_PROMPT="""
You are an AI assistant that helps users learn from the information found in the source material.
Answer the query using only the sources provided below.
Use bullets if the answer has multiple points.
If the answer is longer than 3 sentences, provide a summary.
Answer ONLY with the facts listed in the list of sources below.
If there isn't enough information below, say you don't know.
Do not generate answers that don't use the sources below.
Query: {query}
Sources:\n{sources}
"""

# Queries are unchanged in this update
query="Are there any cloud formations specific to oceans and large bodies of water?"
vector_query = VectorizableTextQuery(text=query, k_nearest_neighbors=50, fields="text_vector")

# Add query_type semantic and semantic_configuration_name
# Add scoring_profile and scoring_parameters
search_results = search_client.search(
    query_type="semantic",
    semantic_configuration_name="my-semantic-config",
    scoring_profile="my-scoring-profile",
    scoring_parameters=["tags-ocean, 'sea surface', seas, surface"],
    search_text=query,
    vector_queries= [vector_query],
    select="title, chunk, locations",
    top=5,
)
sources_formatted = "=================\n".join([f'TITLE: {document["title"]}, CONTENT: {document["chunk"]}, LOCATIONS: {document["locations"]}' for document in search_results])

response = openai_client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": GROUNDED_PROMPT.format(query=query, sources=sources_formatted)
        }
    ],
    model=deployment_name
)

print(response.choices[0].message.content)

La sortie d’une requête classée sémantiquement et boostée pourrait ressembler à l’exemple suivant.

Yes, there are specific cloud formations influenced by oceans and large bodies of water:

- **Stratus Clouds Over Icebergs**: Low stratus clouds can frame holes over icebergs, 
such as Iceberg A-56 in the South Atlantic Ocean, likely due to thermal instability caused 
by the iceberg (source: page-39.pdf).

- **Undular Bores**: These are wave structures in the atmosphere created by the collision 
of cool, dry air from a continent with warm, moist air over the ocean, as seen off the 
coast of Mauritania (source: page-23.pdf).

- **Ship Tracks**: These are narrow clouds formed by water vapor condensing around tiny 
particles from ship exhaust. They are observed over the oceans, such as in the Pacific Ocean 
off the coast of California (source: page-31.pdf).

These specific formations are influenced by unique interactions between atmospheric conditions 
and the presence of large water bodies or objects within them.

L’ajout d’un classement sémantique et de profils de scoring affecte positivement la réponse du LLM en favorisant les résultats qui répondent aux critères de scoring et qui sont pertinents d’un point de vue sémantique.

Maintenant que vous avez une meilleure compréhension de la conception d’index et de requête, nous allons passer à l’optimisation pour la vitesse et la concision. Nous revisitons la définition du schéma pour implémenter une quantification et une réduction du stockage, mais le reste du pipeline et des modèles restent intacts.

Étape suivante