What are Semantic Kernel Text Search plugins?
Semantic Kernel uses Plugins to connect existing APIs with AI. These Plugins have functions that can be used to add relevant data or examples to prompts, or to allow the AI to perform actions automatically.
To integrate Text Search with Semantic Kernel, we need to turn it into a Plugin. Once we have a Text Search plugin, we can use it to add relevant information to prompts or to retrieve information as needed. Creating a plugin from Text Search is a simple process, which we will explain below.
Tip
To run the samples shown on this page go to GettingStartedWithTextSearch/Step2_Search_For_RAG.cs.
Basic search plugin
Semantic Kernel provides a default template implementation that supports variable substitution and function calling.
By including an expression such as {{MyPlugin.Function $arg1}}
in a prompt template, the specified function i.e., MyPlugin.Function
will be invoked with the provided argument arg1
(which is resolved from KernelArguments
).
The return value from the function invocation is inserted into the prompt. This technique can be used to inject relevant information into a prompt.
The sample below shows how to create a plugin named SearchPlugin
from an instance of BingTextSearch
.
Using CreateWithSearch
creates a new plugin with a single Search
function that calls the underlying text search implementation.
The SearchPlugin
is added to the Kernel
which makes it available to be called during prompt rendering.
The prompt template includes a call to {{SearchPlugin.Search $query}}
which will invoke the SearchPlugin
to retrieve results related to the current query.
The results are then inserted into the rendered prompt before it is sent to the AI model.
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.Plugins.Web.Bing;
// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
modelId: "gpt-4o",
apiKey: "<Your OpenAI API Key>");
Kernel kernel = kernelBuilder.Build();
// Create a text search using Bing search
var textSearch = new BingTextSearch(apiKey: "<Your Bing API Key>");
// Build a text search plugin with Bing search and add to the kernel
var searchPlugin = textSearch.CreateWithSearch("SearchPlugin");
kernel.Plugins.Add(searchPlugin);
// Invoke prompt and use text search plugin to provide grounding information
var query = "What is the Semantic Kernel?";
var prompt = "{{SearchPlugin.Search $query}}. {{$query}}";
KernelArguments arguments = new() { { "query", query } };
Console.WriteLine(await kernel.InvokePromptAsync(prompt, arguments));
Search plugin with citations
The sample below repeats the pattern described in the previous section with a few notable changes:
CreateWithGetTextSearchResults
is used to create aSearchPlugin
which calls theGetTextSearchResults
method from the underlying text search implementation.- The prompt template uses Handlebars syntax. This allows the template to iterate over the search results and render the name, value and link for each result.
- The prompt includes an instruction to include citations, so the AI model will do the work of adding citations to the response.
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;
using Microsoft.SemanticKernel.Plugins.Web.Bing;
// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
modelId: "gpt-4o",
apiKey: "<Your OpenAI API Key>");
Kernel kernel = kernelBuilder.Build();
// Create a text search using Bing search
var textSearch = new BingTextSearch(apiKey: "<Your Bing API Key>");
// Build a text search plugin with Bing 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
));
Search plugin with a filter
The samples shown so far will use the top ranked web search results to provide the grounding data. To provide more reliability in the data the web search can be restricted to only return results from a specified site.
The sample below builds on the previous one to add filtering of the search results.
A TextSearchFilter
with an equality clause is used to specify that only results from the Microsoft Developer Blogs site (site == 'devblogs.microsoft.com'
) are to be included in the search results.
The sample uses KernelPluginFactory.CreateFromFunctions
to create the SearchPlugin
.
A custom description is provided for the plugin.
The ITextSearch.CreateGetTextSearchResults
extension method is used to create the KernelFunction
which invokes the text search service.
Tip
The site
filter is Bing specific. For Google web search use siteSearch
.
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.Plugins.Web.Bing;
// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
modelId: "gpt-4o",
apiKey: "<Your OpenAI API Key>");
Kernel kernel = kernelBuilder.Build();
// Create a text search using Bing search
var textSearch = new BingTextSearch(apiKey: "<Your Bing API Key>");
// Create a filter to search only the Microsoft Developer Blogs site
var filter = new TextSearchFilter().Equality("site", "devblogs.microsoft.com");
var searchOptions = new TextSearchOptions() { Filter = filter };
// Build a text search plugin with Bing search and add to the kernel
var searchPlugin = KernelPluginFactory.CreateFromFunctions(
"SearchPlugin", "Search Microsoft Developer Blogs site only",
[textSearch.CreateGetTextSearchResults(searchOptions: searchOptions)]);
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
));
Tip
Follow the link for more information on how to filter the answers that Bing returns.
Custom search plugin
In the previous sample a static site filter was applied to the search operations. What if you need this filter to be dynamic?
The next sample shows how you can perform more customization of the SearchPlugin
so that the filter value can be dynamic.
The sample uses KernelFunctionFromMethodOptions
to specify the following for the SearchPlugin
:
FunctionName
: The search function is namedGetSiteResults
because it will apply a site filter if the query includes a domain.Description
: The description describes how this specialized search function works.Parameters
: The parameters include an additional optional parameter for thesite
so the domain can be specified.
Customizing the search function is required if you want to provide multiple specialized search functions. In prompts you can use the function names to make the template more readable. If you use function calling then the model will use the function name and description to select the best search function to invoke.
When this sample is executed, the response will use techcommunity.microsoft.com as the source for relevant data.
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;
using Microsoft.SemanticKernel.Plugins.Web.Bing;
// Create a kernel with OpenAI chat completion
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
modelId: "gpt-4o",
apiKey: "<Your OpenAI API Key>");
Kernel kernel = kernelBuilder.Build();
// Create a text search using Bing search
var textSearch = new BingTextSearch(apiKey: "<Your Bing API Key>");
// Build a text search plugin with Bing search and add to the kernel
var options = new KernelFunctionFromMethodOptions()
{
FunctionName = "GetSiteResults",
Description = "Perform a search for content related to the specified query and optionally from the specified domain.",
Parameters =
[
new KernelParameterMetadata("query") { Description = "What to search for", IsRequired = true },
new KernelParameterMetadata("top") { Description = "Number of results", IsRequired = false, DefaultValue = 5 },
new KernelParameterMetadata("skip") { Description = "Number of results to skip", IsRequired = false, DefaultValue = 0 },
new KernelParameterMetadata("site") { Description = "Only return results from this domain", IsRequired = false },
],
ReturnParameter = new() { ParameterType = typeof(KernelSearchResults<string>) },
};
var searchPlugin = KernelPluginFactory.CreateFromFunctions("SearchPlugin", "Search specified site", [textSearch.CreateGetTextSearchResults(options)]);
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-GetSiteResults query)}}
{{#each this}}
Name: {{Name}}
Value: {{Value}}
Link: {{Link}}
-----------------
{{/each}}
{{/with}}
{{query}}
Only include results from techcommunity.microsoft.com.
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
));
Coming soon
More coming soon.
Coming soon
More coming soon.