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}"); } } } }