| | |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.zy.ai.domain.autotune.AutoTuneControlModeSnapshot; |
| | | import com.zy.ai.domain.autotune.AutoTuneJobStatus; |
| | | import com.zy.ai.domain.autotune.AutoTuneTriggerType; |
| | | import com.zy.ai.entity.AiAutoTuneMcpCall; |
| | | import com.zy.ai.entity.AiAutoTuneJob; |
| | | import com.zy.ai.enums.AiPromptScene; |
| | | import com.zy.ai.service.AiAutoTuneJobService; |
| | | import com.zy.ai.service.AiAutoTuneMcpCallService; |
| | | import com.zy.ai.service.AutoTuneAgentService; |
| | | import com.zy.ai.service.AutoTuneControlModeService; |
| | | import com.zy.ai.service.AutoTuneCoordinatorService; |
| | | import com.zy.asrs.entity.WrkMast; |
| | | import com.zy.asrs.service.WrkMastService; |
| | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Date; |
| | | import java.util.LinkedHashMap; |
| | |
| | | @RequiredArgsConstructor |
| | | public class AutoTuneCoordinatorServiceImpl implements AutoTuneCoordinatorService { |
| | | |
| | | private static final String CONFIG_ENABLED = "aiAutoTuneEnabled"; |
| | | private static final String CONFIG_INTERVAL_MINUTES = "aiAutoTuneIntervalMinutes"; |
| | | private static final String DEFAULT_ENABLED = "N"; |
| | | private static final int DEFAULT_INTERVAL_MINUTES = 10; |
| | | private static final int MIN_INTERVAL_MINUTES = 5; |
| | | private static final int MAX_INTERVAL_MINUTES = 60; |
| | |
| | | ); |
| | | |
| | | private final ConfigService configService; |
| | | private final AutoTuneControlModeService autoTuneControlModeService; |
| | | private final WrkMastService wrkMastService; |
| | | private final AiAutoTuneJobService aiAutoTuneJobService; |
| | | private final AiAutoTuneMcpCallService aiAutoTuneMcpCallService; |
| | | private final AutoTuneAgentService autoTuneAgentService; |
| | | private final RedisUtil redisUtil; |
| | | private final OperateLogService operateLogService; |
| | |
| | | } |
| | | |
| | | AutoTuneAgentService.AutoTuneAgentResult agentResult = null; |
| | | Date startTime = new Date(); |
| | | try { |
| | | if (writeGuard && intervalMinutes != null) { |
| | | safeMarkLastTriggerGuard(intervalMinutes); |
| | | } |
| | | agentResult = autoTuneAgentService.runAutoTune(triggerType); |
| | | safeWriteOperateLog(agentResult); |
| | | safeWriteAgentRunAudit(triggerType, startTime, agentResult); |
| | | return AutoTuneCoordinatorResult.triggered(agentResult); |
| | | } catch (Exception exception) { |
| | | log.error("Auto tune coordinator failed to run agent", exception); |
| | | agentResult = failedAgentResult(triggerType, exception); |
| | | safeWriteOperateLog(agentResult); |
| | | safeWriteAgentRunAudit(triggerType, startTime, agentResult); |
| | | return AutoTuneCoordinatorResult.triggered(agentResult); |
| | | } finally { |
| | | redisUtil.compareAndDelete(lockKey, lockToken); |
| | |
| | | } |
| | | |
| | | private boolean isEnabled() { |
| | | String enabled = configService.getConfigValue(CONFIG_ENABLED, DEFAULT_ENABLED); |
| | | if (enabled == null) { |
| | | return false; |
| | | } |
| | | String normalized = enabled.trim(); |
| | | return "Y".equalsIgnoreCase(normalized) |
| | | || "true".equalsIgnoreCase(normalized) |
| | | || "1".equals(normalized); |
| | | AutoTuneControlModeSnapshot controlMode = autoTuneControlModeService.currentMode(); |
| | | return controlMode != null && Boolean.TRUE.equals(controlMode.getEnabled()); |
| | | } |
| | | |
| | | private int resolveIntervalMinutes() { |
| | |
| | | } |
| | | |
| | | private AutoTuneAgentService.AutoTuneAgentResult failedAgentResult(String triggerType, Exception exception) { |
| | | AutoTuneControlModeSnapshot controlMode = autoTuneControlModeService.currentMode(); |
| | | AutoTuneAgentService.AutoTuneAgentResult result = new AutoTuneAgentService.AutoTuneAgentResult(); |
| | | result.setSuccess(false); |
| | | result.setTriggerType(triggerType); |
| | |
| | | result.setCompletionTokens(0L); |
| | | result.setTotalTokens(0L); |
| | | result.setMaxRoundsReached(false); |
| | | result.setAnalysisOnly(controlMode.getAnalysisOnly()); |
| | | result.setAllowApply(controlMode.getAllowApply()); |
| | | result.setExecutionMode(controlMode.getModeCode()); |
| | | result.setActualApplyCalled(false); |
| | | result.setRollbackCalled(false); |
| | | result.setSuccessCount(0); |
| | | result.setRejectCount(0); |
| | | result.setMcpCalls(new ArrayList<>()); |
| | | return result; |
| | | } |
| | | |
| | | private void safeWriteAgentRunAudit(String triggerType, |
| | | Date startTime, |
| | | AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | | try { |
| | | writeAgentRunAudit(triggerType, startTime, agentResult); |
| | | } catch (Exception exception) { |
| | | log.warn("Auto tune coordinator failed to write agent run audit", exception); |
| | | } |
| | | } |
| | | |
| | | private void writeAgentRunAudit(String triggerType, |
| | | Date startTime, |
| | | AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | | if (agentResult == null) { |
| | | return; |
| | | } |
| | | Date finishTime = new Date(); |
| | | Integer intervalMinutes = resolveIntervalMinutes(); |
| | | AiAutoTuneJob job = new AiAutoTuneJob(); |
| | | job.setTriggerType(AutoTuneTriggerType.normalize(triggerType)); |
| | | job.setStatus(resolveAuditStatus(agentResult)); |
| | | job.setStartTime(startTime == null ? finishTime : startTime); |
| | | job.setFinishTime(finishTime); |
| | | job.setHasActiveTasks(resolveHasActiveTasksForAudit()); |
| | | job.setPromptSceneCode(AiPromptScene.AUTO_TUNE_DISPATCH.getCode()); |
| | | job.setSummary(agentResult.getSummary()); |
| | | job.setIntervalBefore(intervalMinutes); |
| | | job.setIntervalAfter(intervalMinutes); |
| | | job.setSuccessCount(safeCount(agentResult.getSuccessCount())); |
| | | job.setRejectCount(safeCount(agentResult.getRejectCount())); |
| | | if (isErrorAuditStatus(job.getStatus())) { |
| | | job.setErrorMessage(agentResult.getSummary()); |
| | | } |
| | | job.setLlmCallCount(agentResult.getLlmCallCount() == null ? 0 : agentResult.getLlmCallCount()); |
| | | job.setPromptTokens(toSafeInteger(agentResult.getPromptTokens())); |
| | | job.setCompletionTokens(toSafeInteger(agentResult.getCompletionTokens())); |
| | | job.setTotalTokens(toSafeInteger(agentResult.getTotalTokens())); |
| | | job.setCreateTime(job.getStartTime()); |
| | | if (!aiAutoTuneJobService.save(job)) { |
| | | log.warn("Auto tune coordinator failed to save agent run audit"); |
| | | return; |
| | | } |
| | | safeWriteMcpCallAudit(job.getId(), agentResult); |
| | | } |
| | | |
| | | private void safeWriteMcpCallAudit(Long agentJobId, AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | | try { |
| | | writeMcpCallAudit(agentJobId, agentResult); |
| | | } catch (Exception exception) { |
| | | log.warn("Auto tune coordinator failed to write MCP call audit", exception); |
| | | } |
| | | } |
| | | |
| | | private void writeMcpCallAudit(Long agentJobId, AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | | if (agentJobId == null || agentResult == null || agentResult.getMcpCalls() == null |
| | | || agentResult.getMcpCalls().isEmpty()) { |
| | | return; |
| | | } |
| | | List<AiAutoTuneMcpCall> mcpCalls = new ArrayList<>(); |
| | | Date createTime = new Date(); |
| | | for (AutoTuneAgentService.McpCallResult callResult : agentResult.getMcpCalls()) { |
| | | mcpCalls.add(toMcpCallEntity(agentJobId, callResult, createTime)); |
| | | } |
| | | if (!aiAutoTuneMcpCallService.saveBatch(mcpCalls)) { |
| | | log.warn("Auto tune coordinator failed to save MCP call audit"); |
| | | } |
| | | } |
| | | |
| | | private AiAutoTuneMcpCall toMcpCallEntity(Long agentJobId, |
| | | AutoTuneAgentService.McpCallResult callResult, |
| | | Date createTime) { |
| | | AiAutoTuneMcpCall mcpCall = new AiAutoTuneMcpCall(); |
| | | mcpCall.setAgentJobId(agentJobId); |
| | | mcpCall.setCallSeq(callResult.getCallSeq()); |
| | | mcpCall.setToolName(callResult.getToolName()); |
| | | mcpCall.setStatus(callResult.getStatus()); |
| | | mcpCall.setDryRun(toTinyInt(callResult.getDryRun())); |
| | | mcpCall.setApplyJobId(callResult.getApplyJobId()); |
| | | mcpCall.setSuccessCount(safeCount(callResult.getSuccessCount())); |
| | | mcpCall.setRejectCount(safeCount(callResult.getRejectCount())); |
| | | mcpCall.setDurationMs(callResult.getDurationMs()); |
| | | mcpCall.setRequestJson(callResult.getRequestJson()); |
| | | mcpCall.setResponseJson(callResult.getResponseJson()); |
| | | mcpCall.setErrorMessage(callResult.getErrorMessage()); |
| | | mcpCall.setCreateTime(createTime); |
| | | return mcpCall; |
| | | } |
| | | |
| | | private Integer toTinyInt(Boolean value) { |
| | | if (value == null) { |
| | | return null; |
| | | } |
| | | return value ? 1 : 0; |
| | | } |
| | | |
| | | private String resolveAuditStatus(AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | | int successCount = safeCount(agentResult.getSuccessCount()); |
| | | int rejectCount = safeCount(agentResult.getRejectCount()); |
| | | if (!Boolean.TRUE.equals(agentResult.getSuccess())) { |
| | | if (successCount > 0 && rejectCount > 0) { |
| | | return AutoTuneJobStatus.PARTIAL_SUCCESS.getCode(); |
| | | } |
| | | if (rejectCount > 0) { |
| | | return AutoTuneJobStatus.REJECTED.getCode(); |
| | | } |
| | | return AutoTuneJobStatus.FAILED.getCode(); |
| | | } |
| | | if (successCount > 0 && rejectCount > 0) { |
| | | return AutoTuneJobStatus.PARTIAL_SUCCESS.getCode(); |
| | | } |
| | | if (rejectCount > 0) { |
| | | return AutoTuneJobStatus.REJECTED.getCode(); |
| | | } |
| | | if (Boolean.TRUE.equals(agentResult.getActualApplyCalled()) |
| | | || Boolean.TRUE.equals(agentResult.getRollbackCalled())) { |
| | | return AutoTuneJobStatus.SUCCESS.getCode(); |
| | | } |
| | | return AutoTuneJobStatus.NO_CHANGE.getCode(); |
| | | } |
| | | |
| | | private boolean isErrorAuditStatus(String status) { |
| | | return AutoTuneJobStatus.FAILED.getCode().equals(status) |
| | | || AutoTuneJobStatus.REJECTED.getCode().equals(status) |
| | | || AutoTuneJobStatus.PARTIAL_SUCCESS.getCode().equals(status); |
| | | } |
| | | |
| | | private int safeCount(Integer value) { |
| | | return value == null ? 0 : value; |
| | | } |
| | | |
| | | private int resolveHasActiveTasksForAudit() { |
| | | try { |
| | | return hasActiveTasks() ? 1 : 0; |
| | | } catch (RuntimeException exception) { |
| | | log.warn("Auto tune coordinator failed to query active tasks for audit", exception); |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | private Integer toSafeInteger(Long value) { |
| | | if (value == null) { |
| | | return 0; |
| | | } |
| | | if (value > Integer.MAX_VALUE) { |
| | | return Integer.MAX_VALUE; |
| | | } |
| | | if (value < Integer.MIN_VALUE) { |
| | | return Integer.MIN_VALUE; |
| | | } |
| | | return value.intValue(); |
| | | } |
| | | |
| | | private void safeWriteOperateLog(AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | |
| | | private Map<String, Object> buildRequestSummary(AutoTuneAgentService.AutoTuneAgentResult agentResult) { |
| | | Map<String, Object> request = new LinkedHashMap<>(); |
| | | request.put("trigger", agentResult.getTriggerType()); |
| | | request.put("analysisOnly", agentResult.getAnalysisOnly()); |
| | | request.put("allowApply", agentResult.getAllowApply()); |
| | | request.put("executionMode", agentResult.getExecutionMode()); |
| | | return request; |
| | | } |
| | | |
| | |
| | | Map<String, Object> response = new LinkedHashMap<>(); |
| | | response.put("success", agentResult.getSuccess()); |
| | | response.put("summary", agentResult.getSummary()); |
| | | response.put("analysisOnly", agentResult.getAnalysisOnly()); |
| | | response.put("allowApply", agentResult.getAllowApply()); |
| | | response.put("executionMode", agentResult.getExecutionMode()); |
| | | response.put("toolCallCount", agentResult.getToolCallCount()); |
| | | response.put("llmCallCount", agentResult.getLlmCallCount()); |
| | | response.put("promptTokens", agentResult.getPromptTokens()); |
| | | response.put("completionTokens", agentResult.getCompletionTokens()); |
| | | response.put("totalTokens", agentResult.getTotalTokens()); |
| | | response.put("maxRoundsReached", agentResult.getMaxRoundsReached()); |
| | | response.put("actualApplyCalled", agentResult.getActualApplyCalled()); |
| | | response.put("rollbackCalled", agentResult.getRollbackCalled()); |
| | | response.put("successCount", agentResult.getSuccessCount()); |
| | | response.put("rejectCount", agentResult.getRejectCount()); |
| | | response.put("mcpCallCount", agentResult.getMcpCalls() == null ? 0 : agentResult.getMcpCalls().size()); |
| | | return response; |
| | | } |
| | | } |