Partager via


Comment utiliser des magasins de vecteurs avec la recherche de texte du noyau sémantique

Tous les connecteurs du Magasin de vecteurs peuvent être utilisés pour la recherche de texte.

  1. Utilisez le connecteur Vector Store pour récupérer la collection d’enregistrements que vous souhaitez rechercher.
  2. Encapsulez la collection d’enregistrements avec VectorStoreTextSearch.
  3. Convertissez en plug-in pour une utilisation dans les scénarios d’appel de fonctions et/ou RAG.

Il est très probable que vous souhaitiez personnaliser la fonction de recherche de plug-in afin que sa description reflète le type de données disponible dans la collection d’enregistrements. Par exemple, si la collection d’enregistrements contient des informations sur les hôtels, la description de la fonction de recherche de plug-in doit mentionner ceci. Cela vous permettra d’inscrire plusieurs plug-ins, par exemple, un pour rechercher des hôtels, un autre pour les restaurants et une autre pour les choses à faire.

Les abstractions de recherche de texte incluent une fonction pour retourner un résultat de recherche normalisé, c’est-à-dire une instance de TextSearchResult. Ce résultat de recherche normalisé contient une valeur et éventuellement un nom et un lien. Les abstractions de recherche de texte incluent une fonction pour retourner une valeur de chaîne, par exemple, l’une des propriétés du modèle de données est retournée en tant que résultat de recherche. Pour que la recherche de texte fonctionne correctement, vous devez fournir un moyen de mapper à partir du modèle de données du Magasin de vecteurs à une instance de TextSearchResult. La section suivante décrit les deux options que vous pouvez utiliser pour effectuer ce mappage.

Conseil

Pour exécuter les exemples affichés sur cette page, accédez à GettingStartedWithTextSearch/Step4_Search_With_VectorStore.cs.

Le mappage d’un modèle de données Vector Store à un TextSearchResult objet peut être effectué de manière déclarative à l’aide d’attributs.

  1. [TextSearchResultValue] - Ajoutez cet attribut à la propriété du modèle de données qui sera la valeur du TextSearchResult, par exemple les données textuelles utilisées par le modèle IA pour répondre aux questions.
  2. [TextSearchResultName] - Ajoutez cet attribut à la propriété du modèle de données qui sera le nom du TextSearchResult.
  3. [TextSearchResultLink] - Ajoutez cet attribut à la propriété du modèle de données qui sera le lien vers le TextSearchResult.

L’exemple suivant montre un modèle de données dont les attributs de résultat de recherche de texte sont appliqués.

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Data;

public sealed class DataModel
{
    [VectorStoreRecordKey]
    [TextSearchResultName]
    public Guid Key { get; init; }

    [VectorStoreRecordData]
    [TextSearchResultValue]
    public string Text { get; init; }

    [VectorStoreRecordData]
    [TextSearchResultLink]
    public string Link { get; init; }

    [VectorStoreRecordData(IsFilterable = true)]
    public required string Tag { get; init; }

    [VectorStoreRecordVector(1536)]
    public ReadOnlyMemory<float> Embedding { get; init; }
}

Le mappage d’un modèle de données vector store à un ou à un string TextSearchResult peut également être effectué en fournissant des implémentations respectives ITextSearchStringMapper ITextSearchResultMapper et respectivement.

Vous pouvez décider de créer des mappeurs personnalisés pour les scénarios suivants :

  1. Plusieurs propriétés du modèle de données doivent être combinées, par exemple, si plusieurs propriétés doivent être combinées pour fournir la valeur.
  2. Une logique supplémentaire est nécessaire pour générer l’une des propriétés, par exemple, si la propriété de lien doit être calculée à partir des propriétés du modèle de données.

L’exemple suivant montre un modèle de données et deux exemples d’implémentations de mappeur qui peuvent être utilisées avec le modèle de données.

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Data;

protected sealed class DataModel
{
    [VectorStoreRecordKey]
    public Guid Key { get; init; }

    [VectorStoreRecordData]
    public required string Text { get; init; }

    [VectorStoreRecordData]
    public required string Link { get; init; }

    [VectorStoreRecordData(IsFilterable = true)]
    public required string Tag { get; init; }

    [VectorStoreRecordVector(1536)]
    public ReadOnlyMemory<float> Embedding { get; init; }
}

/// <summary>
/// String mapper which converts a DataModel to a string.
/// </summary>
protected sealed class DataModelTextSearchStringMapper : ITextSearchStringMapper
{
    /// <inheritdoc />
    public string MapFromResultToString(object result)
    {
        if (result is DataModel dataModel)
        {
            return dataModel.Text;
        }
        throw new ArgumentException("Invalid result type.");
    }
}

/// <summary>
/// Result mapper which converts a DataModel to a TextSearchResult.
/// </summary>
protected sealed class DataModelTextSearchResultMapper : ITextSearchResultMapper
{
    /// <inheritdoc />
    public TextSearchResult MapFromResultToTextSearchResult(object result)
    {
        if (result is DataModel dataModel)
        {
            return new TextSearchResult(value: dataModel.Text) { Name = dataModel.Key.ToString(), Link = dataModel.Link };
        }
        throw new ArgumentException("Invalid result type.");
    }
}

Les implémentations du mappeur peuvent être fournies en tant que paramètres lors de la création de l’exemple VectorStoreTextSearch ci-dessous :

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Data;

// Create custom mapper to map a <see cref="DataModel"/> to a <see cref="string"/>
var stringMapper = new DataModelTextSearchStringMapper();

// Create custom mapper to map a <see cref="DataModel"/> to a <see cref="TextSearchResult"/>
var resultMapper = new DataModelTextSearchResultMapper();

// Add code to create instances of IVectorStoreRecordCollection and ITextEmbeddingGenerationService 

// Create a text search instance using the vector store record collection.
var result = new VectorStoreTextSearch<DataModel>(vectorStoreRecordCollection, textEmbeddingGeneration, stringMapper, resultMapper);

L’exemple ci-dessous montre comment créer une instance d’utilisation d’une collection d’enregistrements VectorStoreTextSearch Vector Store.

Conseil

Les exemples suivants nécessitent des instances de IVectorStoreRecordCollection et ITextEmbeddingGenerationService. Pour créer une instance de IVectorStoreRecordCollection référence à la documentation de chaque connecteur. Pour créer une instance de ITextEmbeddingGenerationService sélection du service que vous souhaitez utiliser, par exemple, Azure OpenAI, OpenAI, ... ou utiliser un modèle local ONNX, Ollama, ... et créez une instance de l’implémentation correspondante ITextEmbeddingGenerationService .

Conseil

Un VectorStoreTextSearch peut également être construit à partir d’une instance de IVectorizableTextSearch. Dans ce cas, il n’est pas ITextEmbeddingGenerationService nécessaire.

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

// Add code to create instances of IVectorStoreRecordCollection and ITextEmbeddingGenerationService 

// Create a text search instance using the vector store record collection.
var textSearch = new VectorStoreTextSearch<DataModel>(vectorStoreRecordCollection, textEmbeddingGeneration);

// Search and return results as TextSearchResult items
var query = "What is the Semantic Kernel?";
KernelSearchResults<TextSearchResult> textResults = await textSearch.GetTextSearchResultsAsync(query, new() { Top = 2, Skip = 0 });
Console.WriteLine("\n--- Text Search Results ---\n");
await foreach (TextSearchResult result in textResults.Results)
{
    Console.WriteLine($"Name:  {result.Name}");
    Console.WriteLine($"Value: {result.Value}");
    Console.WriteLine($"Link:  {result.Link}");
}

Création d’un plug-in de recherche à partir d’un magasin vectoriel

L’exemple ci-dessous montre comment créer un plug-in nommé SearchPlugin à partir d’une instance de VectorStoreTextSearch. L’utilisation CreateWithGetTextSearchResults crée un plug-in avec une fonction unique GetTextSearchResults qui appelle l’implémentation de recherche de collection d’enregistrements Vector Store sous-jacente. Il SearchPlugin est ajouté à celui Kernel qui le rend disponible lors du rendu d’invite. Le modèle d’invite inclut un appel auquel {{SearchPlugin.Search $query}} l’appel appelle les résultats pour récupérer les SearchPlugin résultats liés à la requête actuelle. Les résultats sont ensuite insérés dans l’invite rendue avant d’être envoyés au modèle.

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
        modelId: TestConfiguration.OpenAI.ChatModelId,
        apiKey: TestConfiguration.OpenAI.ApiKey);
Kernel kernel = kernelBuilder.Build();

// Add code to create instances of IVectorStoreRecordCollection and ITextEmbeddingGenerationService

// Create a text search instance using the vector store record collection.
var textSearch = new VectorStoreTextSearch<DataModel>(vectorStoreRecordCollection, textEmbeddingGeneration);

// Build a text search plugin with vector store search and add to the kernel
var searchPlugin = textSearch.CreateWithGetTextSearchResults("SearchPlugin");
kernel.Plugins.Add(searchPlugin);

// Invoke prompt and use text search plugin to provide grounding information
var query = "What is the Semantic Kernel?";
string promptTemplate = """
    {{#with (SearchPlugin-GetTextSearchResults query)}}  
        {{#each this}}  
        Name: {{Name}}
        Value: {{Value}}
        Link: {{Link}}
        -----------------
        {{/each}}  
    {{/with}}  

    {{query}}

    Include citations to the relevant information where it is referenced in the response.
    """;
KernelArguments arguments = new() { { "query", query } };
HandlebarsPromptTemplateFactory promptTemplateFactory = new();
Console.WriteLine(await kernel.InvokePromptAsync(
    promptTemplate,
    arguments,
    templateFormat: HandlebarsPromptTemplateFactory.HandlebarsTemplateFormat,
    promptTemplateFactory: promptTemplateFactory
));

Utilisation d’un magasin de vecteurs avec appel de fonction

L’exemple ci-dessous crée également une SearchPlugin instance de VectorStoreTextSearch. Ce plug-in sera publié sur le modèle à utiliser avec l’appel automatique de fonction à l’aide des FunctionChoiceBehavior paramètres d’exécution d’invite. Lorsque vous exécutez cet exemple, le modèle appelle la fonction de recherche pour récupérer des informations supplémentaires pour répondre à la question. Il va probablement simplement rechercher « Noyau sémantique » plutôt que la requête entière.

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
        modelId: TestConfiguration.OpenAI.ChatModelId,
        apiKey: TestConfiguration.OpenAI.ApiKey);
Kernel kernel = kernelBuilder.Build();

// Add code to create instances of IVectorStoreRecordCollection and ITextEmbeddingGenerationService

// Create a text search instance using the vector store record collection.
var textSearch = new VectorStoreTextSearch<DataModel>(vectorStoreRecordCollection, textEmbeddingGeneration);

// Build a text search plugin with vector store search and add to the kernel
var searchPlugin = textSearch.CreateWithGetTextSearchResults("SearchPlugin");
kernel.Plugins.Add(searchPlugin);

// Invoke prompt and use text search plugin to provide grounding information
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() };
KernelArguments arguments = new(settings);
Console.WriteLine(await kernel.InvokePromptAsync("What is the Semantic Kernel?", arguments));

Personnalisation de la fonction de recherche

L’exemple ci-dessous montre comment personnaliser la description de la fonction de recherche ajoutée au SearchPlugin. Voici quelques éléments que vous souhaiterez peut-être effectuer :

  1. Modifiez le nom de la fonction de recherche pour refléter ce qui se trouve dans la collection d’enregistrements associée, par exemple, vous pouvez nommer la fonction SearchForHotels si la collection d’enregistrements contient des informations sur l’hôtel.
  2. Modifiez la description de la fonction. Une description précise de la fonction aide le modèle IA à sélectionner la meilleure fonction à appeler. Cela est particulièrement important si vous ajoutez plusieurs fonctions de recherche.
  3. Ajoutez un paramètre supplémentaire à la fonction de recherche. Si la collection d’enregistrements contient des informations sur l’hôtel et que l’une des propriétés est le nom de la ville, vous pouvez ajouter une propriété à la fonction de recherche pour spécifier la ville. Un filtre sera automatiquement ajouté et filtrera les résultats de recherche par ville.

Conseil

L’exemple ci-dessous utilise l’implémentation par défaut de la recherche. Vous pouvez choisir de fournir votre propre implémentation qui appelle la collection d’enregistrements Vector Store sous-jacente avec des options supplémentaires pour affiner vos recherches.

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
        modelId: TestConfiguration.OpenAI.ChatModelId,
        apiKey: TestConfiguration.OpenAI.ApiKey);
Kernel kernel = kernelBuilder.Build();

// Add code to create instances of IVectorStoreRecordCollection and ITextEmbeddingGenerationService

// Create a text search instance using the vector store record collection.
var textSearch = new VectorStoreTextSearch<DataModel>(vectorStoreRecordCollection, textEmbeddingGeneration);

// Create options to describe the function I want to register.
var options = new KernelFunctionFromMethodOptions()
{
    FunctionName = "Search",
    Description = "Perform a search for content related to the specified query from a record collection.",
    Parameters =
    [
        new KernelParameterMetadata("query") { Description = "What to search for", IsRequired = true },
        new KernelParameterMetadata("top") { Description = "Number of results", IsRequired = false, DefaultValue = 2 },
        new KernelParameterMetadata("skip") { Description = "Number of results to skip", IsRequired = false, DefaultValue = 0 },
    ],
    ReturnParameter = new() { ParameterType = typeof(KernelSearchResults<string>) },
};

// Build a text search plugin with vector store search and add to the kernel
var searchPlugin = textSearch.CreateWithGetTextSearchResults("SearchPlugin", "Search a record collection", [textSearch.CreateSearch(options)]);
kernel.Plugins.Add(searchPlugin);

// Invoke prompt and use text search plugin to provide grounding information
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() };
KernelArguments arguments = new(settings);
Console.WriteLine(await kernel.InvokePromptAsync("What is the Semantic Kernel?", arguments));

Bientôt disponible

Plus bientôt.

Bientôt disponible

Plus bientôt.

Étapes suivantes