using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using AI.Filter;
using AI.KnowledgeBase;
using AI.Plugin;
using AI.AgentIntegration;
using AI.Models;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using AI.Interface;
namespace AI.Service
{
///
/// 提供全局唯一的 实例,负责初始化模型与插件注册。
///
public class KernelService : IChatBackend
{
///
/// Gets 获取当前应用的全局 实例。
///
public Kernel? Kernel { get; private set; }
///
/// 对话 Service
///
public IChatCompletionService? ChatCompletionService { get; private set; }
private readonly IKernelBuilder builder;
private bool _isBuilt = false;
///
/// 构造函数。从 ai-settings.json 加载配置并初始化 Kernel Builder。
///
public KernelService()
{
var settings = AISettings.Load();
builder = Kernel.CreateBuilder();
builder.Services.AddOpenAIChatCompletion(
modelId: settings.ModelId,
apiKey: settings.ApiKey,
endpoint: new Uri(settings.Endpoint));
// 注册 Filter
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
}
///
/// 调用指定插件的指定函数。
///
/// 插件名称。
/// 函数名称。
/// 调用参数。
/// 函数执行结果文本。
/// 当插件或函数名称无效时抛出。
public async Task InvokeAsync(string plugin, string function, KernelArguments? args = null)
{
var result = await Kernel.InvokeAsync(plugin, function, args ?? []);
return result.ToString() ?? string.Empty;
}
///
/// 向模型发送自然语言请求,让模型自动决定是否调用已注册的工具。
///
/// 自然语言输入。
/// 聊天会话。如果为 null,将创建新的会话。
/// 取消令牌,用于取消请求或配合超时。
/// 模型的响应文本。
/// 当输入为空时抛出。
/// 当 Kernel 未初始化时抛出。
public async Task AskAsync(string input, ChatSession? session = null, string? guidePrompt = null, CancellationToken cancellationToken = default)
{
if (Kernel == null || ChatCompletionService == null)
{
throw new InvalidOperationException("KernelService 尚未初始化,请先调用 Build() 方法。");
}
session ??= new ChatSession();
CurrentSessionContext.Current = session;
try
{
session.AddUserMessage(input);
Debug.WriteLine($"Session [{session.Id}]: {input}");
var executionSettings = new OpenAIPromptExecutionSettings()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions,
Temperature = 0.3f,
TopP = 0.9f,
};
var historyForLlm = session.GetHistoryForLlm(guidePrompt);
LogHistoryForLlm(session.Id, historyForLlm);
ChatMessageContent response = await ChatCompletionService.GetChatMessageContentAsync(
historyForLlm,
executionSettings,
Kernel!,
cancellationToken);
string responseMessage = response.Content ?? "没有回复";
Debug.WriteLine($"Session [{session.Id}] Response: {responseMessage}");
session.AddAssistantMessage(responseMessage);
return responseMessage;
}
finally
{
CurrentSessionContext.Current = null;
}
}
///
/// 流式向模型发送自然语言请求
///
/// 自然语言输入
/// 聊天会话。如果为 null,将创建新的会话。
/// 取消令牌,用于取消请求或配合超时。
/// 当 Kernel 未初始化时抛出。
public async IAsyncEnumerable AskStreamAsync(string input, ChatSession? session = null, string? guidePrompt = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (Kernel == null || ChatCompletionService == null)
{
throw new InvalidOperationException("KernelService 尚未初始化,请先调用 Build() 方法。");
}
session ??= new ChatSession();
CurrentSessionContext.Current = session;
try
{
session.AddUserMessage(input);
var executionSettings = new OpenAIPromptExecutionSettings()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions,
Temperature = 0.3f,
TopP = 0.9f,
};
var historyForLlm = session.GetHistoryForLlm(guidePrompt);
LogHistoryForLlm(session.Id, historyForLlm);
var fullResponse = new StringBuilder();
await foreach (var content in ChatCompletionService.GetStreamingChatMessageContentsAsync(historyForLlm, executionSettings, Kernel!, cancellationToken))
{
if (!string.IsNullOrWhiteSpace(content.Content))
{
fullResponse.Append(content.Content);
yield return content.Content;
}
}
// 流式响应完成后,通过 ChatSession 添加助手消息
if (fullResponse.Length > 0)
{
session.AddAssistantMessage(fullResponse.ToString());
}
}
finally
{
CurrentSessionContext.Current = null;
}
}
///
/// 初始化 KernelService:注册插件并构建 Kernel。
/// 这是推荐的初始化方式,一次性完成所有初始化步骤。
///
/// 应用控制器实例
/// 表单请求通知器(可选,为 null 时不注册表单插件)
/// 当 appController 为 null 时抛出
/// 当 Kernel 已经构建时抛出
public void Initialize(IAppController appController, IFormRequestNotifier? formNotifier = null)
{
ArgumentNullException.ThrowIfNull(appController);
if (_isBuilt)
{
throw new InvalidOperationException("Kernel 已经构建,无法重新初始化。");
}
RegisterController(appController, formNotifier);
Build();
_isBuilt = true;
}
///
/// 注册带 的类,以及 Prompt 工具。
/// 必须在 Build() 之前调用。
///
/// 应用实例
/// 表单请求通知器(可选)
/// 如果 Kernel 已经构建,则抛出异常
private void RegisterController(IAppController appController, IFormRequestNotifier? formNotifier = null)
{
var appStatePlugin = new AppStatePlugin(appController);
var importPlugin = new ImportPlugin(appController);
var simpleKnowledgeBase = new SimpleKnowledgeBase();
var knowledgeBasePlugin = new KnowledgeBasePlugin(simpleKnowledgeBase);
builder.Plugins.AddFromObject(appStatePlugin, "AppState");
builder.Plugins.AddFromObject(importPlugin, "Import");
builder.Plugins.AddFromObject(knowledgeBasePlugin, "KnowledgeBase");
if (formNotifier != null)
{
var formRequestPlugin = new FormRequestPlugin(formNotifier);
builder.Plugins.AddFromObject(formRequestPlugin, "FormRequest");
}
}
///
/// 构建 Kernel 实例。在调用此方法之前,必须调用 RegisterController() 或 Initialize() 注册插件。
///
/// 如果插件未注册,则抛出异常
private void Build()
{
Kernel = builder.Build();
ChatCompletionService = Kernel.GetRequiredService();
}
private const int MaxLoggedContentLength = 300;
///
/// 将发给 LLM 的 ChatHistory 按条输出到 Debug,便于排查「到底发给模型什么」。
///
private static void LogHistoryForLlm(string sessionId, ChatHistory history)
{
if (history == null)
{
return;
}
Debug.WriteLine($"[Session {sessionId}] History for LLM ({history.Count} messages):");
for (int i = 0; i < history.Count; i++)
{
var msg = history[i];
var role = msg.Role.ToString() ?? "?";
var content = msg.Content ?? string.Empty;
Debug.WriteLine($" [{i}] {role}: {content}");
}
}
}
}