mirror of https://github.com/abpframework/abp.git
3 changed files with 312 additions and 159 deletions
@ -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<AbpAIOptions>(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<AbpAIOptions>(options => |
||||
|
{ |
||||
|
options.Workspaces.Configure<GreetingAssistant>(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<AbpAIOptions>(options => |
||||
|
{ |
||||
|
options.Workspaces.Configure<ContentPlanner>(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<GreetingAssistant> _chatClient; |
||||
|
|
||||
|
public GreetingService(IChatClient<GreetingAssistant> chatClient) |
||||
|
{ |
||||
|
_chatClient = chatClient; |
||||
|
} |
||||
|
|
||||
|
public async Task<string> 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<ContentPlanner> _kernelAccessor; |
||||
|
private readonly IChatClient<ContentPlanner> _chatClient; // available even if only Kernel is configured |
||||
|
|
||||
|
public PlanningService( |
||||
|
IKernelAccessor<ContentPlanner> kernelAccessor, |
||||
|
IChatClient<ContentPlanner> chatClient) |
||||
|
{ |
||||
|
_kernelAccessor = kernelAccessor; |
||||
|
_chatClient = chatClient; |
||||
|
} |
||||
|
|
||||
|
public async Task<string> 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<TWorkspace>(Action<WorkspaceConfiguration>)` |
||||
|
- `Configure(string name, Action<WorkspaceConfiguration>)` |
||||
|
|
||||
|
- `WorkspaceConfiguration` per workspace: |
||||
|
- `ChatClient`: `ChatClientConfiguration` |
||||
|
- `Builder`: `ChatClientBuilder?` |
||||
|
- `ConfigureBuilder(Action<ChatClientBuilder>)` |
||||
|
- `ConfigureBuilder(string name, Action<ChatClientBuilder>)` (named actions executed in order) |
||||
|
- `Kernel`: `KernelConfiguration` |
||||
|
- `Builder`: `IKernelBuilder?` |
||||
|
- `ConfigureBuilder(Action<IKernelBuilder>)` |
||||
|
- `ConfigureBuilder(string name, Action<IKernelBuilder>)` |
||||
|
|
||||
|
- `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<ChatResponse> GetResponseAsync(IEnumerable<ChatMessage> 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<TWorkspace>`: Typed chat client for a workspace. |
||||
|
- `IKernelAccessor<TWorkspace>`: 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 |
||||
@ -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<TWorkSpace>`, `IKernel<TWorkSpace>`) 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<AbpAIOptions>`). 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<AbpAIOptions>(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: "<OPENAI_API_KEY>"); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
// Default Kernel (inject Kernel) |
|
||||
options.Kernels.ConfigureDefault(cfg => |
|
||||
{ |
|
||||
var kb = Kernel.CreateBuilder(); |
|
||||
// Example: OpenAI connector (Microsoft.SemanticKernel.Connectors.OpenAI) |
|
||||
kb.AddOpenAIChatCompletion("gpt-4o-mini", "<OPENAI_API_KEY>"); |
|
||||
cfg.Builder = kb; |
|
||||
}); |
|
||||
|
|
||||
// Workspace-scoped ChatClient (inject IChatClient<CommentSummarizer>) |
|
||||
options.ChatClients.Configure<CommentSummarizer>(cfg => |
|
||||
{ |
|
||||
cfg.Builder = new ChatClientBuilder(); |
|
||||
cfg.ConfigureBuilder(b => b.UseOpenAIChatClient("gpt-4o-mini", "<OPENAI_API_KEY>")); |
|
||||
}); |
|
||||
|
|
||||
// Workspace-scoped Kernel (inject IKernel<CommentSummarizer>) |
|
||||
options.Kernels.Configure<CommentSummarizer>(cfg => |
|
||||
{ |
|
||||
var kb = Kernel.CreateBuilder(); |
|
||||
kb.AddOpenAIChatCompletion("gpt-4o-mini", "<OPENAI_API_KEY>"); |
|
||||
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<CommentSummarizer> _chatClient; |
|
||||
private readonly IKernel<CommentSummarizer> _kernel; |
|
||||
|
|
||||
public CommentSummarizerService( |
|
||||
IChatClient<CommentSummarizer> chatClient, |
|
||||
IKernel<CommentSummarizer> kernel) |
|
||||
{ |
|
||||
_chatClient = chatClient; |
|
||||
_kernel = kernel; |
|
||||
} |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
Access the original Semantic Kernel instance via `IKernel<TWorkSpace>.Kernel`: |
|
||||
|
|
||||
```csharp |
|
||||
public class KernelUsage |
|
||||
{ |
|
||||
private readonly IKernel<CommentSummarizer> _workspaceKernel; |
|
||||
|
|
||||
public KernelUsage(IKernel<CommentSummarizer> 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<YourWorkspace>(...)`. |
|
||||
- Only Kernel per workspace: configure `options.Kernels.Configure<YourWorkspace>(...)`. |
|
||||
- Single global setup: just use `ConfigureDefault` for either or both; inject the default services. |
|
||||
|
|
||||
### Terminology |
|
||||
|
|
||||
- `WorkspaceNameAttribute`: names a workspace; used for both stacks. |
|
||||
- `IChatClient<TWorkSpace>` and `IKernel<TWorkSpace>`: typed services bound to a workspace. |
|
||||
- `IChatClient` and `Kernel`: defaults if configured via `ConfigureDefault`. |
|
||||
Loading…
Reference in new issue