Delen via


Vector Stores gebruiken met Semantic Kernel Text Search

Alle Vector Store-connectors kunnen worden gebruikt voor het zoeken naar tekst.

  1. Gebruik de Vector Store-connector om de recordverzameling op te halen die u wilt zoeken.
  2. De recordverzameling verpakken met VectorStoreTextSearch.
  3. Converteren naar een invoegtoepassing voor gebruik in RAG- en/of functie-aanroepende scenario's.

Het is zeer waarschijnlijk dat u de zoekfunctie van de invoegtoepassing wilt aanpassen, zodat de beschrijving overeenkomt met het type gegevens dat beschikbaar is in de recordverzameling. Als de recordverzameling bijvoorbeeld informatie bevat over hotels, moet de beschrijving van de zoekfunctie van de invoegtoepassing dit vermelden. Hierdoor kunt u meerdere plug-ins registreren, bijvoorbeeld één om te zoeken naar hotels, een andere voor restaurants en een andere om dingen te doen.

De abstracties van tekstzoekopdrachten bevatten een functie om een genormaliseerd zoekresultaat te retourneren, bijvoorbeeld een instantie van TextSearchResult. Dit genormaliseerde zoekresultaat bevat een waarde en eventueel een naam en koppeling. De tekstzoekopdrachten bevatten een functie om een tekenreekswaarde te retourneren, bijvoorbeeld een van de eigenschappen van het gegevensmodel wordt geretourneerd als het zoekresultaat. Voor een juiste werking van tekstzoekopdrachten moet u een manier opgeven om van het Vector Store-gegevensmodel toe te wijzen aan een exemplaar van TextSearchResult. In de volgende sectie worden de twee opties beschreven die u kunt gebruiken om deze toewijzing uit te voeren.

Tip

Als u de voorbeelden wilt uitvoeren die op deze pagina worden weergegeven, gaat u naar GettingStartedWithTextSearch/Step4_Search_With_VectorStore.cs.

De toewijzing van een Vector Store-gegevensmodel aan een TextSearchResult kan declaratief worden uitgevoerd met behulp van kenmerken.

  1. [TextSearchResultValue] - Voeg dit kenmerk toe aan de eigenschap van het gegevensmodel. Dit is de waarde van de TextSearchResult, bijvoorbeeld de tekstgegevens die door het AI-model worden gebruikt om vragen te beantwoorden.
  2. [TextSearchResultName] - Voeg dit kenmerk toe aan de eigenschap van het gegevensmodel. Dit is de naam van het TextSearchResult.
  3. [TextSearchResultLink] - Voeg dit kenmerk toe aan de eigenschap van het gegevensmodel. Dit is de koppeling naar het TextSearchResult.

In het volgende voorbeeld ziet u een gegevensmodel waarop de kenmerken van het zoekresultaat voor tekst zijn toegepast.

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; }
}

De toewijzing van een Vector Store-gegevensmodel aan een string of a TextSearchResult kan ook worden uitgevoerd door implementaties van ITextSearchStringMapper en ITextSearchResultMapper respectievelijk.

U kunt ervoor kiezen om aangepaste mappers te maken voor de volgende scenario's:

  1. Meerdere eigenschappen uit het gegevensmodel moeten samen worden gecombineerd, bijvoorbeeld als meerdere eigenschappen moeten worden gecombineerd om de waarde op te geven.
  2. Aanvullende logica is vereist om een van de eigenschappen te genereren, bijvoorbeeld als de koppelingseigenschap moet worden berekend op basis van de eigenschappen van het gegevensmodel.

In het volgende voorbeeld ziet u een gegevensmodel en twee voorbeeld-mapper-implementaties die kunnen worden gebruikt met het gegevensmodel.

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.");
    }
}

De mapper-implementaties kunnen worden opgegeven als parameters bij het maken van de VectorStoreTextSearch onderstaande:

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);

In het onderstaande voorbeeld ziet u hoe u een exemplaar maakt van het gebruik van VectorStoreTextSearch een Vector Store-recordverzameling.

Tip

Voor de volgende voorbeelden zijn exemplaren van IVectorStoreRecordCollection en ITextEmbeddingGenerationService. Raadpleeg de documentatie voor elke connector om een exemplaar te IVectorStoreRecordCollection maken. Als u een exemplaar wilt maken van ITextEmbeddingGenerationService de service die u wilt gebruiken, bijvoorbeeld Azure OpenAI, OpenAI, ... of gebruik een lokaal model ONNX, Ollama, ... en maak een exemplaar van de bijbehorende ITextEmbeddingGenerationService implementatie.

Tip

Een VectorStoreTextSearch kan ook worden samengesteld vanuit een exemplaar van IVectorizableTextSearch. In dit geval is er geen ITextEmbeddingGenerationService behoefte.

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}");
}

Een zoekinvoegtoepassing maken vanuit een vectorarchief

In het onderstaande voorbeeld ziet u hoe u een invoegtoepassing maakt met de naam SearchPlugin van een exemplaar van VectorStoreTextSearch. Met behulp van CreateWithGetTextSearchResults maakt u een nieuwe invoegtoepassing met één GetTextSearchResults functie die de onderliggende Implementatie van de Vector Store-recordverzameling aanroept. De SearchPlugin waarde wordt toegevoegd aan de Kernel weergave waardoor deze beschikbaar is om te worden aangeroepen tijdens het weergeven van prompts. De promptsjabloon bevat een aanroep {{SearchPlugin.Search $query}} waarmee de SearchPlugin resultaten worden aangeroepen die betrekking hebben op de huidige query. De resultaten worden vervolgens ingevoegd in de weergegeven prompt voordat deze naar het model wordt verzonden.

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
));

Een vectorarchief gebruiken met functie-aanroepen

In het onderstaande voorbeeld wordt ook een SearchPlugin exemplaar van VectorStoreTextSearch. Deze invoegtoepassing wordt geadverteerd naar het model voor gebruik met automatische functie-aanroepen met behulp van de FunctionChoiceBehavior instellingen voor de promptuitvoering. Wanneer u dit voorbeeld uitvoert, roept het model de zoekfunctie aan om aanvullende informatie op te halen om op de vraag te reageren. Er wordt waarschijnlijk alleen gezocht naar 'Semantische kernel' in plaats van de hele query.

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));

De zoekfunctie aanpassen

In het onderstaande voorbeeld ziet u hoe u de beschrijving kunt aanpassen van de zoekfunctie die aan de SearchPluginfunctie wordt toegevoegd. U kunt het volgende doen:

  1. Wijzig de naam van de zoekfunctie om aan te geven wat er in de gekoppelde recordverzameling staat, bijvoorbeeld dat u de functie SearchForHotels een naam wilt geven als de recordverzameling hotelgegevens bevat.
  2. Wijzig de beschrijving van de functie. Een nauwkeurige functiebeschrijving helpt het AI-model om de beste functie te selecteren die moet worden aangeroepen. Dit is vooral belangrijk als u meerdere zoekfuncties toevoegt.
  3. Voeg een extra parameter toe aan de zoekfunctie. Als de recordverzameling hotelgegevens bevat en een van de eigenschappen de plaatsnaam is, kunt u een eigenschap toevoegen aan de zoekfunctie om de plaats op te geven. Er wordt automatisch een filter toegevoegd en de zoekresultaten worden gefilterd op plaats.

Tip

In het onderstaande voorbeeld wordt de standaard implementatie van zoeken gebruikt. U kunt ervoor kiezen om uw eigen implementatie te bieden die de onderliggende Vector Store-recordverzameling aanroept met extra opties om uw zoekopdrachten af te stemmen.

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));

Binnenkort beschikbaar

Binnenkort meer beschikbaar.

Binnenkort beschikbaar

Binnenkort meer beschikbaar.

Volgende stappen