From a2a7b8aeac9450479ba69bd819107d1e25a6b6e0 Mon Sep 17 00:00:00 2001
From: Shawn Callegari <36091529+shawncal@users.noreply.github.com>
Date: Fri, 26 May 2023 12:02:06 -0700
Subject: [PATCH] Merge "KernelBuilder" sample into KernelSyntaxExamples
(#1232)
### Motivation and Context
- The KernelBuilder project contains only a single file, and has the
same intent as KernelSyntaxExamples.
- The project name, "KernelBuilder", doesn't make it clear that these
are samples, and seemingly indicates that this is the implementation of
KernelBuilder itself.
- Having this be a standalone project increases the time required to run
"dotnet format", "dotnet build", VS loading/rebuilding and other
solution-wide operations.
### Description
Merges the KernelBuilder program file into KernelSyntaxExamples,
matching the format of the other examples in that project.
---
dotnet/SK-dotnet.sln | 10 +-
samples/dotnet/KernelBuilder/GlobalUsings.cs | 12 --
.../dotnet/KernelBuilder/KernelBuilder.csproj | 23 ---
samples/dotnet/KernelBuilder/Program.cs | 163 ----------------
.../Example42_KernelBuilder.cs | 183 ++++++++++++++++++
.../dotnet/kernel-syntax-examples/Program.cs | 3 +
6 files changed, 187 insertions(+), 207 deletions(-)
delete mode 100644 samples/dotnet/KernelBuilder/GlobalUsings.cs
delete mode 100644 samples/dotnet/KernelBuilder/KernelBuilder.csproj
delete mode 100644 samples/dotnet/KernelBuilder/Program.cs
create mode 100644 samples/dotnet/kernel-syntax-examples/Example42_KernelBuilder.cs
diff --git a/dotnet/SK-dotnet.sln b/dotnet/SK-dotnet.sln
index 2e063fc42411..cc6605d08282 100644
--- a/dotnet/SK-dotnet.sln
+++ b/dotnet/SK-dotnet.sln
@@ -31,8 +31,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
- ..\README.md = ..\README.md
..\.github\workflows\dotnet-format.yml = ..\.github\workflows\dotnet-format.yml
+ ..\README.md = ..\README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SemanticKernel.UnitTests", "src\SemanticKernel.UnitTests\SemanticKernel.UnitTests.csproj", "{37E39C68-5A40-4E63-9D3C-0C66AD98DFCB}"
@@ -48,8 +48,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{F4243136
nuget\NUGET.md = nuget\NUGET.md
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KernelBuilder", "..\samples\dotnet\KernelBuilder\KernelBuilder.csproj", "{A52818AC-57FB-495F-818F-9E1E7BC5618C}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitHubSkills", "..\samples\dotnet\github-skills\GitHubSkills.csproj", "{39E5F0F6-8B36-4ECA-A5F6-FC7522DC2ECF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Skills.OpenAPI", "src\Skills\Skills.OpenAPI\Skills.OpenAPI.csproj", "{F2A1F81E-700E-4C0E-B021-B9EF29AA20BD}"
@@ -170,11 +168,6 @@ Global
{107156B4-5A8B-45C7-97A2-4544D7FA19DE}.Publish|Any CPU.Build.0 = Release|Any CPU
{107156B4-5A8B-45C7-97A2-4544D7FA19DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{107156B4-5A8B-45C7-97A2-4544D7FA19DE}.Release|Any CPU.Build.0 = Release|Any CPU
- {A52818AC-57FB-495F-818F-9E1E7BC5618C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A52818AC-57FB-495F-818F-9E1E7BC5618C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A52818AC-57FB-495F-818F-9E1E7BC5618C}.Publish|Any CPU.ActiveCfg = Release|Any CPU
- {A52818AC-57FB-495F-818F-9E1E7BC5618C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A52818AC-57FB-495F-818F-9E1E7BC5618C}.Release|Any CPU.Build.0 = Release|Any CPU
{39E5F0F6-8B36-4ECA-A5F6-FC7522DC2ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39E5F0F6-8B36-4ECA-A5F6-FC7522DC2ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39E5F0F6-8B36-4ECA-A5F6-FC7522DC2ECF}.Publish|Any CPU.ActiveCfg = Release|Any CPU
@@ -315,7 +308,6 @@ Global
{9ECD1AA0-75B3-4E25-B0B5-9F0945B64974} = {831DDCA2-7D2C-4C31-80DB-6BDB3E1F7AE0}
{107156B4-5A8B-45C7-97A2-4544D7FA19DE} = {9ECD1AA0-75B3-4E25-B0B5-9F0945B64974}
{F4243136-252A-4459-A7C4-EE8C056D6B0B} = {158A4E5E-AEE0-4D60-83C7-8E089B2D881D}
- {A52818AC-57FB-495F-818F-9E1E7BC5618C} = {FA3720F1-C99A-49B2-9577-A940257098BF}
{39E5F0F6-8B36-4ECA-A5F6-FC7522DC2ECF} = {FA3720F1-C99A-49B2-9577-A940257098BF}
{F2A1F81E-700E-4C0E-B021-B9EF29AA20BD} = {9ECD1AA0-75B3-4E25-B0B5-9F0945B64974}
{BC70A5D8-2125-4C37-8C0E-C903EAFA9772} = {FA3720F1-C99A-49B2-9577-A940257098BF}
diff --git a/samples/dotnet/KernelBuilder/GlobalUsings.cs b/samples/dotnet/KernelBuilder/GlobalUsings.cs
deleted file mode 100644
index 41add0ac078a..000000000000
--- a/samples/dotnet/KernelBuilder/GlobalUsings.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-global using Microsoft.Extensions.Logging;
-global using Microsoft.Extensions.Logging.Abstractions;
-global using Microsoft.SemanticKernel;
-global using Microsoft.SemanticKernel.AI;
-global using Microsoft.SemanticKernel.Memory;
-global using Microsoft.SemanticKernel.Reliability;
-global using Microsoft.SemanticKernel.SkillDefinition;
-global using Microsoft.SemanticKernel.TemplateEngine;
-global using Polly;
-global using Polly.Retry;
diff --git a/samples/dotnet/KernelBuilder/KernelBuilder.csproj b/samples/dotnet/KernelBuilder/KernelBuilder.csproj
deleted file mode 100644
index 0c94b9489f4f..000000000000
--- a/samples/dotnet/KernelBuilder/KernelBuilder.csproj
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- KernelSetup
- net6.0
- LatestMajor
- Exe
- enable
- enable
- CA2000
- false
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/samples/dotnet/KernelBuilder/Program.cs b/samples/dotnet/KernelBuilder/Program.cs
deleted file mode 100644
index c1c055812ee6..000000000000
--- a/samples/dotnet/KernelBuilder/Program.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-// ==========================================================================================================
-// The easier way to instantiate the Semantic Kernel is to use KernelBuilder.
-// You can access the builder using either Kernel.Builder or KernelBuilder.
-
-#pragma warning disable CA1852
-#pragma warning disable CA1050
-
-using Microsoft.SemanticKernel.AI.TextCompletion;
-using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextCompletion;
-using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
-using Microsoft.SemanticKernel.Services;
-
-#pragma warning disable CA1852 // Seal internal types
-IKernel kernel1 = Kernel.Builder.Build();
-#pragma warning restore CA1852 // Seal internal types
-
-IKernel kernel2 = Kernel.Builder.Build();
-
-// ==========================================================================================================
-// Kernel.Builder returns a new builder instance, in case you want to configure the builder differently.
-// The following are 3 distinct builder instances.
-
-var builder1 = new KernelBuilder();
-
-var builder2 = Kernel.Builder;
-
-var builder3 = Kernel.Builder;
-
-// ==========================================================================================================
-// A builder instance can create multiple kernel instances, e.g. in case you need
-// multiple kernels that share the same dependencies.
-
-var builderX = new KernelBuilder();
-
-var kernelX1 = builderX.Build();
-var kernelX2 = builderX.Build();
-var kernelX3 = builderX.Build();
-
-// ==========================================================================================================
-// Kernel instances can be created the usual way with "new", though the process requires particular
-// attention to how dependencies are wired together. Although the building blocks are available
-// to enable custom configurations, we highly recommend using KernelBuilder instead, to ensure
-// a correct dependency injection.
-
-// Manually setup all the dependencies used internally by the kernel
-var logger = NullLogger.Instance;
-var memoryStorage = new VolatileMemoryStore();
-var textEmbeddingGenerator = new AzureTextEmbeddingGeneration("modelId", "https://...", "apiKey", logger: logger);
-var memory = new SemanticTextMemory(memoryStorage, textEmbeddingGenerator);
-var skills = new SkillCollection();
-var templateEngine = new PromptTemplateEngine(logger);
-var config = new KernelConfig();
-
-var httpHandler = new DefaultHttpRetryHandler(new HttpRetryConfig(), logger);
-var httpClient = new HttpClient(httpHandler);
-var aiServices = new AIServiceCollection();
-ITextCompletion Factory() => new AzureTextCompletion("deploymentName", "https://...", "apiKey", httpClient, logger);
-aiServices.SetService("foo", Factory);
-IAIServiceProvider aiServiceProvider = aiServices.Build();
-
-// Create kernel manually injecting all the dependencies
-var kernel3 = new Kernel(skills, aiServiceProvider, templateEngine, memory, config, logger);
-
-// ==========================================================================================================
-// The kernel builder purpose is to simplify this process, automating how dependencies
-// are connected, still allowing to customize parts of the composition.
-
-// Example: how to use a custom memory and configure Azure OpenAI
-var kernel4 = Kernel.Builder
- .WithLogger(NullLogger.Instance)
- .WithMemory(memory)
- .WithAzureTextCompletionService("deploymentName", "https://...", "apiKey")
- .Build();
-
-// Example: how to use a custom memory storage and custom embedding generator
-var kernel5 = Kernel.Builder
- .WithLogger(NullLogger.Instance)
- .WithMemoryStorageAndTextEmbeddingGeneration(memoryStorage, textEmbeddingGenerator)
- .Build();
-
-// Example: how to use a custom memory storage
-var kernel6 = Kernel.Builder
- .WithLogger(NullLogger.Instance)
- .WithMemoryStorage(memoryStorage) // Custom memory storage
- .WithAzureTextCompletionService("myName1", "completionDeploymentName", "https://...", "apiKey") // This will be used when using AI completions
- .WithAzureTextEmbeddingGenerationService("myName2", "embeddingsDeploymentName", "https://...", "apiKey") // This will be used when indexing memory records
- .Build();
-
-// ==========================================================================================================
-// The AI services are defined with the builder
-
-var kernel7 = Kernel.Builder
- .WithAzureTextCompletionService("myName1", "completionDeploymentName", "https://...", "apiKey", true)
- .Build();
-
-// ==========================================================================================================
-// When invoking AI, by default the kernel will retry on transient errors, such as throttling and timeouts.
-// The default behavior can be configured or a custom retry handler can be injected that will apply to all
-// AI requests (when using the kernel).
-
-var kernel8 = Kernel.Builder
- .Configure(c => c.SetDefaultHttpRetryConfig(new HttpRetryConfig
- {
- MaxRetryCount = 3,
- UseExponentialBackoff = true,
- // MinRetryDelay = TimeSpan.FromSeconds(2),
- // MaxRetryDelay = TimeSpan.FromSeconds(8),
- // MaxTotalRetryTime = TimeSpan.FromSeconds(30),
- // RetryableStatusCodes = new[] { HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout },
- // RetryableExceptions = new[] { typeof(HttpRequestException) }
- }))
- .Build();
-
-var kernel9 = Kernel.Builder
- .Configure(c => c.SetHttpRetryHandlerFactory(new NullHttpRetryHandlerFactory()))
- .Build();
-
-var kernel10 = Kernel.Builder.WithRetryHandlerFactory(new RetryThreeTimesFactory()).Build();
-
-// Example of a basic custom retry handler
-public class RetryThreeTimesFactory : IDelegatingHandlerFactory
-{
- public DelegatingHandler Create(ILogger? log)
- {
- return new RetryThreeTimes(log);
- }
-}
-
-public class RetryThreeTimes : DelegatingHandler
-{
- private readonly AsyncRetryPolicy _policy;
-
- public RetryThreeTimes(ILogger? log = null)
- {
- this._policy = GetPolicy(log ?? NullLogger.Instance);
- }
-
- protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- return await this._policy.ExecuteAsync(async () =>
- {
- var response = await base.SendAsync(request, cancellationToken);
- return response;
- });
- }
-
- private static AsyncRetryPolicy GetPolicy(ILogger log)
- {
- return Policy
- .Handle(ex => ex.ErrorCode == AIException.ErrorCodes.Throttling)
- .WaitAndRetryAsync(new[]
- {
- TimeSpan.FromSeconds(2),
- TimeSpan.FromSeconds(4),
- TimeSpan.FromSeconds(8)
- },
- (ex, timespan, retryCount, _) => log.LogWarning(ex,
- "Error executing action [attempt {0} of 3], pausing {1}ms",
- retryCount, timespan.TotalMilliseconds));
- }
-}
diff --git a/samples/dotnet/kernel-syntax-examples/Example42_KernelBuilder.cs b/samples/dotnet/kernel-syntax-examples/Example42_KernelBuilder.cs
new file mode 100644
index 000000000000..b18e65d1f358
--- /dev/null
+++ b/samples/dotnet/kernel-syntax-examples/Example42_KernelBuilder.cs
@@ -0,0 +1,183 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// ==========================================================================================================
+// The easier way to instantiate the Semantic Kernel is to use KernelBuilder.
+// You can access the builder using either Kernel.Builder or KernelBuilder.
+
+#pragma warning disable CA1852
+
+using System;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.AI;
+using Microsoft.SemanticKernel.AI.TextCompletion;
+using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextCompletion;
+using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
+using Microsoft.SemanticKernel.Memory;
+using Microsoft.SemanticKernel.Reliability;
+using Microsoft.SemanticKernel.Services;
+using Microsoft.SemanticKernel.SkillDefinition;
+using Microsoft.SemanticKernel.TemplateEngine;
+using Polly;
+using Polly.Retry;
+
+// ReSharper disable once InconsistentNaming
+public static class Example42_KernelBuilder
+{
+ public static void Run()
+ {
+#pragma warning disable CA1852 // Seal internal types
+ IKernel kernel1 = Kernel.Builder.Build();
+#pragma warning restore CA1852 // Seal internal types
+
+ IKernel kernel2 = Kernel.Builder.Build();
+
+ // ==========================================================================================================
+ // Kernel.Builder returns a new builder instance, in case you want to configure the builder differently.
+ // The following are 3 distinct builder instances.
+
+ var builder1 = new KernelBuilder();
+
+ var builder2 = Kernel.Builder;
+
+ var builder3 = Kernel.Builder;
+
+ // ==========================================================================================================
+ // A builder instance can create multiple kernel instances, e.g. in case you need
+ // multiple kernels that share the same dependencies.
+
+ var builderX = new KernelBuilder();
+
+ var kernelX1 = builderX.Build();
+ var kernelX2 = builderX.Build();
+ var kernelX3 = builderX.Build();
+
+ // ==========================================================================================================
+ // Kernel instances can be created the usual way with "new", though the process requires particular
+ // attention to how dependencies are wired together. Although the building blocks are available
+ // to enable custom configurations, we highly recommend using KernelBuilder instead, to ensure
+ // a correct dependency injection.
+
+ // Manually setup all the dependencies used internally by the kernel
+ var logger = NullLogger.Instance;
+ var memoryStorage = new VolatileMemoryStore();
+ var textEmbeddingGenerator = new AzureTextEmbeddingGeneration("modelId", "https://...", "apiKey", logger: logger);
+ using var memory = new SemanticTextMemory(memoryStorage, textEmbeddingGenerator);
+ var skills = new SkillCollection();
+ var templateEngine = new PromptTemplateEngine(logger);
+ var config = new KernelConfig();
+
+ using var httpHandler = new DefaultHttpRetryHandler(new HttpRetryConfig(), logger);
+ using var httpClient = new HttpClient(httpHandler);
+ var aiServices = new AIServiceCollection();
+ ITextCompletion Factory() => new AzureTextCompletion("deploymentName", "https://...", "apiKey", httpClient, logger);
+ aiServices.SetService("foo", Factory);
+ IAIServiceProvider aiServiceProvider = aiServices.Build();
+
+ // Create kernel manually injecting all the dependencies
+ using var kernel3 = new Kernel(skills, aiServiceProvider, templateEngine, memory, config, logger);
+
+ // ==========================================================================================================
+ // The kernel builder purpose is to simplify this process, automating how dependencies
+ // are connected, still allowing to customize parts of the composition.
+
+ // Example: how to use a custom memory and configure Azure OpenAI
+ var kernel4 = Kernel.Builder
+ .WithLogger(NullLogger.Instance)
+ .WithMemory(memory)
+ .WithAzureTextCompletionService("deploymentName", "https://...", "apiKey")
+ .Build();
+
+ // Example: how to use a custom memory storage and custom embedding generator
+ var kernel5 = Kernel.Builder
+ .WithLogger(NullLogger.Instance)
+ .WithMemoryStorageAndTextEmbeddingGeneration(memoryStorage, textEmbeddingGenerator)
+ .Build();
+
+ // Example: how to use a custom memory storage
+ var kernel6 = Kernel.Builder
+ .WithLogger(NullLogger.Instance)
+ .WithMemoryStorage(memoryStorage) // Custom memory storage
+ .WithAzureTextCompletionService("myName1", "completionDeploymentName", "https://...", "apiKey") // This will be used when using AI completions
+ .WithAzureTextEmbeddingGenerationService("myName2", "embeddingsDeploymentName", "https://...", "apiKey") // This will be used when indexing memory records
+ .Build();
+
+ // ==========================================================================================================
+ // The AI services are defined with the builder
+
+ var kernel7 = Kernel.Builder
+ .WithAzureTextCompletionService("myName1", "completionDeploymentName", "https://...", "apiKey", true)
+ .Build();
+
+ // ==========================================================================================================
+ // When invoking AI, by default the kernel will retry on transient errors, such as throttling and timeouts.
+ // The default behavior can be configured or a custom retry handler can be injected that will apply to all
+ // AI requests (when using the kernel).
+
+ var kernel8 = Kernel.Builder
+ .Configure(c => c.SetDefaultHttpRetryConfig(new HttpRetryConfig
+ {
+ MaxRetryCount = 3,
+ UseExponentialBackoff = true,
+ // MinRetryDelay = TimeSpan.FromSeconds(2),
+ // MaxRetryDelay = TimeSpan.FromSeconds(8),
+ // MaxTotalRetryTime = TimeSpan.FromSeconds(30),
+ // RetryableStatusCodes = new[] { HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout },
+ // RetryableExceptions = new[] { typeof(HttpRequestException) }
+ }))
+ .Build();
+
+ var kernel9 = Kernel.Builder
+ .Configure(c => c.SetHttpRetryHandlerFactory(new NullHttpRetryHandlerFactory()))
+ .Build();
+
+ var kernel10 = Kernel.Builder.WithRetryHandlerFactory(new RetryThreeTimesFactory()).Build();
+ }
+
+ // Example of a basic custom retry handler
+ public class RetryThreeTimesFactory : IDelegatingHandlerFactory
+ {
+ public DelegatingHandler Create(ILogger? log)
+ {
+ return new RetryThreeTimes(log);
+ }
+ }
+
+ public class RetryThreeTimes : DelegatingHandler
+ {
+ private readonly AsyncRetryPolicy _policy;
+
+ public RetryThreeTimes(ILogger? log = null)
+ {
+ this._policy = GetPolicy(log ?? NullLogger.Instance);
+ }
+
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ return await this._policy.ExecuteAsync(async () =>
+ {
+ var response = await base.SendAsync(request, cancellationToken);
+ return response;
+ });
+ }
+
+ private static AsyncRetryPolicy GetPolicy(ILogger log)
+ {
+ return Policy
+ .Handle(ex => ex.ErrorCode == AIException.ErrorCodes.Throttling)
+ .WaitAndRetryAsync(new[]
+ {
+ TimeSpan.FromSeconds(2),
+ TimeSpan.FromSeconds(4),
+ TimeSpan.FromSeconds(8)
+ },
+ (ex, timespan, retryCount, _) => log.LogWarning(ex,
+ "Error executing action [attempt {0} of 3], pausing {1}ms",
+ retryCount, timespan.TotalMilliseconds));
+ }
+ }
+}
diff --git a/samples/dotnet/kernel-syntax-examples/Program.cs b/samples/dotnet/kernel-syntax-examples/Program.cs
index 194662a82dfc..d54442f6b02a 100644
--- a/samples/dotnet/kernel-syntax-examples/Program.cs
+++ b/samples/dotnet/kernel-syntax-examples/Program.cs
@@ -129,5 +129,8 @@ public static async Task Main()
Example41_HttpClientUsage.Run();
Console.WriteLine("== DONE ==");
+
+ Example42_KernelBuilder.Run();
+ Console.WriteLine("== DONE ==");
}
}