{"id":2310,"date":"2024-03-22T10:51:55","date_gmt":"2024-03-22T17:51:55","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=2310"},"modified":"2024-03-27T08:31:40","modified_gmt":"2024-03-27T15:31:40","slug":"using-semantic-kernel-with-dependency-injection","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/using-semantic-kernel-with-dependency-injection\/","title":{"rendered":"Using Semantic Kernel with Dependency Injection"},"content":{"rendered":"<p><span data-contrast=\"auto\">Semantic Kernel fully supports <\/span><a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/core\/extensions\/dependency-injection\"><span data-contrast=\"none\">dependency injection<\/span><\/a><span data-contrast=\"auto\">. After receiving many questions from the community as to how to best use dependency injection with Semantic Kernel, the team created an app to illustrate some effective patterns.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:0,&quot;335559740&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Dependency injection is a technique in which an object receives other objects that it requires rather than creating them internally. This leads to greater separation of concerns and classes that are loosely coupled to the objects on which they depend. In turn, this leads to software that is easier to test and maintain.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:0,&quot;335559740&quot;:240}\">\u00a0<\/span><\/p>\n<p aria-level=\"1\"><strong>The Demo App\u00a0<\/strong><\/p>\n<p><span data-contrast=\"auto\">The code for the application demonstrating usage of dependency injection with Semantic Kernel is found in the library\u2019s <\/span><a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/tree\/main\/dotnet\/samples\/HomeAutomation\"><span data-contrast=\"none\">GitHub repository<\/span><\/a><span data-contrast=\"auto\">.\u00a0 The application is called HomeAutomation and simulates the automation of home devices such as lights.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:0,&quot;335559740&quot;:240}\">\u00a0<\/span><\/p>\n<p><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:0,&quot;335559740&quot;:240}\"> <a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2024\/03\/HomeAutomation-Image-1.png\"><img decoding=\"async\" class=\"alignnone wp-image-2312 size-full\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2024\/03\/HomeAutomation-Image-1.png\" alt=\"Image HomeAutomation Image 1\" width=\"277\" height=\"778\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2024\/03\/HomeAutomation-Image-1.png 277w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2024\/03\/HomeAutomation-Image-1-107x300.png 107w\" sizes=\"(max-width: 277px) 100vw, 277px\" \/><\/a><\/span><\/p>\n<p>To successfully run the application, you must provide the details of the model you intend to use. For example, if you want to use the gpt-4 model in Azure OpenAI, you will need to enter the following .Net secrets to use the application:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">cd dotnet\/samples\/HouseAutomation\r\ndotnet user-secrets init\r\ndotnet user-secrets set \"AzureOpenAI:ChatDeploymentName\" \"gpt-4\"\r\ndotnet user-secrets set \"AzureOpenAI:Endpoint\" \"https:\/\/YOUR_ENDPOINT.openai.azure.com\/\"\r\ndotnet user-secrets set \"AzureOpenAI:ApiKey\" \"YOUR_API_KEY\"\r\n<\/code><\/pre>\n<p>YOUR_ENDPOINT needs to be replaced with the host on which your Azure OpenAI instance is running and YOUR_API_KEY with your instance\u2019s API key.<\/p>\n<p>Alternatively, you can set these values through the following environment variables:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">AzureOpenAI__ChatDeploymentName\r\nAzureOpenAI__Endpoint\r\nAzureOpenAI__ApiKey\r\n<\/code><\/pre>\n<p>Once running, the program will wait for and respond to user queries.<\/p>\n<p><span style=\"font-size: 14pt;\"><strong>The Code<\/strong><\/span><\/p>\n<p>The application code is broadly divided into two parts: one setting up dependency injection and another making use of it.<\/p>\n<p><strong><span style=\"font-size: 12pt;\">Setting up dependency injection<\/span><\/strong><\/p>\n<p>The code in program.cs sets up dependency injection. Let\u2019s examine it. First, an application builder is created:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);<\/code><\/pre>\n<p>For an ASP.Net application, you would use WebApplication.CreateBuilder(args) instead.<\/p>\n<p>The options are loaded into the application with the following code:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">builder.Services.AddOptions&lt;AzureOpenAI&gt;()\r\n       .Bind(builder.Configuration.GetSection(nameof(AzureOpenAI)))\r\n       .ValidateDataAnnotations()\r\n       .ValidateOnStart();\r\n<\/code><\/pre>\n<p>Then, a singleton IChatCompletionService to be re-used by all kernels is created:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">builder.Services.AddSingleton&lt;IChatCompletionService&gt;(sp =&gt;\r\n{\r\n    AzureOpenAI options = sp.GetRequiredService&lt;IOptions&lt;AzureOpenAI&gt;&gt;().Value;\r\n    return new AzureOpenAIChatCompletionService(options.ChatDeploymentName, options.Endpoint, options.ApiKey);\r\n});\r\n<\/code><\/pre>\n<p>Note that a custom HttpClient could be passed into AzureOpenAIChatCompletionService\u2019s constructor, for instance if specific headers needed to be present.<\/p>\n<p>Plugins to be used by the Semantic Kernel are then provided:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">builder.Services.AddSingleton&lt;MyTimePlugin&gt;();\r\nbuilder.Services.AddSingleton&lt;MyAlarmPlugin&gt;();\r\nbuilder.Services.AddKeyedSingleton&lt;MyLightPlugin&gt;(\"OfficeLight\");\r\nbuilder.Services.AddKeyedSingleton&lt;MyLightPlugin&gt;(\"PorchLight\", (sp, key) =&gt;\r\n{\r\n    return new MyLightPlugin(turnedOn: true);\r\n});\r\n<\/code><\/pre>\n<p>The plugins are provided as singletons so that they can be re-used by multiple kernels. Note the keyed singletons \u201cOfficeLight\u201d and \u201cPorchLight\u201d. Keyed singletons are used when distinct instances of the same class need to be provided.<\/p>\n<p>To add an OpenAI or OpenAPI plugin, you need to create a temporary kernel, use it to load the plugin and add it as a keyed singleton:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">Kernel kernel = new();\r\nKernelPlugin openAIPlugin = await kernel.ImportPluginFromOpenAIAsync(\"&lt;OpenAI plugin name&gt;\", new Uri(\"&lt;OpenAI plugin URI&gt;\"));\r\nbuilder.Services.AddKeyedSingleton&lt;KernelPlugin&gt;(\"MyImportedOpenAIPlugin\", openAIPlugin);\r\n \r\nKernelPlugin openApiPlugin = await kernel.ImportPluginFromOpenApiAsync(\"&lt;OpenAPI plugin name&gt;\", new Uri(\"&lt;OpenAPI plugin URI&gt;\"));\r\nbuilder.Services.AddKeyedSingleton&lt;KernelPlugin&gt;(\"MyImportedOpenApiPlugin\", openApiPlugin);\r\n<\/code><\/pre>\n<p>Once you have registered all the plugins you require, you can register a kernel with the plugins you want:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">builder.Services.AddKeyedTransient&lt;Kernel&gt;(\"HomeAutomationKernel\", (sp, key) =&gt;\r\n{\r\n    \/\/ Create a collection of plugins that the kernel will use\r\n    KernelPluginCollection pluginCollection = new();\r\n    pluginCollection.AddFromObject(sp.GetRequiredService&lt;MyTimePlugin&gt;());\r\n    pluginCollection.AddFromObject(sp.GetRequiredService&lt;MyAlarmPlugin&gt;());\r\n    pluginCollection.AddFromObject(sp.GetRequiredKeyedService&lt;MyLightPlugin&gt;(\"OfficeLight\"), \"OfficeLight\");\r\n    pluginCollection.AddFromObject(sp.GetRequiredKeyedService&lt;MyLightPlugin&gt;(\"PorchLight\"), \"PorchLight\");\r\n \r\n    return new Kernel(sp, pluginCollection);\r\n});\r\n<\/code><\/pre>\n<p>The kernel is normally registered as transient so that a new one is created for each operation where one is requested.<\/p>\n<p>Note that appropriate loggers are automagically passed to the Semantic Kernel components when using dependency injection.<\/p>\n<p><strong><span style=\"font-size: 12pt;\">Using dependency injection<\/span><\/strong><\/p>\n<p>In Program.cs, the code to execute after setup is complete is specified by the following line:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">builder.Services.AddHostedService&lt;Worker&gt;();<\/code><\/pre>\n<p>This line causes an instance of Worker to be created and its ExecuteAsync() method to be invoked.<\/p>\n<p>Let\u2019s look at Worker.cs. First, its constructor takes in a Kernel parameter that is populated by dependency injection:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">public Worker(IHostApplicationLifetime hostApplicationLifetime,\r\n    [FromKeyedServices(\"HomeAutomationKernel\")] Kernel kernel)\r\n{\r\n    _hostApplicationLifetime = hostApplicationLifetime;\r\n    _kernel = kernel;\r\n}<\/code><\/pre>\n<p>In this case, the HomeAutomationKernel keyed Kernel is selected. This way, you could use a certain variation of the kernel with the Worker class and another variation with other classes.<\/p>\n<p>In many cases, that is all you would need to do to use Semantic Kernel with dependency injection. But, to illustrate that kernels themselves have a set of services, we access one of them in the application:<\/p>\n<pre class=\"prettyprint language-cs language-csharp\"><code class=\"language-cs language-csharp\">var chatCompletionService = _kernel.GetRequiredService&lt;IChatCompletionService&gt;();<\/code><\/pre>\n<p>chatCompletionService can then be used in the code.<\/p>\n<p>The IChatCompletionService instance could also have been passed through Worker\u2019s constructor. You have the flexibility to use whichever approach suits your requirements better.<\/p>\n<p><strong><span style=\"font-size: 12pt;\">Recap<\/span><\/strong><\/p>\n<p>Semantic Kernel supports dependency injection both to construct its objects and to provide services. Logging is automatically taken care of when using dependency injection. Services and plugins used by Semantic Kernel are typically registered with the dependency injection container as singletons so that they can be re-used \/ shared between various kernels. Kernels are typically registered as transient so that each instance remains unaffected by changes made to kernels handling other tasks. In addition to being usable as services, Kernels themselves possess services which can be accessed and used.<\/p>\n<p>Please reach out if you have any questions or feedback through our <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/discussions\/categories\/general\">Semantic Kernel GitHub Discussion Channel<\/a>. We look forward to hearing from you!\u00a0We would also love your support, if you&#8217;ve enjoyed using Semantic Kernel, give us a star on <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Semantic Kernel fully supports dependency injection. After receiving many questions from the community as to how to best use dependency injection with Semantic Kernel, the team created an app to illustrate some effective patterns.\u00a0 Dependency injection is a technique in which an object receives other objects that it requires rather than creating them internally. This [&hellip;]<\/p>\n","protected":false},"author":149071,"featured_media":2364,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[41],"class_list":["post-2310","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-semantic-kernel","tag-semantic-kernel-dependency-injection-setting-up-dependency-injection-feature-announcement"],"acf":[],"blog_post_summary":"<p>Semantic Kernel fully supports dependency injection. After receiving many questions from the community as to how to best use dependency injection with Semantic Kernel, the team created an app to illustrate some effective patterns.\u00a0 Dependency injection is a technique in which an object receives other objects that it requires rather than creating them internally. This [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/2310","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/149071"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=2310"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/2310\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/2364"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=2310"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=2310"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=2310"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}