依赖注入 #

概述 #

Semantic Kernel 支持与 .NET 依赖注入(DI)系统深度集成,方便在 ASP.NET Core 等应用中使用。

基本配置 #

服务注册 #

csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;

var services = new ServiceCollection();

services.AddKernel()
    .AddOpenAIChatCompletion(
        modelId: "gpt-4",
        apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY")
    );

var serviceProvider = services.BuildServiceProvider();
var kernel = serviceProvider.GetRequiredService<Kernel>();

多服务配置 #

csharp
services.AddKernel()
    .AddOpenAIChatCompletion(
        serviceId: "openai-gpt4",
        modelId: "gpt-4",
        apiKey: "openai-key"
    )
    .AddAzureOpenAIChatCompletion(
        serviceId: "azure-gpt4",
        deploymentName: "gpt-4-deployment",
        endpoint: "https://your-resource.openai.azure.com/",
        apiKey: "azure-key"
    )
    .AddOpenAITextEmbeddingGeneration(
        modelId: "text-embedding-3-small",
        apiKey: "api-key"
    );

ASP.NET Core 集成 #

Program.cs 配置 #

csharp
using Microsoft.SemanticKernel;

var builder = WebApplication.CreateBuilder(args);

// 添加 Semantic Kernel
builder.Services.AddKernel()
    .AddAzureOpenAIChatCompletion(
        deploymentName: builder.Configuration["AzureOpenAI:DeploymentName"]!,
        endpoint: builder.Configuration["AzureOpenAI:Endpoint"]!,
        apiKey: builder.Configuration["AzureOpenAI:ApiKey"]!
    );

// 添加插件
builder.Services.AddTransient<WeatherPlugin>();
builder.Services.AddTransient<EmailPlugin>();

// 添加服务
builder.Services.AddScoped<IChatService, ChatService>();
builder.Services.AddScoped<IDocumentService, DocumentService>();

var app = builder.Build();

控制器中使用 #

csharp
[ApiController]
[Route("api/[controller]")]
public class ChatController : ControllerBase
{
    private readonly Kernel _kernel;
    private readonly IChatService _chatService;

    public ChatController(Kernel kernel, IChatService chatService)
    {
        _kernel = kernel;
        _chatService = chatService;
    }

    [HttpPost]
    public async Task<IActionResult> Chat([FromBody] ChatRequest request)
    {
        var result = await _kernel.InvokePromptAsync(request.Message);
        return Ok(new { response = result.ToString() });
    }
}

插件注册 #

方式一:自动注册 #

csharp
// 注册插件类
builder.Services.AddTransient<WeatherPlugin>();
builder.Services.AddTransient<EmailPlugin>();
builder.Services.AddTransient<DatabasePlugin>();

// Kernel 会自动解析依赖

方式二:工厂注册 #

csharp
builder.Services.AddTransient<Kernel>(sp =>
{
    var kernel = Kernel.Builder()
        .AddOpenAIChatCompletion("gpt-4", "api-key")
        .Build();

    // 手动添加插件
    kernel.Plugins.AddFromType<WeatherPlugin>();
    kernel.Plugins.AddFromType<EmailPlugin>();

    return kernel;
});

方式三:配置式注册 #

csharp
public class KernelConfigurator
{
    public static void Configure(IServiceCollection services, IConfiguration configuration)
    {
        services.AddKernel()
            .AddAzureOpenAIChatCompletion(
                deploymentName: configuration["AzureOpenAI:DeploymentName"]!,
                endpoint: configuration["AzureOpenAI:Endpoint"]!,
                apiKey: configuration["AzureOpenAI:ApiKey"]!
            );

        // 根据配置注册插件
        var enabledPlugins = configuration.GetSection("Plugins").Get<string[]>();
        
        foreach (var plugin in enabledPlugins ?? Array.Empty<string>())
        {
            switch (plugin)
            {
                case "Weather":
                    services.AddTransient<WeatherPlugin>();
                    break;
                case "Email":
                    services.AddTransient<EmailPlugin>();
                    break;
            }
        }
    }
}

服务注入 #

在插件中注入服务 #

csharp
public class DatabasePlugin
{
    private readonly IDatabaseService _db;
    private readonly ILogger<DatabasePlugin> _logger;

    public DatabasePlugin(
        IDatabaseService db,
        ILogger<DatabasePlugin> logger)
    {
        _db = db;
        _logger = logger;
    }

    [KernelFunction("query")]
    public async Task<string> QueryAsync(string sql)
    {
        _logger.LogInformation("执行查询: {SQL}", sql);
        return await _db.ExecuteQueryAsync(sql);
    }
}

在服务中使用 Kernel #

csharp
public class ChatService : IChatService
{
    private readonly Kernel _kernel;
    private readonly IChatHistoryRepository _historyRepo;
    private readonly ILogger<ChatService> _logger;

    public ChatService(
        Kernel kernel,
        IChatHistoryRepository historyRepo,
        ILogger<ChatService> logger)
    {
        _kernel = kernel;
        _historyRepo = historyRepo;
        _logger = logger;
    }

    public async Task<string> ChatAsync(string userId, string message)
    {
        // 获取历史
        var history = await _historyRepo.GetHistoryAsync(userId);
        
        // 构建上下文
        var chatHistory = new ChatHistory();
        chatHistory.AddSystemMessage("你是一个友好的助手。");
        
        foreach (var msg in history)
        {
            chatHistory.AddUserMessage(msg.UserMessage);
            chatHistory.AddAssistantMessage(msg.AssistantMessage);
        }
        
        chatHistory.AddUserMessage(message);

        // 获取回复
        var chatService = _kernel.GetRequiredService<IChatCompletionService>();
        var response = await chatService.GetChatMessageContentAsync(chatHistory);

        // 保存历史
        await _historyRepo.SaveHistoryAsync(userId, message, response.Content!);

        return response.Content!;
    }
}

配置管理 #

appsettings.json #

json
{
    "SemanticKernel": {
        "Provider": "AzureOpenAI",
        "AzureOpenAI": {
            "Endpoint": "https://your-resource.openai.azure.com/",
            "DeploymentName": "gpt-4-deployment",
            "ApiKey": ""
        },
        "OpenAI": {
            "ModelId": "gpt-4",
            "ApiKey": "",
            "OrgId": ""
        },
        "Embedding": {
            "ModelId": "text-embedding-3-small"
        }
    },
    "Plugins": ["Weather", "Email", "Database"]
}

配置类 #

csharp
public class SemanticKernelOptions
{
    public string Provider { get; set; } = "OpenAI";
    public AzureOpenAIOptions AzureOpenAI { get; set; } = new();
    public OpenAIOptions OpenAI { get; set; } = new();
    public EmbeddingOptions Embedding { get; set; } = new();
}

public class AzureOpenAIOptions
{
    public string Endpoint { get; set; } = "";
    public string DeploymentName { get; set; } = "";
    public string ApiKey { get; set; } = "";
}

public class OpenAIOptions
{
    public string ModelId { get; set; } = "gpt-4";
    public string ApiKey { get; set; } = "";
    public string? OrgId { get; set; }
}

public class EmbeddingOptions
{
    public string ModelId { get; set; } = "text-embedding-3-small";
}

配置绑定 #

csharp
builder.Services.Configure<SemanticKernelOptions>(
    builder.Configuration.GetSection("SemanticKernel"));

// 使用配置
builder.Services.AddKernelServices(builder.Configuration);

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddKernelServices(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        var options = configuration.GetSection("SemanticKernel")
            .Get<SemanticKernelOptions>();

        var kernelBuilder = services.AddKernel();

        switch (options.Provider)
        {
            case "AzureOpenAI":
                kernelBuilder.AddAzureOpenAIChatCompletion(
                    options.AzureOpenAI.DeploymentName,
                    options.AzureOpenAI.Endpoint,
                    options.AzureOpenAI.ApiKey
                );
                break;

            case "OpenAI":
                kernelBuilder.AddOpenAIChatCompletion(
                    options.OpenAI.ModelId,
                    options.OpenAI.ApiKey,
                    options.OpenAI.OrgId
                );
                break;
        }

        kernelBuilder.AddOpenAITextEmbeddingGeneration(
            options.Embedding.ModelId,
            options.OpenAI.ApiKey
        );

        return services;
    }
}

作用域管理 #

Scoped Kernel #

csharp
// 每个 Scope 创建新的 Kernel 实例
builder.Services.AddScoped<Kernel>(sp =>
{
    var configuration = sp.GetRequiredService<IConfiguration>();
    
    return Kernel.CreateBuilder()
        .AddOpenAIChatCompletion(
            configuration["OpenAI:ModelId"]!,
            configuration["OpenAI:ApiKey"]!
        )
        .Build();
});

Singleton Kernel #

csharp
// 全局共享 Kernel 实例
builder.Services.AddSingleton<Kernel>(sp =>
{
    var configuration = sp.GetRequiredService<IConfiguration>();
    
    return Kernel.CreateBuilder()
        .AddOpenAIChatCompletion(
            configuration["OpenAI:ModelId"]!,
            configuration["OpenAI:ApiKey"]!
        )
        .Build();
});

测试支持 #

模拟 Kernel #

csharp
public class MockKernelBuilder
{
    public static Kernel BuildMockKernel()
    {
        var mockChatService = new Mock<IChatCompletionService>();
        mockChatService
            .Setup(s => s.GetChatMessageContentsAsync(
                It.IsAny<ChatHistory>(),
                It.IsAny<PromptExecutionSettings>(),
                It.IsAny<Kernel>(),
                It.IsAny<CancellationToken>()))
            .ReturnsAsync(new List<ChatMessageContent>
            {
                new(AuthorRole.Assistant, "模拟响应")
            });

        var kernel = new Kernel();
        kernel.AddService(mockChatService.Object);

        return kernel;
    }
}

测试示例 #

csharp
public class ChatServiceTests
{
    private readonly Kernel _mockKernel;
    private readonly Mock<IChatHistoryRepository> _mockRepo;
    private readonly ChatService _service;

    public ChatServiceTests()
    {
        _mockKernel = MockKernelBuilder.BuildMockKernel();
        _mockRepo = new Mock<IChatHistoryRepository>();
        _service = new ChatService(_mockKernel, _mockRepo.Object);
    }

    [Fact]
    public async Task ChatAsync_ReturnsResponse()
    {
        var result = await _service.ChatAsync("user1", "你好");
        
        Assert.NotNull(result);
    }
}

最佳实践 #

1. 使用配置文件 #

csharp
// 推荐:使用配置
builder.Services.AddKernel()
    .AddOpenAIChatCompletion(
        configuration["OpenAI:ModelId"]!,
        configuration["OpenAI:ApiKey"]!
    );

// 避免:硬编码
builder.Services.AddKernel()
    .AddOpenAIChatCompletion("gpt-4", "hardcoded-key");

2. 安全存储密钥 #

csharp
// 使用 Azure Key Vault
builder.Services.AddAzureClients(builder =>
{
    builder.AddSecretClient(builder.Configuration.GetSection("KeyVault"));
});

// 或使用环境变量
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");

3. 合理的生命周期 #

csharp
// Kernel: Singleton(共享连接池)
builder.Services.AddSingleton<Kernel>();

// 服务: Scoped(每个请求)
builder.Services.AddScoped<IChatService, ChatService>();

// 插件: Transient(每次创建)
builder.Services.AddTransient<WeatherPlugin>();

下一步 #

现在你已经掌握了依赖注入,接下来学习 智能聊天机器人,开始实战项目!

最后更新:2026-04-04