From 1b93474a67aa2323d20630b1bb026713b2bad009 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期三, 29 四月 2026 16:59:32 +0800
Subject: [PATCH] #Agent自动调参

---
 src/main/java/com/zy/ai/service/impl/AutoTuneAgentServiceImpl.java |  122 ++++++++++++++++++++++++++++++++--------
 1 files changed, 98 insertions(+), 24 deletions(-)

diff --git a/src/main/java/com/zy/ai/service/impl/AutoTuneAgentServiceImpl.java b/src/main/java/com/zy/ai/service/impl/AutoTuneAgentServiceImpl.java
index 509fe00..cdfe44f 100644
--- a/src/main/java/com/zy/ai/service/impl/AutoTuneAgentServiceImpl.java
+++ b/src/main/java/com/zy/ai/service/impl/AutoTuneAgentServiceImpl.java
@@ -3,6 +3,7 @@
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.zy.ai.domain.autotune.AutoTuneApplyResult;
+import com.zy.ai.domain.autotune.AutoTuneControlModeSnapshot;
 import com.zy.ai.domain.autotune.AutoTuneTriggerType;
 import com.zy.ai.entity.AiPromptTemplate;
 import com.zy.ai.entity.ChatCompletionRequest;
@@ -11,7 +12,9 @@
 import com.zy.ai.mcp.service.SpringAiMcpToolManager;
 import com.zy.ai.service.AiPromptTemplateService;
 import com.zy.ai.service.AutoTuneAgentService;
+import com.zy.ai.service.AutoTuneControlModeService;
 import com.zy.ai.service.LlmChatService;
+import com.zy.ai.utils.AiPromptUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -46,10 +49,12 @@
     private final LlmChatService llmChatService;
     private final SpringAiMcpToolManager mcpToolManager;
     private final AiPromptTemplateService aiPromptTemplateService;
+    private final AutoTuneControlModeService autoTuneControlModeService;
 
     @Override
     public AutoTuneAgentResult runAutoTune(String triggerType) {
         String normalizedTriggerType = normalizeTriggerType(triggerType);
+        AutoTuneControlModeSnapshot controlMode = buildControlModeSnapshot();
         UsageCounter usageCounter = new UsageCounter();
         RunState runState = new RunState();
         boolean maxRoundsReached = false;
@@ -62,7 +67,7 @@
             }
 
             AiPromptTemplate promptTemplate = aiPromptTemplateService.resolvePublished(AiPromptScene.AUTO_TUNE_DISPATCH.getCode());
-            List<ChatCompletionRequest.Message> messages = buildMessages(promptTemplate, normalizedTriggerType);
+            List<ChatCompletionRequest.Message> messages = buildMessages(promptTemplate, normalizedTriggerType, controlMode);
 
             for (int round = 0; round < MAX_TOOL_ROUNDS; round++) {
                 ChatCompletionResponse response = llmChatService.chatCompletionOrThrow(messages, TEMPERATURE, MAX_TOKENS, tools);
@@ -74,7 +79,7 @@
                 List<ChatCompletionRequest.ToolCall> toolCalls = assistantMessage.getTool_calls();
                 if (toolCalls == null || toolCalls.isEmpty()) {
                     return buildResult(runState.isSuccessful(), normalizedTriggerType, summaryBuffer, runState,
-                            usageCounter, false);
+                            usageCounter, false, controlMode);
                 }
 
                 for (ChatCompletionRequest.ToolCall toolCall : toolCalls) {
@@ -83,16 +88,20 @@
                 }
             }
             maxRoundsReached = true;
-            return buildResult(false, normalizedTriggerType, summaryBuffer, runState, usageCounter, maxRoundsReached);
+            return buildResult(false, normalizedTriggerType, summaryBuffer, runState, usageCounter, maxRoundsReached,
+                    controlMode);
         } catch (Exception exception) {
             log.error("Auto tune agent stopped with error", exception);
             appendSummary(summaryBuffer, "鑷姩璋冨弬 Agent 鎵ц寮傚父: " + exception.getMessage());
             runState.markToolError();
-            return buildResult(false, normalizedTriggerType, summaryBuffer, runState, usageCounter, maxRoundsReached);
+            return buildResult(false, normalizedTriggerType, summaryBuffer, runState, usageCounter, maxRoundsReached,
+                    controlMode);
         }
     }
 
-    private List<ChatCompletionRequest.Message> buildMessages(AiPromptTemplate promptTemplate, String triggerType) {
+    private List<ChatCompletionRequest.Message> buildMessages(AiPromptTemplate promptTemplate,
+                                                              String triggerType,
+                                                              AutoTuneControlModeSnapshot controlMode) {
         List<ChatCompletionRequest.Message> messages = new ArrayList<>();
 
         ChatCompletionRequest.Message systemMessage = new ChatCompletionRequest.Message();
@@ -102,15 +111,7 @@
 
         ChatCompletionRequest.Message userMessage = new ChatCompletionRequest.Message();
         userMessage.setRole("user");
-        userMessage.setContent("璇锋墽琛屼竴娆″悗鍙� WCS 鑷姩璋冨弬銆倀riggerType=" + triggerType
-                + "銆傚繀椤诲厛璋冪敤 wcs_local_dispatch_get_auto_tune_snapshot 鑾峰彇浜嬪疄锛涘闇�鎻愪氦鍙樻洿锛�"
-                + "蹇呴』鍏� dry-run锛屽啀鏍规嵁 dry-run 缁撴灉鍐冲畾鏄惁瀹為檯搴旂敤锛涘疄闄呭簲鐢ㄦ椂蹇呴』甯︿笂 dry-run 杩斿洖鐨� dryRunToken銆�"
-                + "绂佹鍦ㄦ病鏈夋敹鍒� wcs_local_dispatch_apply_auto_tune_changes 鎴� wcs_local_dispatch_revert_last_auto_tune_job 宸ュ叿杩斿洖缁撴灉鏃跺0绉板凡璇曠畻銆佸凡搴旂敤鎴栧凡鍥炴粴銆�"
-                + "蹇呴』妫�鏌� taskSnapshot.stationLimitBlockedTasks 鍜� taskSnapshot.outboundTaskSamples 涓殑 systemMsg銆亀rkSts銆乥atchSeq锛屽垽鏂槸鍚﹀瓨鍦ㄨ涓婇檺鎸′綇鐨勬棭搴忓嚭搴撲换鍔°��"
-                + "鎵�鏈夋彁浜ょ粰 wcs_local_dispatch_apply_auto_tune_changes 鐨� changes 閮藉繀椤诲厛鍖归厤 snapshot.ruleSnapshot 涓搴� targetType/targetKey 鐨勮鍒欍��"
-                + "姣忎釜鍙傛暟閮藉繀椤绘弧瓒� minValue銆乵axValue 鎴� dynamicMaxValue銆乵axStep銆乧ooldownMinutes 鍜岃鍒� note锛涙壘涓嶅埌瑙勫垯鎴栨棤娉曡瘉鏄庡姩鎬佷笂闄愭椂绂佹鎻愪氦銆�"
-                + "dry-run 杩斿洖 success=false 鎴� rejectCount>0 鏃讹紝蹇呴』鍋滄瀹為檯搴旂敤骞惰鏄庢嫆缁濆師鍥狅紝鎴栭噸鏂版彁浜ゅ畬鍏ㄥ悎娉曠殑 dry-run銆�"
-                + "涓嶈杈撳嚭鑷敱鏍煎紡 JSON 渚涘灞傝В鏋愩��");
+        userMessage.setContent(AiPromptUtils.buildAutoTuneRuntimeGuard(triggerType, controlMode));
         messages.add(userMessage);
         return messages;
     }
@@ -126,7 +127,9 @@
         return message;
     }
 
-    private Object callMountedTool(ChatCompletionRequest.ToolCall toolCall, RunState runState, String triggerType) {
+    private Object callMountedTool(ChatCompletionRequest.ToolCall toolCall,
+                                   RunState runState,
+                                   String triggerType) {
         String toolName = resolveToolName(toolCall);
         if (!ALLOWED_TOOL_NAMES.contains(toolName)) {
             throw new IllegalArgumentException("Disallowed auto-tune MCP tool: " + toolName);
@@ -138,11 +141,13 @@
             Object output = mcpToolManager.callTool(toolName, arguments);
             runState.markToolSuccess(toolName);
             recordMutationResult(toolName, arguments, output, runState);
-            if (TOOL_APPLY_CHANGES.equals(toolName) && isRejectedApplyResult(output)) {
-                runState.markApplyRejected();
-                Object wrappedOutput = withRejectedApplyInstruction(output);
-                runState.addMcpCall(buildMcpCall(toolName, arguments, wrappedOutput, startTimeMillis, null));
-                return wrappedOutput;
+            if (isRejectedApplyResult(output)) {
+                runState.markApplyRejected(resolveApplyError(output));
+                if (TOOL_APPLY_CHANGES.equals(toolName)) {
+                    Object wrappedOutput = withRejectedApplyInstruction(output);
+                    runState.addMcpCall(buildMcpCall(toolName, arguments, wrappedOutput, startTimeMillis, null));
+                    return wrappedOutput;
+                }
             }
             runState.addMcpCall(buildMcpCall(toolName, arguments, output, startTimeMillis, null));
             return output;
@@ -279,8 +284,10 @@
         if (TOOL_APPLY_CHANGES.equals(toolName)) {
             boolean dryRun = Boolean.TRUE.equals(arguments.getBoolean("dryRun"));
             if (!dryRun) {
-                runState.markActualApply();
                 runState.addCounts(output);
+                if (outputHasSuccessfulChange(output)) {
+                    runState.markActualApply();
+                }
             } else if (isRejectedApplyResult(output)) {
                 runState.addCounts(output);
             }
@@ -290,6 +297,46 @@
             runState.markRollback();
             runState.addCounts(output);
         }
+    }
+
+    private boolean outputHasSuccessfulChange(Object output) {
+        if (output instanceof AutoTuneApplyResult) {
+            AutoTuneApplyResult result = (AutoTuneApplyResult) output;
+            if (result.getChanges() != null) {
+                return hasSuccessfulChange(result.getChanges());
+            }
+            return safeCount(result.getSuccessCount()) > 0;
+        }
+        if (output instanceof Map<?, ?>) {
+            Map<?, ?> result = (Map<?, ?>) output;
+            if (!isApplyResultShape(result)) {
+                return false;
+            }
+            if (result.containsKey("changes")) {
+                return hasSuccessfulChange(result.get("changes"));
+            }
+            return safeCount(result.get("successCount")) > 0;
+        }
+        return false;
+    }
+
+    private boolean hasSuccessfulChange(Object changes) {
+        if (!(changes instanceof List<?>)) {
+            return false;
+        }
+        for (Object change : (List<?>) changes) {
+            String resultStatus = null;
+            if (change instanceof com.zy.ai.entity.AiAutoTuneChange) {
+                resultStatus = ((com.zy.ai.entity.AiAutoTuneChange) change).getResultStatus();
+            } else if (change instanceof Map<?, ?>) {
+                Object status = ((Map<?, ?>) change).get("resultStatus");
+                resultStatus = status == null ? null : String.valueOf(status);
+            }
+            if (resultStatus != null && "success".equalsIgnoreCase(resultStatus.trim())) {
+                return true;
+            }
+        }
+        return false;
     }
 
     private boolean isRejectedApplyResult(Object output) {
@@ -403,10 +450,14 @@
                                             StringBuilder summaryBuffer,
                                             RunState runState,
                                             UsageCounter usageCounter,
-                                            boolean maxRoundsReached) {
+                                            boolean maxRoundsReached,
+                                            AutoTuneControlModeSnapshot controlMode) {
         AutoTuneAgentResult result = new AutoTuneAgentResult();
         result.setSuccess(success);
         result.setTriggerType(triggerType);
+        result.setAnalysisOnly(controlMode.getAnalysisOnly());
+        result.setAllowApply(controlMode.getAllowApply());
+        result.setExecutionMode(controlMode.getModeCode());
         result.setToolCallCount(runState.getToolCallCount());
         result.setLlmCallCount(usageCounter.getLlmCallCount());
         result.setPromptTokens(usageCounter.getPromptTokens());
@@ -430,6 +481,9 @@
         }
         if (runState.hasApplyRejected()) {
             summary = summary + "\n鑷姩璋冨弬 Agent 瀛樺湪琚嫆缁濈殑 dry-run/apply 缁撴灉锛屾湭瑙嗕负鎴愬姛璋冨弬銆�";
+            if (!isBlank(runState.getFirstRejectReason())) {
+                summary = summary + "鎷掔粷鍘熷洜: " + runState.getFirstRejectReason();
+            }
         }
         if (success && !runState.hasActualMutation()) {
             summary = "鑷姩璋冨弬 Agent 鏈皟鐢ㄥ疄闄呭簲鐢ㄦ垨鍥炴粴宸ュ叿锛屾湭淇敼杩愯鍙傛暟銆�"
@@ -438,8 +492,20 @@
         if (maxRoundsReached) {
             summary = summary + "\n鑷姩璋冨弬 Agent 杈惧埌鏈�澶у伐鍏疯皟鐢ㄨ疆娆★紝宸插仠姝€��";
         }
+        summary = buildModeSummary(controlMode) + (summary.isEmpty() ? "" : "\n" + summary);
         result.setSummary(summary);
         return result;
+    }
+
+    private String buildModeSummary(AutoTuneControlModeSnapshot controlMode) {
+        return "鎵ц妯″紡: " + controlMode.getModeCode()
+                + "锛宎nalysisOnly=" + controlMode.getAnalysisOnly()
+                + "锛宎llowApply=" + controlMode.getAllowApply()
+                + "锛宮odeLabel=" + controlMode.getModeLabel();
+    }
+
+    private AutoTuneControlModeSnapshot buildControlModeSnapshot() {
+        return autoTuneControlModeService.currentMode();
     }
 
     private List<Object> filterAllowedTools(List<Object> tools) {
@@ -482,7 +548,7 @@
         return isBlank(triggerType) ? "agent" : triggerType.trim();
     }
 
-    private boolean isBlank(String value) {
+    private static boolean isBlank(String value) {
         return value == null || value.trim().isEmpty();
     }
 
@@ -524,6 +590,7 @@
         private boolean snapshotCalled;
         private boolean toolError;
         private boolean applyRejected;
+        private String firstRejectReason;
         private boolean actualApplyCalled;
         private boolean rollbackCalled;
         private int successCount;
@@ -541,8 +608,11 @@
             toolError = true;
         }
 
-        void markApplyRejected() {
+        void markApplyRejected(String rejectReason) {
             applyRejected = true;
+            if (isBlank(firstRejectReason) && !isBlank(rejectReason)) {
+                firstRejectReason = rejectReason;
+            }
         }
 
         void markActualApply() {
@@ -599,6 +669,10 @@
             return applyRejected;
         }
 
+        String getFirstRejectReason() {
+            return firstRejectReason;
+        }
+
         boolean isActualApplyCalled() {
             return actualApplyCalled;
         }

--
Gitblit v1.9.1