|
| 1 | +# Artificial Intelligence |
| 2 | + |
| 3 | +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": |
| 4 | + |
| 5 | +- Microsoft.Extensions.AI `IChatClient` |
| 6 | +- Microsoft.SemanticKernel `Kernel` |
| 7 | + |
| 8 | +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. |
| 9 | + |
| 10 | +## Installation |
| 11 | + |
| 12 | +> This package is not included by default. Install it to enable AI features. |
| 13 | +
|
| 14 | +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: |
| 15 | + |
| 16 | +```bash |
| 17 | +abp add-package Volo.Abp.AI |
| 18 | +``` |
| 19 | + |
| 20 | +### Manual Installation |
| 21 | + |
| 22 | +Add nuget package to your project: |
| 23 | + |
| 24 | +```bash |
| 25 | +dotnet add package Volo.Abp.AI |
| 26 | +``` |
| 27 | + |
| 28 | +Then add the module dependency to your module class: |
| 29 | + |
| 30 | +```csharp |
| 31 | +using Volo.Abp.AI; |
| 32 | +using Volo.Abp.Modularity; |
| 33 | + |
| 34 | +[DependsOn(typeof(AbpAIModule))] |
| 35 | +public class MyProjectModule : AbpModule |
| 36 | +{ |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +## Usage |
| 41 | + |
| 42 | +### Chat Client |
| 43 | + |
| 44 | +#### Default configuration (quick start) |
| 45 | + |
| 46 | +Configure the default workspace to inject `IChatClient` directly. |
| 47 | + |
| 48 | +```csharp |
| 49 | +using Microsoft.Extensions.AI; |
| 50 | +using Microsoft.SemanticKernel; |
| 51 | +using Volo.Abp.AI; |
| 52 | +using Volo.Abp.Modularity; |
| 53 | + |
| 54 | +public class MyProjectModule : AbpModule |
| 55 | +{ |
| 56 | + public override void ConfigureServices(ServiceConfigurationContext context) |
| 57 | + { |
| 58 | + context.Services.PreConfigure<AbpAIOptions>(options => |
| 59 | + { |
| 60 | + options.Workspaces.ConfigureDefault(configuration => |
| 61 | + { |
| 62 | + configuration.ConfigureChatClient(chatClientConfiguration => |
| 63 | + { |
| 64 | + chatClientConfiguration.Builder = new ChatClientBuilder( |
| 65 | + sp => new OllamaApiClient("http://localhost:11434", "mistral") |
| 66 | + ); |
| 67 | + }); |
| 68 | + |
| 69 | + // Chat client only in this quick start |
| 70 | + }); |
| 71 | + }); |
| 72 | + } |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +Once configured, inject the default chat client: |
| 77 | + |
| 78 | +```csharp |
| 79 | +using Microsoft.Extensions.AI; |
| 80 | + |
| 81 | +public class MyService |
| 82 | +{ |
| 83 | + private readonly IChatClient _chatClient; // default chat client |
| 84 | +
|
| 85 | + public MyService(IChatClient chatClient) |
| 86 | + { |
| 87 | + _chatClient = chatClient; |
| 88 | + } |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +#### Workspace configuration |
| 93 | + |
| 94 | +Workspaces allow multiple, isolated AI configurations. Define workspace types (optionally decorated with `WorkspaceNameAttribute`). If omitted, the type’s full name is used. |
| 95 | + |
| 96 | +```csharp |
| 97 | +using Volo.Abp.AI; |
| 98 | + |
| 99 | +[WorkspaceName("GreetingAssistant")] |
| 100 | +public class GreetingAssistant // ChatClient-only workspace |
| 101 | +{ |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +Configure a ChatClient workspace: |
| 106 | + |
| 107 | +```csharp |
| 108 | +public class MyProjectModule : AbpModule |
| 109 | +{ |
| 110 | + public override void ConfigureServices(ServiceConfigurationContext context) |
| 111 | + { |
| 112 | + context.Services.PreConfigure<AbpAIOptions>(options => |
| 113 | + { |
| 114 | + options.Workspaces.Configure<GreetingAssistant>(configuration => |
| 115 | + { |
| 116 | + configuration.ConfigureChatClient(chatClientConfiguration => |
| 117 | + { |
| 118 | + chatClientConfiguration.Builder = new ChatClientBuilder( |
| 119 | + sp => new OllamaApiClient("http://localhost:11434", "mistral") |
| 120 | + ); |
| 121 | + |
| 122 | + chatClientConfiguration.BuilderConfigurers.Add(builder => |
| 123 | + { |
| 124 | + // Anything you want to do with the builder: |
| 125 | + // builder.UseFunctionInvocation().UseLogging(); // For example |
| 126 | + }); |
| 127 | + }); |
| 128 | + }); |
| 129 | + }); |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +### Semantic Kernel |
| 135 | + |
| 136 | +#### Default configuration |
| 137 | + |
| 138 | + |
| 139 | +```csharp |
| 140 | +public class MyProjectModule : AbpModule |
| 141 | +{ |
| 142 | + public override void ConfigureServices(ServiceConfigurationContext context) |
| 143 | + { |
| 144 | + context.Services.PreConfigure<AbpAIOptions>(options => |
| 145 | + { |
| 146 | + options.Workspaces.ConfigureDefault(configuration => |
| 147 | + { |
| 148 | + configuration.ConfigureKernel(kernelConfiguration => |
| 149 | + { |
| 150 | + kernelConfiguration.Builder = Kernel.CreateBuilder() |
| 151 | + .AddAzureOpenAIChatClient("...", "..."); |
| 152 | + }); |
| 153 | + // Note: Chat client is not configured here |
| 154 | + }); |
| 155 | + }); |
| 156 | + } |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +Once configured, inject the default kernel: |
| 161 | + |
| 162 | +```csharp |
| 163 | +using System.Threading.Tasks; |
| 164 | +using Volo.Abp.AI; |
| 165 | + |
| 166 | +public class MyService |
| 167 | +{ |
| 168 | + private readonly IKernelAccessor _kernelAccessor; |
| 169 | + public MyService(IKernelAccessor kernelAccessor) |
| 170 | + { |
| 171 | + _kernelAccessor = kernelAccessor; |
| 172 | + } |
| 173 | + |
| 174 | + public async Task DoSomethingAsync() |
| 175 | + { |
| 176 | + var kernel = _kernelAccessor.Kernel; // Kernel might be null if no workspace is configured. |
| 177 | +
|
| 178 | + var result = await kernel.InvokeAsync(/*... */); |
| 179 | + } |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +#### Workspace configuration |
| 184 | + |
| 185 | +```csharp |
| 186 | +public class MyProjectModule : AbpModule |
| 187 | +{ |
| 188 | + public override void ConfigureServices(ServiceConfigurationContext context) |
| 189 | + { |
| 190 | + context.Services.PreConfigure<AbpAIOptions>(options => |
| 191 | + { |
| 192 | + options.Workspaces.Configure<ContentPlanner>(configuration => |
| 193 | + { |
| 194 | + configuration.ConfigureKernel(kernelConfiguration => |
| 195 | + { |
| 196 | + kernelConfiguration.Builder = Kernel.CreateBuilder() |
| 197 | + .AddOpenAIChatCompletion("...", "..."); |
| 198 | + }); |
| 199 | + }); |
| 200 | + }); |
| 201 | + } |
| 202 | +} |
| 203 | +``` |
| 204 | + |
| 205 | +#### Workspace usage |
| 206 | + |
| 207 | +```csharp |
| 208 | +using Microsoft.Extensions.AI; |
| 209 | +using Volo.Abp.AI; |
| 210 | +using Microsoft.SemanticKernel; |
| 211 | + |
| 212 | +public class PlanningService |
| 213 | +{ |
| 214 | + private readonly IKernelAccessor<ContentPlanner> _kernelAccessor; |
| 215 | + private readonly IChatClient<ContentPlanner> _chatClient; // available even if only Kernel is configured |
| 216 | +
|
| 217 | + public PlanningService( |
| 218 | + IKernelAccessor<ContentPlanner> kernelAccessor, |
| 219 | + IChatClient<ContentPlanner> chatClient) |
| 220 | + { |
| 221 | + _kernelAccessor = kernelAccessor; |
| 222 | + _chatClient = chatClient; |
| 223 | + } |
| 224 | + |
| 225 | + public async Task<string> PlanAsync(string topic) |
| 226 | + { |
| 227 | + var kernel = _kernelAccessor.Kernel; // Microsoft.SemanticKernel.Kernel |
| 228 | + // Use Semantic Kernel APIs if needed... |
| 229 | +
|
| 230 | + var response = await _chatClient.GetResponseAsync( |
| 231 | + [new ChatMessage(ChatRole.User, $"Create a content plan for: {topic}")] |
| 232 | + ); |
| 233 | + return response?.Message?.Text ?? string.Empty; |
| 234 | + } |
| 235 | +} |
| 236 | +``` |
| 237 | + |
| 238 | +## Options |
| 239 | + |
| 240 | +`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. |
| 241 | + |
| 242 | +`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. |
| 243 | + |
| 244 | +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). |
| 245 | + |
| 246 | + |
| 247 | +## Advanced Usage and Customizations |
| 248 | + |
| 249 | +### Addding Your Own DelegatingChatClient |
| 250 | + |
| 251 | +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(...)`. |
| 252 | + |
| 253 | +Example sketch: |
| 254 | + |
| 255 | +```csharp |
| 256 | +using Microsoft.Extensions.AI; |
| 257 | + |
| 258 | +public class SystemMessageChatClient : DelegatingChatClient |
| 259 | +{ |
| 260 | + public SystemMessageChatClient(IChatClient inner, string systemMessage) : base(inner) |
| 261 | + { |
| 262 | + SystemMessage = systemMessage; |
| 263 | + } |
| 264 | + |
| 265 | + public string SystemMessage { get; set; } |
| 266 | + |
| 267 | + public override Task<ChatResponse> GetResponseAsync(IEnumerable<ChatMessage> messages, ChatOptions? options = null, CancellationToken cancellationToken = default) |
| 268 | + { |
| 269 | + // Mutate messages/options as needed, then call base |
| 270 | + return base.GetResponseAsync(messages, options, cancellationToken); |
| 271 | + } |
| 272 | +} |
| 273 | + |
| 274 | +public static class SystemMessageChatClientExtensions |
| 275 | +{ |
| 276 | + public static ChatClientBuilder UseSystemMessage(this ChatClientBuilder builder, string systemMessage) |
| 277 | + { |
| 278 | + return builder.Use(client => new SystemMessageChatClient(client, systemMessage)); |
| 279 | + } |
| 280 | +} |
| 281 | +``` |
| 282 | + |
| 283 | + |
| 284 | +```cs |
| 285 | +chatClientConfiguration.BuilderConfigurers.Add(builder => |
| 286 | +{ |
| 287 | + builder.UseSystemMessage("You are a helpful assistant that greets users in a friendly manner with their names."); |
| 288 | +}); |
| 289 | +``` |
| 290 | + |
| 291 | +## Technical Anatomy |
| 292 | + |
| 293 | +- `AbpAIModule`: Wires up configured workspaces, registers keyed services and default services for the `"Default"` workspace. |
| 294 | +- `AbpAIOptions`: Holds `Workspaces` and provides helper methods for internal keyed service naming. |
| 295 | +- `WorkspaceConfigurationDictionary` and `WorkspaceConfiguration`: Configure per-workspace Chat Client and Kernel. |
| 296 | +- `ChatClientConfiguration` and `KernelConfiguration`: Hold builders and a list of ordered builder configurers. |
| 297 | +- `WorkspaceNameAttribute`: Names a workspace; falls back to the type’s full name if not specified. |
| 298 | +- `IChatClient<TWorkspace>`: Typed chat client for a workspace. |
| 299 | +- `IKernelAccessor<TWorkspace>`: Provides access to the workspace’s `Kernel` instance if configured. |
| 300 | +- `AbpAIWorkspaceOptions`: Exposes `ConfiguredWorkspaceNames` for diagnostics. |
| 301 | + |
| 302 | +There are no database tables for this feature; it is a pure configuration and DI integration layer. |
| 303 | + |
| 304 | +## See Also |
| 305 | + |
| 306 | +- Microsoft.Extensions.AI (Chat Client) |
| 307 | +- Microsoft Semantic Kernel |
0 commit comments