package org.example.service; import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; import com.alibaba.cloud.ai.graph.agent.ReactAgent; import com.alibaba.cloud.ai.graph.exception.GraphRunnerException; import org.example.agent.tool.DateTimeTools; import org.example.agent.tool.InternalDocsTools; import org.example.agent.tool.QueryLogsTools; import org.example.agent.tool.QueryMetricsTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; /** * 聊天服务 * 封装 ReactAgent 对话的公共逻辑,包括模型创建、系统提示词构建、Agent 配置等 */ @Service public class ChatService { private static final Logger logger = LoggerFactory.getLogger(ChatService.class); @Autowired private InternalDocsTools internalDocsTools; @Autowired private DateTimeTools dateTimeTools; @Autowired private QueryMetricsTools queryMetricsTools; @Autowired(required = false) // Mock 模式下才注册,所以设置为 optional,真实环境通过mcp配置注入 private QueryLogsTools queryLogsTools; @Autowired private ToolCallbackProvider tools; @Value("${spring.ai.dashscope.api-key}") private String dashScopeApiKey; /** * 创建 DashScope API 实例 */ public DashScopeApi createDashScopeApi() { return DashScopeApi.builder() .apiKey(dashScopeApiKey) .build(); } /** * 创建 ChatModel * @param temperature 控制随机性 (0.0-1.0) * @param maxToken 最大输出长度 * @param topP 核采样参数 */ public DashScopeChatModel createChatModel(DashScopeApi dashScopeApi, double temperature, int maxToken, double topP) { return DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .defaultOptions(DashScopeChatOptions.builder() .withModel(DashScopeChatModel.DEFAULT_MODEL_NAME) .withTemperature(temperature) .withMaxToken(maxToken) .withTopP(topP) .build()) .build(); } /** * 创建标准对话 ChatModel(默认参数) */ public DashScopeChatModel createStandardChatModel(DashScopeApi dashScopeApi) { return createChatModel(dashScopeApi, 0.7, 2000, 0.9); } /** * 构建系统提示词(包含历史消息) * @param history 历史消息列表 * @return 完整的系统提示词 */ public String buildSystemPrompt(List> history) { StringBuilder systemPromptBuilder = new StringBuilder(); // 基础系统提示 systemPromptBuilder.append("你是一个专业的智能助手,可以获取当前时间、查询天气信息、搜索内部文档知识库,以及查询 Prometheus 告警信息。\n"); systemPromptBuilder.append("当用户询问时间相关问题时,使用 getCurrentDateTime 工具。\n"); systemPromptBuilder.append("当用户需要查询公司内部文档、流程、最佳实践或技术指南时,使用 queryInternalDocs 工具。\n"); systemPromptBuilder.append("当用户需要查询 Prometheus 告警、监控指标或系统告警状态时,使用 queryPrometheusAlerts 工具。\n"); systemPromptBuilder.append("当用户需要查询腾讯云日志时,请调用腾讯云mcp服务查询,默认查询地域ap-guangzhou,查询时间范围为近一个月。\n\n"); // 添加历史消息 if (!history.isEmpty()) { systemPromptBuilder.append("--- 对话历史 ---\n"); for (Map msg : history) { String role = msg.get("role"); String content = msg.get("content"); if ("user".equals(role)) { systemPromptBuilder.append("用户: ").append(content).append("\n"); } else if ("assistant".equals(role)) { systemPromptBuilder.append("助手: ").append(content).append("\n"); } } systemPromptBuilder.append("--- 对话历史结束 ---\n\n"); } systemPromptBuilder.append("请基于以上对话历史,回答用户的新问题。"); return systemPromptBuilder.toString(); } /** * 动态构建方法工具数组 * 根据 cls.mock-enabled 决定是否包含 QueryLogsTools */ public Object[] buildMethodToolsArray() { if (queryLogsTools != null) { // Mock 模式:包含 QueryLogsTools return new Object[]{dateTimeTools, internalDocsTools, queryMetricsTools, queryLogsTools}; } else { // 真实模式:不包含 QueryLogsTools(由 MCP 提供日志查询功能) return new Object[]{dateTimeTools, internalDocsTools, queryMetricsTools}; } } /** * 获取工具回调列表,mcp服务提供的工具 */ public ToolCallback[] getToolCallbacks() { return tools.getToolCallbacks(); } /** * 记录可用工具列表:mcp服务提供的工具 */ public void logAvailableTools() { ToolCallback[] toolCallbacks = tools.getToolCallbacks(); logger.info("可用工具列表:"); for (ToolCallback toolCallback : toolCallbacks) { logger.info(">>> {}", toolCallback.getToolDefinition().name()); } } /** * 创建 ReactAgent * @param chatModel 聊天模型 * @param systemPrompt 系统提示词 * @return 配置好的 ReactAgent */ public ReactAgent createReactAgent(DashScopeChatModel chatModel, String systemPrompt) { return ReactAgent.builder() .name("intelligent_assistant") .model(chatModel) .systemPrompt(systemPrompt) .methodTools(buildMethodToolsArray()) .tools(getToolCallbacks()) .build(); } /** * 执行 ReactAgent 对话(非流式) * @param agent ReactAgent 实例 * @param question 用户问题 * @return AI 回复 */ public String executeChat(ReactAgent agent, String question) throws GraphRunnerException { logger.info("执行 ReactAgent.call() - 自动处理工具调用"); var response = agent.call(question); String answer = response.getText(); logger.info("ReactAgent 对话完成,答案长度: {}", answer.length()); return answer; } }