diff --git a/docs/en/framework/infrastructure/artificial-intelligence.md b/docs/en/framework/infrastructure/artificial-intelligence.md new file mode 100644 index 0000000000..6af5cf589c --- /dev/null +++ b/docs/en/framework/infrastructure/artificial-intelligence.md @@ -0,0 +1,311 @@ +# Artificial Intelligence + +ABP provides a simple way to integrate AI capabilities into your applications by unifying two popular .NET AI stacks under a common concept called a "workspace": + +- Microsoft.Extensions.AI `IChatClient` +- Microsoft.SemanticKernel `Kernel` + +A workspace is just a named scope. You configure providers per workspace and then resolve either default services (for the "Default" workspace) or workspace-scoped services. + +## Installation + +> This package is not included by default. Install it to enable AI features. + +It is suggested to use the ABP CLI to install the package. Open a command line window in the folder of the project (.csproj file) and type the following command: + +```bash +abp add-package Volo.Abp.AI +``` + +### Manual Installation + +Add nuget package to your project: + +```bash +dotnet add package Volo.Abp.AI +``` + +Then add the module dependency to your module class: + +```csharp +using Volo.Abp.AI; +using Volo.Abp.Modularity; + +[DependsOn(typeof(AbpAIModule))] +public class MyProjectModule : AbpModule +{ +} +``` + +## Usage + +### Chat Client + +#### Default configuration (quick start) + +Configure the special workspace named `"Default"` to inject `IChatClient` by default. + +```csharp +using Microsoft.Extensions.AI; +using Microsoft.SemanticKernel; +using Volo.Abp.AI; +using Volo.Abp.Modularity; + +public class MyProjectModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.PreConfigure(options => + { + options.Workspaces.Configure(AbpAIModule.DefaultWorkspaceName, configuration => + { + configuration.ConfigureChatClient(chatClientConfiguration => + { + chatClientConfiguration.Builder = new ChatClientBuilder( + sp => new OllamaApiClient("http://localhost:11434", "mistral") + ); + + chatClientConfiguration.BuilderConfigurers.Add(builder => + { + builder.UseSystemMessage( + "You are a helpful assistant that greets users in a friendly manner with their names." + ); + }); + }); + + // Chat client only in this quick start + }); + }); + } +} +``` + +Notes: + +- Prefer `ConfigureChatClient(...)` / `ConfigureKernel(...)` methods for configuration. +- Set the `Builder` and then use `BuilderConfigurers.Add(...)` to apply incremental changes. +- If a workspace configures only the Kernel, a chat client may still be exposed for that workspace through the Kernel’s service provider (when available). + +Once configured, inject the default chat client: + +```csharp +using Microsoft.Extensions.AI; + +public class MyService +{ + private readonly IChatClient _chatClient; // default chat client + + public MyService(IChatClient chatClient) + { + _chatClient = chatClient; + } +} +``` + +#### Workspace configuration + +Workspaces allow multiple, isolated AI configurations. Define workspace types (optionally decorated with `WorkspaceNameAttribute`). If omitted, the type’s full name is used. + +```csharp +using Volo.Abp.AI; + +[WorkspaceName("GreetingAssistant")] +public class GreetingAssistant // ChatClient-only workspace +{ +} + +[WorkspaceName("ContentPlanner")] +public class ContentPlanner // Kernel-only workspace +{ +} +``` + +Configure a ChatClient workspace: + +```csharp +public class MyProjectModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.PreConfigure(options => + { + options.Workspaces.Configure(configuration => + { + configuration.ConfigureChatClient(chatClientConfiguration => + { + chatClientConfiguration.Builder = new ChatClientBuilder( + sp => new OllamaApiClient("http://localhost:11434", "mistral") + ); + + chatClientConfiguration.BuilderConfigurers.Add(builder => + { + builder.UseSystemMessage( + "You are a helpful assistant that greets users in a friendly manner with their names." + ); + }); + }); + }); + }); + } +} +``` + +### Semantic Kernel + +#### Default configuration + +```csharp +public class MyProjectModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.PreConfigure(options => + { + options.Workspaces.Configure(configuration => + { + configuration.ConfigureKernel(kernelConfiguration => + { + kernelConfiguration.Builder = Kernel.CreateBuilder() + .AddAzureOpenAIChatClient("...", "..."); + }); + // Note: Chat client is not configured here + }); + }); + } +} +``` + +#### Workspace configuration + +```csharp +using Microsoft.Extensions.AI; +using Volo.Abp.AI; + +public class GreetingService +{ + private readonly IChatClient _chatClient; + + public GreetingService(IChatClient chatClient) + { + _chatClient = chatClient; + } + + public async Task GreetAsync(string name) + { + var response = await _chatClient.GetResponseAsync( + [new ChatMessage(ChatRole.User, $"Greet {name}")] + ); + return response?.Message?.Text ?? string.Empty; + } +} +``` + +#### Resolve + +```csharp +using Microsoft.Extensions.AI; +using Volo.Abp.AI; +using Microsoft.SemanticKernel; + +public class PlanningService +{ + private readonly IKernelAccessor _kernelAccessor; + private readonly IChatClient _chatClient; // available even if only Kernel is configured + + public PlanningService( + IKernelAccessor kernelAccessor, + IChatClient chatClient) + { + _kernelAccessor = kernelAccessor; + _chatClient = chatClient; + } + + public async Task PlanAsync(string topic) + { + var kernel = _kernelAccessor.Kernel; // Microsoft.SemanticKernel.Kernel + // Use Semantic Kernel APIs if needed... + + var response = await _chatClient.GetResponseAsync( + [new ChatMessage(ChatRole.User, $"Create a content plan for: {topic}")] + ); + return response?.Message?.Text ?? string.Empty; + } +} +``` + +## Options + +- `AbpAIOptions.Workspaces`: A `WorkspaceConfigurationDictionary` used to configure workspaces. + - `Configure(Action)` + - `Configure(string name, Action)` + +- `WorkspaceConfiguration` per workspace: + - `ChatClient`: `ChatClientConfiguration` + - `Builder`: `ChatClientBuilder?` + - `ConfigureBuilder(Action)` + - `ConfigureBuilder(string name, Action)` (named actions executed in order) + - `Kernel`: `KernelConfiguration` + - `Builder`: `IKernelBuilder?` + - `ConfigureBuilder(Action)` + - `ConfigureBuilder(string name, Action)` + +- `AbpAIWorkspaceOptions.ConfiguredWorkspaceNames`: Automatically set of workspace names configured during startup. Useful for diagnostics. + +## Advanced Usage and Customizations + +### Addding Your Own DelegatingChatClient + +If you want to build your own decorator, implement a `DelegatingChatClient` derivative and provide an extension method that adds it to the `ChatClientBuilder` using `builder.Use(...)`. + +Example sketch: + +```csharp +using Microsoft.Extensions.AI; + +public class MyPolicyChatClient : DelegatingChatClient +{ + public MyPolicyChatClient(IChatClient inner) : base(inner) { } + + public override Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken cancellationToken = default) + { + // Mutate messages/options as needed, then call base + return base.GetResponseAsync(messages, options, cancellationToken); + } +} + +public static class MyPolicyChatClientExtensions +{ + public static ChatClientBuilder UseMyPolicy(this ChatClientBuilder builder) + { + return builder.Use(client => new MyPolicyChatClient(client)); + } +} +``` + +It'll have similar usage with `.UseSystemMessage(...)` extension while configuring a chat client (see configuration examples above). + +```cs +chatClientConfiguration.BuilderConfigurers.Add(builder => +{ + builder.UseMyPolicy(); +}); +``` + + +## Technical Anatomy + +- `AbpAIModule`: Wires up configured workspaces, registers keyed services and default services for the `"Default"` workspace. +- `AbpAIOptions`: Holds `Workspaces` and provides helper methods for internal keyed service naming. +- `WorkspaceConfigurationDictionary` and `WorkspaceConfiguration`: Configure per-workspace Chat Client and Kernel. +- `ChatClientConfiguration` and `KernelConfiguration`: Hold builders and a list of ordered builder configurers. +- `WorkspaceNameAttribute`: Names a workspace; falls back to the type’s full name if not specified. +- `IChatClient`: Typed chat client for a workspace. +- `IKernelAccessor`: Provides access to the workspace’s `Kernel` instance if configured. +- `AbpAIWorkspaceOptions`: Exposes `ConfiguredWorkspaceNames` for diagnostics. + +There are no database tables for this feature; it is a pure configuration and DI integration layer. + +## See Also + +- Microsoft.Extensions.AI (Chat Client) +- Microsoft Semantic Kernel \ No newline at end of file diff --git a/docs/en/framework/infrastructure/index.md b/docs/en/framework/infrastructure/index.md index 681e593aba..e5691612dc 100644 --- a/docs/en/framework/infrastructure/index.md +++ b/docs/en/framework/infrastructure/index.md @@ -3,6 +3,7 @@ ABP provides a complete infrastructure for creating real world software solutions with modern architectures based on the .NET platform. Each of the following documents explains an infrastructure feature: * [Audit Logging](./audit-logging.md) +* [Artificial Intelligence](./artificial-intelligence.md) * [Background Jobs](./background-jobs/index.md) * [Background Workers](./background-workers/index.md) * [BLOB Storing](./blob-storing/index.md) diff --git a/framework/src/Volo.Abp.AI/README.md b/framework/src/Volo.Abp.AI/README.md deleted file mode 100644 index 5f240d05cf..0000000000 --- a/framework/src/Volo.Abp.AI/README.md +++ /dev/null @@ -1,159 +0,0 @@ -### Volo.Abp.AI for application developers - -Use this package to configure and consume two AI stacks in ABP apps with a shared “workspace” scope: -- Microsoft.Extensions.AI Chat Clients -- Microsoft.SemanticKernel Kernels - -Key ideas: -- Decorate a class with `WorkspaceNameAttribute` to define a workspace. The same workspace name is used for both Chat Client and Kernel. -- Resolve services either by workspace type (`IChatClient`, `IKernel`) or as defaults (`IChatClient`, `Kernel`). - -### 1) Add module dependency - -```csharp -using Volo.Abp.AI; -using Volo.Abp.Modularity; - -[DependsOn(typeof(AbpAIModule))] -public class YourAppModule : AbpModule -{ -} -``` - -### 2) Define a workspace - -```csharp -using Volo.Abp.AI; - -[WorkspaceName("CommentSummarizer")] -public class CommentSummarizer { } -``` - -If you omit the attribute, the type’s full name is used as the workspace name. - -### 3) Configure providers per workspace - -Configure in your module (in `ConfigureServices` using `PreConfigure`). You can set defaults and/or configure specific workspaces. - -```csharp -using Microsoft.Extensions.AI; -using Microsoft.SemanticKernel; -using Volo.Abp.AI; -using Volo.Abp.Modularity; - -public class YourAppModule : AbpModule -{ - public override void ConfigureServices(ServiceConfigurationContext context) - { - PreConfigure(options => - { - // Default ChatClient (inject IChatClient) - options.ChatClients.ConfigureDefault(cfg => - { - cfg.Builder = new ChatClientBuilder(); - cfg.ConfigureBuilder(b => - { - // Example: OpenAI provider (Microsoft.Extensions.AI.OpenAI) - b.UseOpenAIChatClient("gpt-4o-mini", apiKey: ""); - }); - }); - - // Default Kernel (inject Kernel) - options.Kernels.ConfigureDefault(cfg => - { - var kb = Kernel.CreateBuilder(); - // Example: OpenAI connector (Microsoft.SemanticKernel.Connectors.OpenAI) - kb.AddOpenAIChatCompletion("gpt-4o-mini", ""); - cfg.Builder = kb; - }); - - // Workspace-scoped ChatClient (inject IChatClient) - options.ChatClients.Configure(cfg => - { - cfg.Builder = new ChatClientBuilder(); - cfg.ConfigureBuilder(b => b.UseOpenAIChatClient("gpt-4o-mini", "")); - }); - - // Workspace-scoped Kernel (inject IKernel) - options.Kernels.Configure(cfg => - { - var kb = Kernel.CreateBuilder(); - kb.AddOpenAIChatCompletion("gpt-4o-mini", ""); - cfg.Builder = kb; - }); - }); - } -} -``` - -Notes: -- `cfg.Builder` is required for both Chat Client and Kernel. -- You can call `cfg.ConfigureBuilder(...)` multiple times; actions run in order. - -### 4) Resolve and use services - -Defaults (from `ConfigureDefault`): - -```csharp -public class MyService -{ - private readonly IChatClient _chatClient; // Microsoft.Extensions.AI - private readonly Kernel _kernel; // Microsoft.SemanticKernel - - public MyService(IChatClient chatClient, Kernel kernel) - { - _chatClient = chatClient; - _kernel = kernel; - } -} -``` - -Workspace-scoped (typed): - -```csharp -public class CommentSummarizerService -{ - private readonly IChatClient _chatClient; - private readonly IKernel _kernel; - - public CommentSummarizerService( - IChatClient chatClient, - IKernel kernel) - { - _chatClient = chatClient; - _kernel = kernel; - } -} -``` - -Access the original Semantic Kernel instance via `IKernel.Kernel`: - -```csharp -public class KernelUsage -{ - private readonly IKernel _workspaceKernel; - - public KernelUsage(IKernel workspaceKernel) - { - _workspaceKernel = workspaceKernel; - } - - public async Task RunAsync() - { - var sk = _workspaceKernel.Kernel; // Microsoft.SemanticKernel.Kernel - // Use SK APIs directly - } -} -``` - -### Frequently used variations - -- Only Chat Client per workspace: configure `options.ChatClients.Configure(...)`. -- Only Kernel per workspace: configure `options.Kernels.Configure(...)`. -- Single global setup: just use `ConfigureDefault` for either or both; inject the default services. - -### Terminology - -- `WorkspaceNameAttribute`: names a workspace; used for both stacks. -- `IChatClient` and `IKernel`: typed services bound to a workspace. -- `IChatClient` and `Kernel`: defaults if configured via `ConfigureDefault`.