Uso de almacenes de vectores con búsqueda de texto de kernel semántica
Todos los conectores del almacén de vectores se pueden usar para la búsqueda de texto.
- Use el conector de almacén de vectores para recuperar la colección de registros que desea buscar.
- Ajuste la colección de registros con
VectorStoreTextSearch
. - Convierta en un complemento para su uso en escenarios de llamadas de funciones o RAG.
Es muy probable que quiera personalizar la función de búsqueda del complemento para que su descripción refleje el tipo de datos disponibles en la colección de registros. Por ejemplo, si la colección de registros contiene información sobre hoteles, la descripción de la función de búsqueda del complemento debe mencionar esto. Esto le permitirá registrar varios complementos, por ejemplo, uno para buscar hoteles, otro para restaurantes y otro para hacer cosas.
Las abstracciones de búsqueda de texto incluyen una función para devolver un resultado de búsqueda normalizado, es decir, una instancia de TextSearchResult
.
Este resultado de búsqueda normalizado contiene un valor y, opcionalmente, un nombre y un vínculo.
Las abstracciones de búsqueda de texto incluyen una función para devolver un valor de cadena, por ejemplo, una de las propiedades del modelo de datos se devolverá como resultado de la búsqueda.
Para que la búsqueda de texto funcione correctamente, debe proporcionar una manera de asignar desde el modelo de datos del almacén de vectores a una instancia de TextSearchResult
.
En la sección siguiente se describen las dos opciones que puede usar para realizar esta asignación.
Sugerencia
Para ejecutar los ejemplos que se muestran en esta página, vaya a GettingStartedWithTextSearch/Step4_Search_With_VectorStore.cs.
Uso de un modelo de almacén de vectores con búsqueda de texto
La asignación de un modelo de datos del almacén de vectores a una TextSearchResult
se puede realizar mediante declaración mediante atributos.
[TextSearchResultValue]
: agregue este atributo a la propiedad del modelo de datos, que será el valor deTextSearchResult
, por ejemplo, los datos textuales que usará el modelo de IA para responder a preguntas.[TextSearchResultName]
: agregue este atributo a la propiedad del modelo de datos, que será el nombre de .TextSearchResult
[TextSearchResultLink]
: agregue este atributo a la propiedad del modelo de datos que será el vínculo a .TextSearchResult
En el ejemplo siguiente se muestra un modelo de datos que tiene aplicados los atributos de resultado de búsqueda de texto.
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; }
}
La asignación de un modelo de datos del almacén de vectores a o string
TextSearchResult
también se puede realizar proporcionando implementaciones de ITextSearchStringMapper
y ITextSearchResultMapper
respectivamente.
Puede decidir crear asignadores personalizados para los escenarios siguientes:
- Es necesario combinar varias propiedades del modelo de datos, por ejemplo, si es necesario combinar varias propiedades para proporcionar el valor.
- Se requiere lógica adicional para generar una de las propiedades, por ejemplo, si la propiedad de vínculo debe calcularse a partir de las propiedades del modelo de datos.
En el ejemplo siguiente se muestra un modelo de datos y dos implementaciones del asignador de ejemplo que se pueden usar con el modelo de datos.
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.");
}
}
Las implementaciones del asignador se pueden proporcionar como parámetros al crear como VectorStoreTextSearch
se muestra a continuación:
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);
Uso de un almacén de vectores con búsqueda de texto
En el ejemplo siguiente se muestra cómo crear una instancia de mediante una colección de VectorStoreTextSearch
registros del almacén de vectores.
Sugerencia
Los ejemplos siguientes requieren instancias de IVectorStoreRecordCollection
y ITextEmbeddingGenerationService
.
Para crear una instancia de IVectorStoreRecordCollection
, consulte la documentación de cada conector.
Para crear una instancia de ITextEmbeddingGenerationService
seleccione el servicio que desea usar, por ejemplo, Azure OpenAI, OpenAI, ... o usar un modelo local ONNX, Ollama, ... y crear una instancia de la implementación correspondiente ITextEmbeddingGenerationService
.
Sugerencia
También VectorStoreTextSearch
se puede construir a partir de una instancia de IVectorizableTextSearch
. En este caso no ITextEmbeddingGenerationService
es necesario.
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}");
}
Creación de un complemento de búsqueda desde un almacén de vectores
En el ejemplo siguiente se muestra cómo crear un complemento denominado SearchPlugin
a partir de una instancia de VectorStoreTextSearch
.
El uso CreateWithGetTextSearchResults
de crea un nuevo complemento con una sola GetTextSearchResults
función que llama a la implementación de búsqueda de la colección de registros del almacén de vectores subyacente.
SearchPlugin
se agrega a , Kernel
que hace que esté disponible para que se llame durante la representación del símbolo del sistema.
La plantilla de solicitud incluye una llamada a la {{SearchPlugin.Search $query}}
SearchPlugin
que invocará para recuperar los resultados relacionados con la consulta actual.
A continuación, los resultados se insertan en el símbolo del sistema representado antes de enviarlo al modelo.
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
));
Uso de un almacén de vectores con llamadas de función
En el ejemplo siguiente también se crea a SearchPlugin
partir de una instancia de VectorStoreTextSearch
.
Este complemento se anunciará al modelo para su uso con la llamada automática a funciones mediante en FunctionChoiceBehavior
la configuración de ejecución del símbolo del sistema.
Al ejecutar este ejemplo, el modelo invocará la función de búsqueda para recuperar información adicional para responder a la pregunta.
Es probable que solo busque "Kernel semántico" en lugar de toda la consulta.
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));
Personalización de la función de búsqueda
En el ejemplo siguiente se muestra cómo personalizar la descripción de la función de búsqueda que se agrega a .SearchPlugin
Algunas cosas que puede que quiera hacer son:
- Cambie el nombre de la función de búsqueda para reflejar lo que se encuentra en la colección de registros asociada, por ejemplo, es posible que desee asignar un nombre a la función
SearchForHotels
si la colección de registros contiene información del hotel. - Cambie la descripción de la función. Una descripción precisa de la función ayuda al modelo de IA a seleccionar la mejor función a la que llamar. Esto es especialmente importante si va a agregar varias funciones de búsqueda.
- Agregue un parámetro adicional a la función de búsqueda. Si la colección de registros contiene información del hotel y una de las propiedades es el nombre de la ciudad, podría agregar una propiedad a la función de búsqueda para especificar la ciudad. Se agregará automáticamente un filtro y filtrará los resultados de búsqueda por ciudad.
Sugerencia
En el ejemplo siguiente se usa la implementación predeterminada de la búsqueda. Puede optar por proporcionar su propia implementación que llama a la colección de registros del Almacén de vectores subyacente con opciones adicionales para ajustar las búsquedas.
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));
Próximamente
Más próximamente.
Próximamente
Más próximamente.