aigc
如何将矢量存储与语义内核文本搜索配合使用
/n所有向量存储 连接器 都可用于文本搜索。
- 使用 Vector Store 连接器检索要搜索的记录集合。
- 使用
VectorStoreTextSearch
. 包装记录集合。 - 转换为插件,以便在 RAG 和/或函数调用方案中使用。
你很可能要自定义插件搜索函数,以便其说明反映记录集合中可用的数据类型。 例如,如果记录集合包含有关酒店的信息,插件搜索函数说明应提及此信息。 这将允许注册多个插件,例如,一个用于搜索酒店,另一个用于餐馆,另一个插件用于执行操作。
文本搜索抽象包括用于返回规范化搜索结果的函数,即返回规范TextSearchResult
化搜索结果的一个实例。
此规范化搜索结果包含一个值,还可以选择一个名称和链接。
文本搜索抽象包括一个函数来返回字符串值,例如,其中一个数据模型属性将作为搜索结果返回。
若要使文本搜索正常工作,需要提供一种从矢量存储数据模型映射到实例的方法 TextSearchResult
。
下一部分介绍可用于执行此映射的两个选项。
提示
若要运行此页上显示的示例,请转到 GettingStartedWithTextSearch/Step4_Search_With_VectorStore.cs。
将矢量存储模型与文本搜索配合使用
可以使用属性以声明方式完成从向量存储数据模型到 a TextSearchResult
的映射。
[TextSearchResultValue]
- 将此属性添加到数据模型的属性(即 AI 模型用于回答问题的文本数据)的值TextSearchResult
。[TextSearchResultName]
- 将此属性添加到数据模型的属性,该属性将是该TextSearchResult
数据模型的名称。[TextSearchResultLink]
- 将此属性添加到数据模型的属性,该属性将成为指向该TextSearchResult
数据模型的链接。
以下示例显示了应用了文本搜索结果属性的数据模型。
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; }
}
也可以通过提供和ITextSearchResultMapper
分别实现ITextSearchStringMapper
从向量存储数据模型到 a string
或 a TextSearchResult
的映射。
可以决定为以下方案创建自定义映射器:
- 需要将数据模型中的多个属性组合在一起,例如,如果需要组合多个属性来提供值。
- 如果需要从数据模型属性计算链接属性,则需要其他逻辑来生成其中一个属性,例如。
以下示例显示了一个数据模型和两个可用于数据模型的示例映射器实现。
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.");
}
}
创建 VectorStoreTextSearch
映射器实现时可以作为参数提供,如下所示:
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);
将矢量存储与文本搜索配合使用
下面的示例演示如何创建使用 Vector Store 记录集合的 VectorStoreTextSearch
实例。
提示
以下示例需要实例 IVectorStoreRecordCollection
和 ITextEmbeddingGenerationService
。
若要为每个连接器创建参考文档的实例IVectorStoreRecordCollection
。
若要创建想要使用的服务的实例 ITextEmbeddingGenerationService
,例如 Azure OpenAI、OpenAI...或使用本地模型 ONNX、Ollama、 ...并创建相应 ITextEmbeddingGenerationService
实现的实例。
提示
还可以从 . 的IVectorizableTextSearch
实例构造 AVectorStoreTextSearch
。 在这种情况下,不需要 ITextEmbeddingGenerationService
。
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}");
}
从向量存储创建搜索插件
下面的示例演示如何创建从实例命名 SearchPlugin
的 VectorStoreTextSearch
插件。
使用 CreateWithGetTextSearchResults
创建一个新插件和一个 GetTextSearchResults
调用基础 Vector Store 记录集合搜索实现的函数。
将 SearchPlugin
添加到 Kernel
允许在提示呈现期间调用它。
提示模板包括调用调用以SearchPlugin
检索与当前查询相关的结果的调用{{SearchPlugin.Search $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
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
));
将向量存储与函数调用配合使用
下面的示例还从 实例VectorStoreTextSearch
创建一个 SearchPlugin
。
此插件将播发到模型,以便在提示执行设置中使用 FunctionChoiceBehavior
自动函数调用。
运行此示例时,模型将调用搜索函数来检索其他信息以响应问题。
它可能只是搜索“语义内核”,而不是整个查询。
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));
自定义搜索函数
下面的示例如何自定义添加到其中 SearchPlugin
搜索函数的说明。
你可能想要执行的操作包括:
- 更改搜索函数的名称以反映关联记录集合中的内容,例如,如果记录集合包含酒店信息,可能需要为函数
SearchForHotels
命名。 - 更改函数的说明。 准确的函数说明可帮助 AI 模型选择要调用的最佳函数。 如果要添加多个搜索函数,这一点尤其重要。
- 向搜索函数添加其他参数。 如果记录集合包含酒店信息,并且其中一个属性是城市名称,则可以将属性添加到搜索函数以指定城市。 将自动添加筛选器,它将按城市筛选搜索结果。
提示
下面的示例使用搜索的默认实现。 可以选择提供自己的实现,该实现调用基础矢量存储记录集合,并提供其他选项来微调搜索。
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));
即将推出
即将推出更多内容。
即将推出
即将推出更多内容。