package com.zy.ai.controller;
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.core.annotations.ManagerAuth;
|
import com.core.common.R;
|
import com.zy.ai.domain.autotune.AutoTuneApplyResult;
|
import com.zy.ai.entity.AiAutoTuneChange;
|
import com.zy.ai.entity.AiAutoTuneJob;
|
import com.zy.ai.entity.AiAutoTuneMcpCall;
|
import com.zy.ai.enums.AiPromptScene;
|
import com.zy.ai.service.AiAutoTuneChangeService;
|
import com.zy.ai.service.AiAutoTuneJobService;
|
import com.zy.ai.service.AiAutoTuneMcpCallService;
|
import com.zy.ai.service.AutoTuneApplyService;
|
import com.zy.ai.service.AutoTuneCoordinatorService;
|
import com.zy.ai.service.AutoTuneSnapshotService;
|
import com.zy.ai.utils.AutoTuneWriteBehaviorUtils;
|
import com.zy.common.web.BaseController;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import java.util.ArrayList;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
@RestController
|
@RequestMapping("/ai/autoTune")
|
@RequiredArgsConstructor
|
public class AutoTuneConsoleController extends BaseController {
|
|
private static final int DEFAULT_JOB_LIMIT = 10;
|
private static final int MAX_JOB_LIMIT = 50;
|
|
private final AutoTuneSnapshotService autoTuneSnapshotService;
|
private final AutoTuneCoordinatorService autoTuneCoordinatorService;
|
private final AutoTuneApplyService autoTuneApplyService;
|
private final AiAutoTuneJobService aiAutoTuneJobService;
|
private final AiAutoTuneChangeService aiAutoTuneChangeService;
|
private final AiAutoTuneMcpCallService aiAutoTuneMcpCallService;
|
|
@GetMapping("/snapshot/auth")
|
@ManagerAuth(memo = "查看AI自动调参快照")
|
public R snapshot() {
|
return R.ok(autoTuneSnapshotService.buildSnapshot());
|
}
|
|
@GetMapping("/jobs/auth")
|
@ManagerAuth(memo = "查看AI自动调参记录")
|
public R jobs(@RequestParam(value = "limit", required = false) Integer limit) {
|
int safeLimit = normalizeLimit(limit);
|
List<AiAutoTuneJob> jobs = aiAutoTuneJobService.list(new QueryWrapper<AiAutoTuneJob>()
|
.eq("prompt_scene_code", AiPromptScene.AUTO_TUNE_DISPATCH.getCode())
|
.orderByDesc("start_time")
|
.orderByDesc("id")
|
.last("limit " + safeLimit));
|
return R.ok(toJobSummaries(jobs));
|
}
|
|
@PostMapping("/triggerManual/auth")
|
@ManagerAuth(memo = "手动触发AI自动调参Agent")
|
public R triggerManual() {
|
return R.ok(autoTuneCoordinatorService.runManualAutoTune());
|
}
|
|
@PostMapping("/triggerScheduler/auth")
|
@ManagerAuth(memo = "按后台规则触发AI自动调参")
|
public R triggerScheduler() {
|
return R.ok(autoTuneCoordinatorService.runAutoTuneIfEligible());
|
}
|
|
@PostMapping("/rollback/auth")
|
@ManagerAuth(memo = "回滚最近一次AI自动调参")
|
public R rollback(@RequestParam(value = "reason", required = false) String reason) {
|
AutoTuneApplyResult result = autoTuneApplyService.rollbackLastSuccessfulJob(reason);
|
return R.ok(result);
|
}
|
|
private int normalizeLimit(Integer limit) {
|
if (limit == null || limit <= 0) {
|
return DEFAULT_JOB_LIMIT;
|
}
|
return Math.min(limit, MAX_JOB_LIMIT);
|
}
|
|
private List<Map<String, Object>> toJobSummaries(List<AiAutoTuneJob> jobs) {
|
List<Map<String, Object>> result = new ArrayList<>();
|
if (jobs == null || jobs.isEmpty()) {
|
return result;
|
}
|
for (AiAutoTuneJob job : jobs) {
|
result.add(toJobSummary(job));
|
}
|
return result;
|
}
|
|
private Map<String, Object> toJobSummary(AiAutoTuneJob job) {
|
LinkedHashMap<String, Object> item = new LinkedHashMap<>();
|
item.put("id", job.getId());
|
item.put("triggerType", job.getTriggerType());
|
item.put("status", job.getStatus());
|
item.put("startTime", job.getStartTime());
|
item.put("finishTime", job.getFinishTime());
|
item.put("hasActiveTasks", job.getHasActiveTasks());
|
item.put("summary", job.getSummary());
|
item.put("reasoningDigest", job.getReasoningDigest());
|
item.put("snapshotDigest", job.getSnapshotDigest());
|
item.put("intervalBefore", job.getIntervalBefore());
|
item.put("intervalAfter", job.getIntervalAfter());
|
item.put("successCount", job.getSuccessCount());
|
item.put("rejectCount", job.getRejectCount());
|
item.put("errorMessage", job.getErrorMessage());
|
item.put("llmCallCount", job.getLlmCallCount());
|
item.put("promptTokens", job.getPromptTokens());
|
item.put("completionTokens", job.getCompletionTokens());
|
item.put("totalTokens", job.getTotalTokens());
|
List<AiAutoTuneMcpCall> mcpCalls = listMcpCalls(job.getId());
|
List<Map<String, Object>> mcpCallSummaries = toMcpCallSummaries(mcpCalls);
|
List<Map<String, Object>> changeSummaries = listChangeSummaries(job, mcpCalls);
|
AutoTuneWriteBehaviorUtils.addWriteBehavior(item,
|
AutoTuneWriteBehaviorUtils.resolveJobWriteBehavior(job, mcpCallSummaries, changeSummaries));
|
item.put("mcpCallCount", mcpCalls.size());
|
item.put("mcpCalls", mcpCallSummaries);
|
item.put("changes", changeSummaries);
|
return item;
|
}
|
|
private List<AiAutoTuneMcpCall> listMcpCalls(Long agentJobId) {
|
if (agentJobId == null) {
|
return new ArrayList<>();
|
}
|
List<AiAutoTuneMcpCall> mcpCalls = aiAutoTuneMcpCallService.list(new QueryWrapper<AiAutoTuneMcpCall>()
|
.eq("agent_job_id", agentJobId)
|
.orderByAsc("call_seq")
|
.orderByAsc("id"));
|
return mcpCalls == null ? new ArrayList<>() : mcpCalls;
|
}
|
|
private List<Map<String, Object>> toMcpCallSummaries(List<AiAutoTuneMcpCall> mcpCalls) {
|
List<Map<String, Object>> result = new ArrayList<>();
|
if (mcpCalls == null || mcpCalls.isEmpty()) {
|
return result;
|
}
|
for (AiAutoTuneMcpCall mcpCall : mcpCalls) {
|
result.add(toMcpCallSummary(mcpCall));
|
}
|
return result;
|
}
|
|
private Map<String, Object> toMcpCallSummary(AiAutoTuneMcpCall mcpCall) {
|
LinkedHashMap<String, Object> item = new LinkedHashMap<>();
|
item.put("id", mcpCall.getId());
|
item.put("callSeq", mcpCall.getCallSeq());
|
item.put("toolName", mcpCall.getToolName());
|
item.put("status", mcpCall.getStatus());
|
item.put("dryRun", toBoolean(mcpCall.getDryRun()));
|
item.put("applyJobId", mcpCall.getApplyJobId());
|
item.put("successCount", mcpCall.getSuccessCount());
|
item.put("rejectCount", mcpCall.getRejectCount());
|
item.put("durationMs", mcpCall.getDurationMs());
|
item.put("requestJson", mcpCall.getRequestJson());
|
item.put("responseJson", mcpCall.getResponseJson());
|
item.put("errorMessage", mcpCall.getErrorMessage());
|
item.put("createTime", mcpCall.getCreateTime());
|
AutoTuneWriteBehaviorUtils.addWriteBehavior(item,
|
AutoTuneWriteBehaviorUtils.resolveMcpWriteBehavior(mcpCall));
|
return item;
|
}
|
|
private Boolean toBoolean(Integer value) {
|
if (value == null) {
|
return null;
|
}
|
return value == 1;
|
}
|
|
private List<Map<String, Object>> listChangeSummaries(AiAutoTuneJob job, List<AiAutoTuneMcpCall> mcpCalls) {
|
List<Map<String, Object>> result = new ArrayList<>();
|
Map<Long, String> ownerTriggerTypes = collectChangeOwnerTriggerTypes(job, mcpCalls);
|
List<Long> applyJobIds = new ArrayList<>(ownerTriggerTypes.keySet());
|
if (applyJobIds.isEmpty()) {
|
return result;
|
}
|
List<AiAutoTuneChange> changes = aiAutoTuneChangeService.list(new QueryWrapper<AiAutoTuneChange>()
|
.in("job_id", applyJobIds)
|
.orderByAsc("job_id")
|
.orderByAsc("id"));
|
if (changes == null || changes.isEmpty()) {
|
return result;
|
}
|
for (AiAutoTuneChange change : changes) {
|
result.add(toChangeSummary(change, ownerTriggerTypes.get(change.getJobId())));
|
}
|
return result;
|
}
|
|
private Map<Long, String> collectChangeOwnerTriggerTypes(AiAutoTuneJob job, List<AiAutoTuneMcpCall> mcpCalls) {
|
LinkedHashMap<Long, String> result = new LinkedHashMap<>();
|
if (job != null && job.getId() != null) {
|
result.put(job.getId(), job.getTriggerType());
|
}
|
if (mcpCalls == null || mcpCalls.isEmpty()) {
|
return result;
|
}
|
for (AiAutoTuneMcpCall mcpCall : mcpCalls) {
|
Long applyJobId = mcpCall.getApplyJobId();
|
if (applyJobId == null || result.containsKey(applyJobId)) {
|
continue;
|
}
|
result.put(applyJobId, resolveMcpApplyJobTriggerType(mcpCall));
|
}
|
return result;
|
}
|
|
private String resolveMcpApplyJobTriggerType(AiAutoTuneMcpCall mcpCall) {
|
if (mcpCall == null || mcpCall.getToolName() == null) {
|
return null;
|
}
|
String toolName = mcpCall.getToolName().toLowerCase();
|
return toolName.contains("revert_last_auto_tune_job") || toolName.contains("rollback") ? "rollback" : null;
|
}
|
|
private Map<String, Object> toChangeSummary(AiAutoTuneChange change, String ownerTriggerType) {
|
LinkedHashMap<String, Object> item = new LinkedHashMap<>();
|
item.put("id", change.getId());
|
item.put("jobId", change.getJobId());
|
item.put("targetType", change.getTargetType());
|
item.put("targetId", change.getTargetId());
|
item.put("targetKey", change.getTargetKey());
|
item.put("oldValue", change.getOldValue());
|
item.put("requestedValue", change.getRequestedValue());
|
item.put("appliedValue", change.getAppliedValue());
|
item.put("resultStatus", change.getResultStatus());
|
item.put("rejectReason", change.getRejectReason());
|
item.put("cooldownExpireTime", change.getCooldownExpireTime());
|
item.put("createTime", change.getCreateTime());
|
AutoTuneWriteBehaviorUtils.addWriteBehavior(item,
|
AutoTuneWriteBehaviorUtils.resolveChangeWriteBehavior(change, ownerTriggerType));
|
return item;
|
}
|
}
|