Using Semantic Kernel in the ABP Framework
Using Semantic Kernel in an ABP Framework
This guide demonstrates how to integrate Microsoft's Semantic Kernel SDK with the ABP.io framework. It includes a wrapper implementation to help you create AI-powered plugins for your ABP application services in a clean, modular way.
🏗️ Architecture Overview
The solution consists of two primary modules:
WafiOpenAISemanticKernelModule
Core module that provides integration with Semantic Kernel.WafiSmartHRAIPluginModule
Sample implementation module demonstrating how to create AI plugins for business entities.
⚙️ Implementation Steps
Follow these steps to integrate Semantic Kernel into your ABP application.
🔹 Step 1: Add the Package to Your HttpApi Project
- Add the Semantic Kernel wrapper package:
dotnet add YourApp.HttpApi.csproj package Wafi.Abp.OpenAISemanticKernel
- Add the module dependency and configure Semantic Kernel options:
This connects your ABP module with the Semantic Kernel framework and sets up OpenAI credentials.
[DependsOn(
// your existing dependencies
typeof(WafiOpenAISemanticKernelModule)
)]
public class YourAppHttpApiModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<WafiOpenAISemanticKernelOptions>(options =>
{
options.ModelId = configuration.GetValue<string>("SemanticKernel:OpenAI:ModelId");
options.ApiKey = configuration.GetValue<string>("SemanticKernel:OpenAI:ApiKey");
});
}
}
- Add the following configuration to your appsettings.json:
{
"SemanticKernel": {
"OpenAI": {
"ApiKey": "your-openai-key",
"ModelId": "gpt-4"
}
}
}
✅ This exposes the
/api/OpenAISemanticKernel/ai/ask
endpoint automatically, which the chat interface will use to interact with Semantic Kernel.
🔹 Step 2: Implement a Chat Interface
In your Web project, create a chat interface to interact with the /ai/ask
API. You can refer to the host/Wafi.SmartHR.Web
project for a sample implementation.
🔹 Step 3: Build Plugins to Connect ABP Services with Semantic Kernel
1. Add dependencies to the plugin project:
dotnet add package Wafi.Abp.OpenAISemanticKernel
dotnet add reference ../YourApp.Application/YourApp.Application.csproj
Add this to your plugin module class:
[DependsOn(typeof(YourAppApplicationModule))]
public class YourAppAIPluginModule : AbpModule
{
// ...
}
2. Create AI Plugins for Your Entities
Each plugin class should clearly describe what the AI will get when calling its methods.
📄 Example: YourEntityPlugin.cs
public class YourEntityPlugin : ApplicationService, ITransientDependency
{
private readonly IYourEntityAppService _entityService;
private readonly IAuthorizationService _authorizationService;
public YourEntityPlugin(
IYourEntityAppService entityService,
IAuthorizationService authorizationService)
{
_entityService = entityService;
_authorizationService = authorizationService;
}
[KernelFunction]
[Description("Search for entities by name or any relevant property using a keyword or phrase")]
public async Task<string> SearchEntitiesAsync(string filter)
{
if (!await _authorizationService.IsGrantedAsync(YourPermissions.Default))
{
return "You are not authorized to access this data";
}
var entities = await _entityService.GetListAsync(filter);
if (entities is null || entities.Items.Count == 0)
{
return $"No entities found for filter '{filter}'";
}
return JsonSerializer.Serialize(entities);
}
}
🧠 Be sure to give a meaningful
[Description]
so that the AI knows exactly what this method does.
3. Create a Plugin Provider
Create a provider class to register your plugin with Semantic Kernel. This is a crucial step that makes your plugin discoverable by the AI system.
using Wafi.Abp.OpenAISemanticKernel.Plugins;
using YourApp.AI.Plugin.YourEntities;
namespace YourApp.AI.Plugin
{
public class YourEntityPluginProvider : SemanticPluginProviderBase<YourEntityPlugin>, IWafiPluginProvider
{
public YourEntityPluginProvider(YourEntityPlugin plugin) : base(plugin) { }
public override string Name => "Your Plugin Name";
}
}
🔐 Authorization
All requests are protected by ABP's permission system. If a user doesn't have the required permissions, they will receive an appropriate message:
⚠️ You are not authorized to access this data.
The authorization check is performed in each plugin method:
if (!await _authorizationService.IsGrantedAsync(YourPermissions.Default))
{
return "You are not authorized to access this data";
}
✅ Final Outcome
After completing these steps, your ABP application will have a fully functioning AI assistant powered by Semantic Kernel.
The AI interface can be accessed through the /askai
endpoint in your web application. When users send questions to this endpoint, the system:
- Processes the natural language query
- Determines which registered plugins can fulfill the request
- Calls the appropriate application services through the plugins
- Returns formatted results to the user
Example 1: Employee List Query
Request:
POST /askai
Content-Type: application/json
{
"question": "Give me the list of employees"
}
Response:
Here is the list of employees: John Doe - Email: john.doe@example.com - Phone: 1234567890 - Date of Birth: January 1, 1990 - Joining Date: January 1, 2020 - Total Leave Days: 20 - Remaining Leave Days: 20. Jane Smith - Email: jane.smith@example.com - Phone: 0987654321 - Date of Birth: February 1, 1991 - Joining Date: February 1, 2021 - Total Leave Days: 20 - Remaining Leave Days: 15
Example 2: Leave Records Query
Request:
POST /askai
Content-Type: application/json
{
"question": "Give me the list of employee leave records"
}
Response:
Here is the list of employee leave records: John Doe - Annual leave from January 1 to January 5, 2025 (5 days) - Sick leave from March 15 to March 16, 2025 (2 days)\n - Personal leave from June 1 to June 3, 2025 (3 days) Jane Smith - Sick leave from February 1 to February 3, 2025 (3 days) - Annual leave from July 1 to July 10, 2025 (10 days)"
📚 Additional Resources
For a deeper understanding of the module's implementation, architecture decisions, and advanced customization options, see:
Comments
Alper Ebiçoğlu 6 days ago
Can you also add the implementation of IYourEntityAppService
Mohammad Eunus 6 days ago
That's a great idea! I think it's possible to use the CrudAppService<> in the plugins. This will make the plugin implementation much simpler.
Enis Necipoğlu 6 days ago
I deleted my first comment by mistake while trying to edit.
I assumed this logic could work pretty well with standard CrudAppService<>
Ariful Islam 6 days ago
CrudAppService<> will also work. For example, EmployeePlugin is an AppService-
public class EmployeePlugin(IEmployeeAppService employeeService, IAuthorizationService authorizationService) : ApplicationService, ITransientDependency
But you must override the CRUD methods for the [KernelFunction] description.
Halil İbrahim Kalkan 6 days ago
Great article. Thanks for sharing.
Yousef Hussein 4 days ago
Great article. Thanks brother Arif.