Verwenden von Vektorspeichern mit semantischer Kerneltextsuche
Alle Vector Store-Connectors können für die Textsuche verwendet werden.
- Verwenden Sie den Vector Store-Connector, um die Datensatzsammlung abzurufen, die Sie durchsuchen möchten.
- Umschließen der Datensatzauflistung mit
VectorStoreTextSearch
. - Konvertieren Sie in ein Plug-In für die Verwendung in RAG- und/oder Funktionsaufrufszenarien.
Es ist sehr wahrscheinlich, dass Sie die Plug-In-Suchfunktion so anpassen möchten, dass die Beschreibung den Typ der in der Datensatzsammlung verfügbaren Daten widerspiegelt. Wenn die Datensatzsammlung beispielsweise Informationen zu Hotels enthält, sollte die Beschreibung der Plug-In-Suchfunktion dies erwähnen. Auf diese Weise können Sie mehrere Plug-Ins registrieren, z. B. eine, um nach Hotels zu suchen, eine für Restaurants und eine andere für Aktivitäten.
Die Textsuchabstraktionen enthalten eine Funktion, um ein normalisiertes Suchergebnis zurückzugeben, d. h. eine Instanz von TextSearchResult
.
Dieses normalisierte Suchergebnis enthält einen Wert und optional einen Namen und einen Link.
Die Textsuchabstraktionen enthalten eine Funktion zum Zurückgeben eines Zeichenfolgenwerts, z. B. eine der Datenmodelleigenschaften, wird als Suchergebnis zurückgegeben.
Damit die Textsuche ordnungsgemäß funktioniert, müssen Sie eine Möglichkeit zum Zuordnen des Vector Store-Datenmodells zu einer Instanz von TextSearchResult
.
Im nächsten Abschnitt werden die beiden Optionen beschrieben, die Sie zum Ausführen dieser Zuordnung verwenden können.
Tipp
Um die auf dieser Seite gezeigten Beispiele auszuführen, wechseln Sie zu GettingStartedWithTextSearch/Step4_Search_With_VectorStore.cs.
Verwenden eines Vektorspeichermodells mit textsuche
Die Zuordnung von einem Vector Store-Datenmodell zu einem TextSearchResult
kann deklarativ mithilfe von Attributen erfolgen.
[TextSearchResultValue]
- Fügen Sie dieses Attribut der Eigenschaft des Datenmodells hinzu, das den Wert derTextSearchResult
Daten darstellt, z. B. die Textdaten, die das KI-Modell verwendet, um Fragen zu beantworten.[TextSearchResultName]
- Fügen Sie dieses Attribut der Eigenschaft des Datenmodells hinzu, das der Name desTextSearchResult
.[TextSearchResultLink]
- Fügen Sie dieses Attribut der Eigenschaft des Datenmodells hinzu, das die Verknüpfung mit demTextSearchResult
.
Das folgende Beispiel zeigt ein Datenmodell, auf das die Textsuchergebnisattribute angewendet wurden.
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; }
}
Die Zuordnung von einem Vector Store-Datenmodell zu einem string
oder einem TextSearchResult
kann auch durch die Bereitstellung von ITextSearchStringMapper
Implementierungen bzw ITextSearchResultMapper
. entsprechenden Erfolgen erfolgen.
Sie können benutzerdefinierte Mapper für die folgenden Szenarien erstellen:
- Mehrere Eigenschaften aus dem Datenmodell müssen kombiniert werden, z. B. wenn mehrere Eigenschaften kombiniert werden müssen, um den Wert bereitzustellen.
- Zusätzliche Logik ist erforderlich, um eine der Eigenschaften zu generieren, z. B. wenn die Verknüpfungseigenschaft aus den Datenmodelleigenschaften berechnet werden muss.
Das folgende Beispiel zeigt ein Datenmodell und zwei Beispielzuordnungsimplementierungen, die mit dem Datenmodell verwendet werden können.
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.");
}
}
Die Mapperimplementierungen können beim Erstellen der VectorStoreTextSearch
folgenden Abbildung als Parameter bereitgestellt werden:
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);
Verwenden eines Vektorspeichers mit der Textsuche
Das folgende Beispiel zeigt, wie Sie eine Instanz der VectorStoreTextSearch
Verwendung einer Vector Store-Datensatzsammlung erstellen.
Tipp
In den folgenden Beispielen sind Instanzen von IVectorStoreRecordCollection
und ITextEmbeddingGenerationService
.
So erstellen Sie eine Instanz von IVectorStoreRecordCollection
Verweisen auf die Dokumentation für jeden Connector.
Zum Erstellen einer Instanz der Auswahl des ITextEmbeddingGenerationService
Diensts, den Sie verwenden möchten, z. B. Azure OpenAI, OpenAI, ... oder verwenden Sie ein lokales Modell ONNX, Ollama, ... und erstellen Sie eine Instanz der entsprechenden ITextEmbeddingGenerationService
Implementierung.
Tipp
A VectorStoreTextSearch
kann auch aus einer Instanz von IVectorizableTextSearch
. In diesem Fall ist keine ITextEmbeddingGenerationService
erforderlich.
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}");
}
Erstellen eines Such-Plug-Ins aus einem Vektorspeicher
Das folgende Beispiel zeigt, wie Sie ein Plug-In SearchPlugin
erstellen, das aus einer Instanz von VectorStoreTextSearch
.
Die Verwendung CreateWithGetTextSearchResults
erstellt ein neues Plug-In mit einer einzigen GetTextSearchResults
Funktion, die die zugrunde liegende Suchimplementierung der Vector Store-Datensatzsammlung aufruft.
Der SearchPlugin
Wird hinzugefügt, der es während des Kernel
Eingabeaufforderungsrenderings zur Verfügung stellt.
Die Eingabeaufforderungsvorlage enthält einen Aufruf, mit {{SearchPlugin.Search $query}}
dem die SearchPlugin
Ergebnisse im Zusammenhang mit der aktuellen Abfrage abgerufen werden.
Die Ergebnisse werden dann in die gerenderte Eingabeaufforderung eingefügt, bevor sie an das Modell gesendet wird.
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
));
Verwenden eines Vektorspeichers mit Funktionsaufrufen
Das folgende Beispiel erstellt auch eine SearchPlugin
aus einer Instanz von VectorStoreTextSearch
.
Dieses Plug-In wird dem Modell für die Verwendung mit automatischen Funktionsaufrufen unter Verwendung der Einstellungen für die FunctionChoiceBehavior
Eingabeaufforderungsausführung angekündigt.
Wenn Sie dieses Beispiel ausführen, ruft das Modell die Suchfunktion auf, um zusätzliche Informationen abzurufen, um auf die Frage zu antworten.
Es wird wahrscheinlich nur nach "Semantic Kernel" und nicht nach der gesamten Abfrage suchen.
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));
Anpassen der Suchfunktion
Im folgenden Beispiel wird beschrieben, wie Sie die Beschreibung der Suchfunktion anpassen, die der SearchPlugin
Suchfunktion hinzugefügt wird.
Einige Dinge, die Sie möglicherweise tun möchten, sind:
- Ändern Sie den Namen der Suchfunktion so, dass sie angibt, was in der zugeordneten Datensatzsammlung enthalten ist, z. B. möchten Sie die Funktion
SearchForHotels
benennen, wenn die Datensatzsammlung Hotelinformationen enthält. - Ändern Sie die Beschreibung der Funktion. Eine genaue Funktionsbeschreibung hilft dem KI-Modell, die beste Funktion auszuwählen, die aufgerufen werden soll. Dies ist besonders wichtig, wenn Sie mehrere Suchfunktionen hinzufügen.
- Fügen Sie der Suchfunktion einen zusätzlichen Parameter hinzu. Wenn die Datensatzsammlung Hotelinformationen enthält und eine der Eigenschaften der Ort ist, können Sie der Suchfunktion eine Eigenschaft hinzufügen, um die Stadt anzugeben. Ein Filter wird automatisch hinzugefügt und filtert Suchergebnisse nach Ort.
Tipp
Im folgenden Beispiel wird die Standardimplementierung der Suche verwendet. Sie können ihre eigene Implementierung bereitstellen, die die zugrunde liegende Vector Store-Datensatzsammlung mit zusätzlichen Optionen aufruft, um Ihre Suchvorgänge zu optimieren.
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));
In Kürze verfügbar
Mehr in Kürze verfügbar.
In Kürze verfügbar
Mehr in Kürze verfügbar.