diff --git a/docs/en/framework/infrastructure/artificial-intelligence.md b/docs/en/framework/infrastructure/artificial-intelligence.md index 652c7c8233..9cb5f3632a 100644 --- a/docs/en/framework/infrastructure/artificial-intelligence.md +++ b/docs/en/framework/infrastructure/artificial-intelligence.md @@ -1,11 +1,9 @@ # Artificial Intelligence +ABP Framework provides integration for AI capabilities to your application by using Microsoft's AI stacks by using abstractions and workspaces. The main purpose of this integration is to provide a consistent way to use AI capabilities and managing different AI providers, models and configurations by using workspaces. -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": +ABP Framework doesn't implement any AI providers or models, it only provides the abstractions by using Microsoft's packages such as [Microsoft.Extensions.AI](https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai) and [Microsoft.SemanticKernel](https://learn.microsoft.com/en-us/semantic-kernel/overview/). -- 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. +ABP allows you to define a default configuration for across the application and also allows you to define isolated configurations for different different purposes by using workspaces. A workspace allows you to configure isolated AI configurations for a named scope. You can resolve AI services for a specific workspace when you need to use them. ## Installation @@ -17,152 +15,59 @@ It is suggested to use the ABP CLI to install the package. Open a command line w 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 +Since ABP supports both `Microsoft.Extensions.AI` and `Microsoft.SemanticKernel`, you can use both of them in your application by resolving `IChatClient` or `IKernelAccessor` services from the [service provider](../fundamentals/dependency-injection.md). -#### Default configuration (quick start) +### Microsoft.Extensions.AI -Configure the default workspace to inject `IChatClient` directly. +You can resolve both `IChatClient` to access configured chat client from your service and use it directly. ```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.ConfigureDefault(configuration => - { - configuration.ConfigureChatClient(chatClientConfiguration => - { - chatClientConfiguration.Builder = new ChatClientBuilder( - sp => new OllamaApiClient("http://localhost:11434", "mistral") - ); - }); - - // Chat client only in this quick start - }); - }); - } -} -``` - -Once configured, inject the default chat client: - -```csharp -using Microsoft.Extensions.AI; - public class MyService { - private readonly IChatClient _chatClient; // default chat client - + private readonly IChatClient _chatClient; 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 -{ -} -``` - -Configure a ChatClient workspace: - -```csharp -public class MyProjectModule : AbpModule -{ - public override void ConfigureServices(ServiceConfigurationContext context) + public async Task GetResponseAsync(string prompt) { - 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 => - { - // Anything you want to do with the builder: - // builder.UseFunctionInvocation().UseLogging(); // For example - }); - }); - }); - }); + return await _chatClient.GetResponseAsync(prompt); } } ``` -### Semantic Kernel - -#### Default configuration +You can also resolve `IChatClientAccessor` to access the `IChatClient` optionally configured scenarios such as developing a module or a service that may use AI capabilities **optionally**. ```csharp -public class MyProjectModule : AbpModule +public class MyService { - public override void ConfigureServices(ServiceConfigurationContext context) + private readonly IChatClientAccessor _chatClientAccessor; + public MyService(IChatClientAccessor chatClientAccessor) + { + _chatClientAccessor = chatClientAccessor; + } + + public async Task GetResponseAsync(string prompt) { - context.Services.PreConfigure(options => + var chatClient = _chatClientAccessor.ChatClient; + if (chatClient is null) { - options.Workspaces.ConfigureDefault(configuration => - { - configuration.ConfigureKernel(kernelConfiguration => - { - kernelConfiguration.Builder = Kernel.CreateBuilder() - .AddAzureOpenAIChatClient("...", "..."); - }); - // Note: Chat client is not configured here - }); - }); + return "No chat client configured"; + } + return await chatClient.GetResponseAsync(prompt); } } ``` -Once configured, inject the default kernel: +### Microsoft.SemanticKernel -```csharp -using System.Threading.Tasks; -using Volo.Abp.AI; +Semantic Kernel can be used by resolving `IKernelAccessor` service that carries the `Kernel` instance. Kernel might be null if no workspace is configured. You should check the kernel before using it. +```csharp public class MyService { private readonly IKernelAccessor _kernelAccessor; @@ -171,137 +76,59 @@ public class MyService _kernelAccessor = kernelAccessor; } - public async Task DoSomethingAsync() - { - var kernel = _kernelAccessor.Kernel; // Kernel might be null if no workspace is configured. - - var result = await kernel.InvokeAsync(/*... */); - } -} -``` - -#### Workspace configuration - -```csharp -public class MyProjectModule : AbpModule -{ - public override void ConfigureServices(ServiceConfigurationContext context) + public async Task GetResponseAsync(string prompt) { - context.Services.PreConfigure(options => + var kernel = _kernelAccessor.Kernel; + if (kernel is null) { - options.Workspaces.Configure(configuration => - { - configuration.ConfigureKernel(kernelConfiguration => - { - kernelConfiguration.Builder = Kernel.CreateBuilder() - .AddOpenAIChatCompletion("...", "..."); - }); - }); - }); + return "No kernel configured"; + } + return await kernel.InvokeAsync(prompt); } } ``` -#### Workspace usage +### Workspaces + +Workspaces are a way to configure isolated AI configurations for a named scope. You can define a workspace by decorating a class with the `WorkspaceNameAttribute` attribute that carries the workspace name. +- Workspace names must be unique. +- Workspace names cannot contain spaces _(use underscores or camelCase)_. +- Workspace names are case-sensitive. ```csharp -using Microsoft.Extensions.AI; using Volo.Abp.AI; -using Microsoft.SemanticKernel; -public class PlanningService +[WorkspaceName("CommentSummarization")] +public class CommentSummarization { - 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 +> [!NOTE] +> If you don't specify the workspace name, the full name of the class will be used as the workspace name. -`AbpAIOptions` configuration pattern offers `ConfigureChatClient(...)` and `ConfigureKernel(...)` methods for configuration. These methods are defined in the `WorkspaceConfiguration` class. They are used to configure the `ChatClient` and `Kernel` respectively. - -`Builder` is set once and is used to build the `ChatClient` or `Kernel` instance. `BuilderConfigurers` is a list of actions that are applied to the `Builder` instance for incremental changes. These actions are executed in the order they are added. - -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). - - -## 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: +You can resolve generic versions of `IChatClient`, `IChatClientAccessor` or `IKernelAccessor` services for a specific workspace as generic arguments. If Chat Client or Kernel is not configured for a workspace, you will get `null` from the accessor services. You should check the accessor before using it. This applies only for specified workspaces. Another workspace may have a configured Chat Client or Kernel. ```csharp -using Microsoft.Extensions.AI; - -public class SystemMessageChatClient : DelegatingChatClient +public class MyService { - public SystemMessageChatClient(IChatClient inner, string systemMessage) : base(inner) + private readonly IChatClientAccessor _chatClientAccessor; + public MyService(IChatClientAccessor chatClientAccessor) { - SystemMessage = systemMessage; + _chatClientAccessor = chatClientAccessor; } - public string SystemMessage { get; set; } - - public override Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken cancellationToken = default) + public async Task GetResponseAsync(string prompt) { - // Mutate messages/options as needed, then call base - return base.GetResponseAsync(messages, options, cancellationToken); - } -} - -public static class SystemMessageChatClientExtensions -{ - public static ChatClientBuilder UseSystemMessage(this ChatClientBuilder builder, string systemMessage) - { - return builder.Use(client => new SystemMessageChatClient(client, systemMessage)); + var chatClient = _chatClientAccessor.ChatClient; + if (chatClient is null) + { + return "No chat client configured for 'CommentSummarization' workspace"; + } + return await chatClient.GetResponseAsync(prompt); } } ``` +## Configuration -```cs -chatClientConfiguration.BuilderConfigurers.Add(builder => -{ - builder.UseSystemMessage("You are a helpful assistant that greets users in a friendly manner with their names."); -}); -``` - -## 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