From 3c1543a1049670c227755229a0305613442bcda8 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期三, 29 四月 2026 20:43:13 +0800
Subject: [PATCH] Merge branch 'codex/ai-provider-protocol-gateway'
---
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