Modifier

Partager via


Récupération d’informations

Azure AI services
Azure AI Search
Azure OpenAI Service
Azure Machine Learning

Une fois que vous avez généré les embeddings pour vos segments, l’étape suivante consiste à générer l’index dans la base de données vectorielle et à expérimenter pour déterminer les recherches optimales à effectuer. Lorsque vous expérimentez la récupération d’informations, il y a plusieurs aspects à considérer, y compris les options de configuration de l’index de recherche, les types de recherches que vous devez effectuer, et votre stratégie de reclassement. Cet article couvre ces trois sujets.

Cet article fait partie d’une série. Lisez l’introduction.

Index de recherche

Remarque

Azure AI Search est un service de recherche Azure natif. Cette section mentionnera certains détails spécifiques pour AI Search. Si vous utilisez un autre store, consultez la documentation pour trouver les configurations clés pour ce service.

L’index de recherche dans votre store a une colonne pour chaque champ de vos données. Les stores de recherche prennent généralement en charge les types de données non vectorielles tels que chaîne, booléen, entier, simple, double, datetime, et des collections comme Collection(simple) et types de données vectorielles tels que Collection(simple). Pour chaque colonne, vous devez configurer les informations telles que le type de données, si le champ est filtrable, récupérable et/ou consultable.

Voici quelques décisions clés que vous devez prendre pour la configuration de recherche vectorielle appliquée aux champs vectoriels :

  • Algorithme de recherche vectorielle : L’algorithme utilisé pour rechercher des correspondances relatives. Azure AI Search dispose d'une option d'algorithme de force brute qui analyse l'ensemble de l'espace vectoriel, appelée KNN exhaustive, et d'une option d'algorithme plus performante qui effectue une recherche approximative du plus proche voisin (ANN), appelée Hierarchical Navigable Small World (HNSW).
  • Métrique : Cette configuration est la métrique de similarité utilisée pour calculer la proximité par l’algorithme. Les options dans Azure AI Search sont cosinus, produit scalaire, et euclidienne. Si vous utilisez des modèles d’embedding Azure OpenAI, choisissez cosine.
  • efConstruction : Paramètre utilisé lors de la construction de l’index Hierarchical Navigable Small Worlds (HNSW) qui définit le nombre de voisins les plus proches connectés à un vecteur lors de l’indexation. Une valeur efConstruction plus grande donne un index de meilleure qualité qu’une valeur plus petite. Le compromis est qu’une valeur plus grande nécessite plus de temps, de stockage et de calcul. efConstruction devrait être plus élevé pour un grand nombre de segments et plus bas pour un faible nombre de segments. Déterminer la valeur optimale nécessite des expérimentations avec vos données et les requêtes prévues.
  • efSearch : Paramètre utilisé au moment de la requête pour définir le nombre de voisins les plus proches (c’est-à-dire, segments similaires) utilisés pendant la recherche.
  • m : Le nombre de liens bidirectionnels. La plage est de 4 à 10, avec des nombres plus bas retournant moins de bruit dans les résultats.

Dans Azure AI Search, les configurations vectorielles sont encapsulées dans une configuration vectorSearch. Lors de la configuration de vos colonnes vectorielles, vous référencez la configuration appropriée pour cette colonne vectorielle et définissez le nombre de dimensions. L’attribut de dimensions de la colonne vectorielle représente le nombre de dimensions générées par le modèle d’embedding que vous avez choisi. Par exemple, le modèle text-embedding-3-small optimisé pour le stockage génère 1 536 dimensions.

Recherches

Lors de l’exécution des requêtes à partir de votre orchestrateur de prompts contre votre store de recherche, vous avez de nombreuses options à considérer. Vous devez déterminer :

  • Quel type de recherche vous allez effectuer : vectorielle, par mot-clé ou hybride.
  • Si vous allez interroger une ou plusieurs colonnes.
  • Si vous allez exécuter manuellement plusieurs requêtes, telles qu’une requête par mot-clé et une recherche vectorielle.
  • Si la requête doit être décomposée en sous-requêtes.
  • Si le filtrage doit être utilisé dans vos requêtes.

Votre orchestrateur de prompts peut prendre une approche statique ou une approche dynamique en mélangeant les approches en fonction des indices contextuels du prompt. Les sections suivantes abordent ces options pour vous aider à expérimenter afin de trouver la bonne approche pour votre charge de travail.

Rechercher dans les types

Les plateformes de recherche prennent généralement en charge les recherches en texte intégral et vectorielles. Certaines plateformes, comme Azure AI Search, prennent en charge les recherches hybrides. Pour voir les capacités des différentes offres de recherche vectorielle, consultez la rubrique Choisir un service Azure pour la recherche vectorielle.

Les recherches vectorielles correspondent à la similarité entre la requête vectorisée (prompt) et les champs vectoriels.

Important

Vous devez effectuer les mêmes opérations de nettoyage que celles que vous avez effectuées sur les segments avant d'intégrer la requête. Par exemple, si vous avez mis en minuscule chaque mot de votre segment vectorisé, vous devez mettre en minuscule chaque mot de la requête avant de la vectoriser.

Remarque

Vous pouvez effectuer une recherche vectorielle sur plusieurs champs vectoriels dans la même requête. Dans Azure AI Search, cela est techniquement une recherche hybride. Pour plus d’informations, voir cette section.

embedding = embedding_model.generate_embedding(
    chunk=str(pre_process.preprocess(query))
)

vector = RawVectorQuery(
    k=retrieve_num_of_documents,
    fields="contentVector",
    vector=embedding,
)

results = client.search(
    search_text=None,
    vector_queries=[vector],
    top=retrieve_num_of_documents,
    select=["title", "content", "summary"],
)

Le code d’exemple effectue une recherche vectorielle sur le champ contentVector. Notez que le code qui vectorise la requête pré-traite d’abord la requête. Ce pré-traitement doit être le même code que celui qui pré-traite les segments avant de les vectoriser. Le modèle d’embedding doit être le même modèle d’embedding qui a vectorisé les segments.

Les recherches en texte intégral correspondent au texte brut stocké dans un index. Il est courant d’extraire des mots-clés d’une requête et d’utiliser ces mots-clés extraits dans une recherche en texte intégral sur une ou plusieurs colonnes indexées. Les recherches en texte intégral peuvent être configurées pour renvoyer des correspondances où tous les termes ou certains termes correspondent.

Vous devez expérimenter pour déterminer quels champs sont efficaces pour exécuter des recherches en texte intégral. Comme discuté dans la phase d’enrichissement, les champs de métadonnées des mots-clés et des entités sont de bons candidats pour la recherche en texte intégral dans des scénarios où le contenu a une signification sémantique similaire, mais où les entités ou les mots-clés diffèrent. D’autres champs courants à considérer pour la recherche en texte intégral sont le titre, le résumé et le texte du segment.

formatted_search_results = []

results = client.search(
    search_text=query,
    top=retrieve_num_of_documents,
    select=["title", "content", "summary"],
)

formatted_search_results = format_results(results)

Le code d’exemple effectue une recherche en texte intégral sur les champs titre, contenu et résumé.

Azure AI Search prend en charge les requêtes hybrides où votre requête peut contenir une ou plusieurs recherches textuelles et une ou plusieurs recherches vectorielles. La plateforme exécute chaque requête, obtient les résultats intermédiaires, reclasse les résultats en utilisant Reciprocal Rank Fusion (RRF), et renvoie les meilleurs N résultats.

 embedding = embedding_model.generate_embedding(
    chunk=str(pre_process.preprocess(query))
)
vector1 = RawVectorQuery(
    k=retrieve_num_of_documents,
    fields="contentVector",
    vector=embedding,
)
vector2 = RawVectorQuery(
    k=retrieve_num_of_documents,
    fields="questionVector",
    vector=embedding,
)

results = client.search(
    search_text=query,
    vector_queries=[vector1, vector2],
    top=retrieve_num_of_documents,
    select=["title", "content", "summary"],
)

Le code d’exemple effectue une recherche en texte intégral sur les champs titre, contenu et résumé et des recherches vectorielles sur les champs contentVector et questionVector. La plateforme Azure AI Search exécute toutes les requêtes en parallèle, reclasse les résultats et renvoie les meilleurs documents retrieve_num_of_documents.

Manuel multiple

Vous pouvez, bien sûr, exécuter plusieurs requêtes, telles qu’une recherche vectorielle et une recherche en texte intégral par mot-clé, manuellement. Vous agrégerez les résultats et reclasserez les résultats manuellement et renverrez les meilleurs résultats. Voici quelques cas d’utilisation pour manuel multiple :

  • Vous utilisez une plateforme de recherche qui ne prend pas en charge les recherches hybrides. Vous suivriez cette option pour effectuer votre propre recherche hybride.
  • Vous voulez exécuter des recherches en texte intégral contre différentes requêtes. Par exemple, vous pourriez extraire des mots-clés de la requête et exécuter une recherche en texte intégral sur votre champ de métadonnées des mots-clés. Vous pourriez ensuite extraire des entités et exécuter une requête sur le champ de métadonnées des entités.
  • Vous voulez contrôler le processus de reclassement vous-même.
  • La requête nécessite plusieurs sous-requêtes pour récupérer les données de base à partir de plusieurs sources.

Sous-requêtes multiples

Certains prompts sont complexes et nécessitent plus d’une collection de données pour fonder le modèle. Par exemple, la requête « Comment fonctionnent les voitures électriques et quelle est la comparaison par rapport aux véhicules à moteur à combustion ? » nécessite probablement des données de base provenant de plusieurs sources.

Il est bon de déterminer si la requête nécessite plusieurs recherches avant d’exécuter des recherches. Si vous jugez que plusieurs sous-requêtes sont nécessaires, vous pouvez exécuter des requêtes manuelles multiples pour toutes les requêtes. Utilisez un grand modèle de langage pour déterminer si plusieurs sous-requêtes sont nécessaires. Le prompt suivant est tiré de l’accélérateur d’expérimentation RAG utilisé pour catégoriser une requête comme simple ou complexe, les complexes nécessitant plusieurs requêtes :

Consider the given question to analyze and determine if it falls into one of these categories:
1. Simple, factual question
  a. The question is asking for a straightforward fact or piece of information
  b. The answer could likely be found stated directly in a single passage of a relevant document
  c. Breaking the question down further is unlikely to be beneficial
  Examples: "What year did World War 2 end?", "What is the capital of France?, "What is the features of productX?"
2. Complex, multi-part question
  a. The question has multiple distinct components or is asking for information about several related topics
  b. Different parts of the question would likely need to be answered by separate passages or documents
  c. Breaking the question down into sub-questions for each component would allow for better results
  d. The question is open-ended and likely to have a complex or nuanced answer
  e. Answering it may require synthesizing information from multiple sources
  f. The question may not have a single definitive answer and could warrant analysis from multiple angles
  Examples: "What were the key causes, major battles, and outcomes of the American Revolutionary War?", "How do electric cars work and how do they compare to gas-powered vehicles?"

Based on this rubric, does the given question fall under category 1 (simple) or category 2 (complex)? The output should be in strict JSON format. Ensure that the generated JSON is 100 percent structurally correct, with proper nesting, comma placement, and quotation marks. There should not be any comma after last element in the JSON.

Example output:
{
  "category": "simple"
}

Un grand modèle de langage peut également être utilisé pour extraire des sous-requêtes d’une requête complexe. Le prompt suivant est tiré de l’accélérateur d’expérimentation RAG qui convertit une requête complexe en plusieurs sous-requêtes.

Your task is to take a question as input and generate maximum 3 sub-questions that cover all aspects of the original question. The output should be in strict JSON format, with the sub-questions contained in an array.
Here are the requirements:
1. Analyze the original question and identify the key aspects or components.
2. Generate sub-questions that address each aspect of the original question.
3. Ensure that the sub-questions collectively cover the entire scope of the original question.
4. Format the output as a JSON object with a single key "questions" that contains an array of the generated sub-questions.
5. Each sub-question should be a string within the "questions" array.
6. The JSON output should be valid and strictly formatted.
7. Ensure that the generated JSON is 100 percent structurally correct, with proper nesting, comma placement, and quotation marks. The JSON should be formatted with proper indentation for readability.
8. There should not be any comma after last element in the array.

Example input question:
What are the main causes of deforestation, and how can it be mitigated?

Example output:
{
  "questions": [
    "What are the primary human activities that contribute to deforestation?",
    "How does agriculture play a role in deforestation?",
    "What is the impact of logging and timber harvesting on deforestation?",
    "How do urbanization and infrastructure development contribute to deforestation?",
    "What are the environmental consequences of deforestation?",
    "What are some effective strategies for reducing deforestation?",
    "How can reforestation and afforestation help mitigate the effects of deforestation?",
    "What role can governments and policies play in preventing deforestation?",
    "How can individuals and communities contribute to reducing deforestation?"
  ]
}

Filtrage

Les champs du store de recherche configurés comme filtrables peuvent être utilisés pour filtrer les requêtes. Envisagez de filtrer sur les mots-clés et les entités pour les requêtes qui utilisent ces champs afin d’aider à affiner le résultat. Le filtrage vous permet de récupérer uniquement les données qui satisfont certaines conditions à partir d’un index en éliminant les données non pertinentes. Cela améliore les performances globales de la requête avec des résultats plus pertinents. Comme pour toute décision, il est important d’expérimenter et de tester. Les requêtes peuvent ne pas avoir de mots-clés ou avoir des mots-clés incorrects, des abréviations ou des acronymes. Vous devez prendre en compte ces cas.

Reclassement

Le reclassement vous permet d’exécuter une ou plusieurs requêtes, d’agréger les résultats et de classer ces résultats. Envisagez les raisons suivantes pour reclasser vos résultats de recherche :

  • Vous avez effectué des recherches manuelles multiples et vous souhaitez agréger les résultats et les classer.
  • Les recherches vectorielles et par mot-clé ne sont pas toujours précises. Vous pouvez augmenter le nombre de documents renvoyés par votre recherche, en incluant potentiellement certains résultats valides qui seraient autrement ignorés, et utiliser le reclassement pour évaluer les résultats.

Vous pouvez utiliser un grand modèle de langage ou un cross-encodeur pour effectuer le reclassement. Certaines plateformes, comme Azure AI Search, ont des méthodes propriétaires pour reclasser les résultats. Vous pouvez évaluer ces options pour vos données afin de déterminer ce qui fonctionne le mieux pour votre scénario. Les sections suivantes fournissent des détails sur ces méthodes.

Reclassement par grand modèle de langage

Voici un prompt de grand modèle de langage tiré de l’accélérateur d’expérimentation RAG qui reclasser les résultats.

A list of documents is shown below. Each document has a number next to it along with a summary of the document. A question is also provided.
Respond with the numbers of the documents you should consult to answer the question, in order of relevance, as well as the relevance score as json string based on json format as shown in the schema section. The relevance score is a number from 1–10 based on how relevant you think the document is to the question. The relevance score can be repetitive. Don't output any additional text or explanation or metadata apart from json string. Just output the json string and strip rest every other text. Strictly remove any last comma from the nested json elements if it's present.
Don't include any documents that are not relevant to the question. There should exactly be one documents element.
Example format:
Document 1:
content of document 1
Document 2:
content of document 2
Document 3:
content of document 3
Document 4:
content of document 4
Document 5:
content of document 5
Document 6:
content of document 6
Question: user defined question

schema:
{
    "documents": {
        "document_1": "Relevance",
        "document_2": "Relevance"
    }
}

Reclassement par cross-encodeur

L’exemple suivant de l’accélérateur d’expérimentation RAG utilise le CrossEncoder fourni par Hugging Face pour charger le modèle Roberta. Il itère ensuite sur chaque segment et utilise le modèle pour calculer la similarité, en leur donnant une valeur. Nous trions les résultats et renvoyons les N meilleurs.

from sentence_transformers import CrossEncoder
...

model_name = 'cross-encoder/stsb-roberta-base'
model = CrossEncoder(model_name)

cross_scores_ques = model.predict(
    [[user_prompt, item] for item in documents],
    apply_softmax=True,
    convert_to_numpy=True,
)

top_indices_ques = cross_scores_ques.argsort()[-k:][::-1]
sub_context = []
for idx in list(top_indices_ques):
    sub_context.append(documents[idx])

Classement sémantique

Azure AI Search a une fonctionnalité propriétaire appelée classement sémantique. Cette fonctionnalité utilise des modèles de deep learning adaptés de Microsoft Bing qui promeuvent les résultats les plus sémantiquement pertinents. Lisez ce qui suit pour voir comment fonctionne le classeur sémantique.

Conseils de recherche

Prenez en considération les conseils suivants lors de la mise en œuvre de votre solution de recherche :

  • Titre, résumé, source, et le contenu brut (non nettoyé) sont de bons champs à renvoyer d’une recherche.
  • Déterminez à l’avance si une requête doit être décomposée en sous-requêtes.
  • En général, il est bon de pratiquer des requêtes sur plusieurs champs, à la fois vectorielles et textuelles. Lorsque vous recevez une requête, vous ne savez pas si la recherche vectorielle ou la recherche textuelle est meilleure. Vous ne savez pas non plus quels champs la recherche vectorielle ou la recherche par mot-clé sont les meilleurs à rechercher. Vous pouvez rechercher sur plusieurs champs, potentiellement avec plusieurs requêtes, reclasser les résultats et renvoyer les résultats avec les scores les plus élevés.
  • Les champs de mots-clés et d’entités sont de bons candidats à considérer pour le filtrage.
  • Il est bon de pratiquer l’utilisation de mots-clés avec les recherches vectorielles. Les mots-clés filtrent les résultats à un sous-ensemble plus petit. Le magasin de vecteurs fonctionne sur cet ensemble pour trouver les meilleures correspondances.

Évaluation de la recherche

Dans la phase de préparation, vous devriez avoir rassemblé des requêtes de test ainsi que des informations de documents de test. Vous pouvez utiliser les informations que vous avez recueillies dans cette phase pour évaluer vos résultats de recherche :

  • La requête : La requête d’exemple.
  • Le contexte : L’ensemble de tous les textes des documents de test qui répondent à la requête d’exemple.

Voici trois méthodes d’évaluation de la récupération bien établies que vous pouvez utiliser pour évaluer votre solution de recherche :

  • Précision à K : Le pourcentage d’éléments pertinents correctement identifiés parmi l’ensemble des résultats de recherche. Cette métrique se concentre sur la précision de vos résultats de recherche.
  • Rappel à K : Le rappel à K mesure le pourcentage d’éléments pertinents dans les K premiers par rapport au nombre total d’éléments relatifs possibles. Cette métrique se concentre sur la couverture des résultats de recherche.
  • Rang réciproque moyen / Mean Reciprocal Rank (MRR) : Le MRR mesure la moyenne des rangs réciproques de la première réponse pertinente dans vos résultats de recherche classés. Cette métrique se concentre sur l’endroit où se trouve le premier résultat pertinent dans les résultats de recherche.

Vous devez tester à la fois des exemples positifs et négatifs. Pour les exemples positifs, vous voulez que les métriques soient aussi proches de 1 que possible. Pour les exemples négatifs, où vos données ne devraient pas être en mesure de répondre aux requêtes, vous voulez que les métriques soient aussi proches de 0 que possible. Vous devez tester toutes vos requêtes de test et faire la moyenne des résultats des requêtes positives et des résultats des requêtes négatives pour comprendre comment vos résultats de recherche fonctionnent dans l’ensemble.

Étapes suivantes