From dc3f9cc91759823ce59486f19b138be4b296a0f1 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 28 四月 2026 09:43:28 +0800
Subject: [PATCH] #
---
/dev/null | 9 -
src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java | 24 +-
src/test/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImplTest.java | 20 ++
src/main/java/com/zy/ai/utils/AiPromptUtils.java | 9
src/main/resources/sql/20260428_ai_auto_tune_consolidated.sql | 256 ++++++++++++++++++++++++++++
src/main/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImpl.java | 23 --
src/main/java/com/zy/ai/domain/autotune/AutoTuneRuleDefinition.java | 149 ++++++++++++++--
src/main/webapp/views/ai/auto_tune.html | 25 ++
8 files changed, 450 insertions(+), 65 deletions(-)
diff --git a/src/main/java/com/zy/ai/domain/autotune/AutoTuneRuleDefinition.java b/src/main/java/com/zy/ai/domain/autotune/AutoTuneRuleDefinition.java
index bff033e..1b3cd79 100644
--- a/src/main/java/com/zy/ai/domain/autotune/AutoTuneRuleDefinition.java
+++ b/src/main/java/com/zy/ai/domain/autotune/AutoTuneRuleDefinition.java
@@ -6,6 +6,12 @@
public final class AutoTuneRuleDefinition {
+ private static final String DEFAULT_RULE_NOTE = "鍗曟璋冩暣骞呭害涓嶈兘瓒呰繃 maxStep銆�";
+ private static final String STATION_OUT_TASK_LIMIT_DYNAMIC_MAX_SOURCE =
+ "currentParameterSnapshot.stationOutBufferCapacities[targetId]";
+ private static final String STATION_OUT_TASK_LIMIT_NOTE =
+ "鍗曟璋冩暣骞呭害涓嶈兘瓒呰繃 maxStep锛涘澶ф椂涓嶅緱瓒呰繃瀵瑰簲绔欑偣 outBufferCapacity銆�";
+
private static final Map<String, Rule> RULE_MAP = buildRuleMap();
private AutoTuneRuleDefinition() {
@@ -24,27 +30,58 @@
private static Map<String, Rule> buildRuleMap() {
LinkedHashMap<String, Rule> ruleMap = new LinkedHashMap<>();
- add(ruleMap, AutoTuneTargetType.SYS_CONFIG, "aiAutoTuneIntervalMinutes", 5, 60, 5, 30, false);
- add(ruleMap, AutoTuneTargetType.SYS_CONFIG, "conveyorStationTaskLimit", 5, 200, 5, 20, false);
- add(ruleMap, AutoTuneTargetType.SYS_CONFIG, "crnOutBatchRunningLimit", 1, 20, 3, 20, false);
- add(ruleMap, AutoTuneTargetType.STATION, "outTaskLimit", 0, null, 3, 10, true);
- add(ruleMap, AutoTuneTargetType.CRN, "maxOutTask", 0, 10, 3, 10, false);
- add(ruleMap, AutoTuneTargetType.CRN, "maxInTask", 0, 10, 3, 10, false);
- add(ruleMap, AutoTuneTargetType.DUAL_CRN, "maxOutTask", 0, 10, 3, 10, false);
- add(ruleMap, AutoTuneTargetType.DUAL_CRN, "maxInTask", 0, 10, 3, 10, false);
+ add(ruleMap, rule(AutoTuneTargetType.SYS_CONFIG, "aiAutoTuneIntervalMinutes")
+ .minValue(5)
+ .maxValue(60)
+ .maxStep(5)
+ .cooldownMinutes(30));
+ add(ruleMap, rule(AutoTuneTargetType.SYS_CONFIG, "conveyorStationTaskLimit")
+ .minValue(5)
+ .maxValue(200)
+ .maxStep(5)
+ .cooldownMinutes(20));
+ add(ruleMap, rule(AutoTuneTargetType.SYS_CONFIG, "crnOutBatchRunningLimit")
+ .minValue(1)
+ .maxValue(20)
+ .maxStep(3)
+ .cooldownMinutes(20));
+ add(ruleMap, rule(AutoTuneTargetType.STATION, "outTaskLimit")
+ .minValue(0)
+ .maxStep(3)
+ .cooldownMinutes(10)
+ .dynamicMaxSource(STATION_OUT_TASK_LIMIT_DYNAMIC_MAX_SOURCE)
+ .note(STATION_OUT_TASK_LIMIT_NOTE));
+ add(ruleMap, rule(AutoTuneTargetType.CRN, "maxOutTask")
+ .minValue(0)
+ .maxValue(10)
+ .maxStep(3)
+ .cooldownMinutes(10));
+ add(ruleMap, rule(AutoTuneTargetType.CRN, "maxInTask")
+ .minValue(0)
+ .maxValue(10)
+ .maxStep(3)
+ .cooldownMinutes(10));
+ add(ruleMap, rule(AutoTuneTargetType.DUAL_CRN, "maxOutTask")
+ .minValue(0)
+ .maxValue(10)
+ .maxStep(3)
+ .cooldownMinutes(10));
+ add(ruleMap, rule(AutoTuneTargetType.DUAL_CRN, "maxInTask")
+ .minValue(0)
+ .maxValue(10)
+ .maxStep(3)
+ .cooldownMinutes(10));
+
return Collections.unmodifiableMap(ruleMap);
}
- private static void add(LinkedHashMap<String, Rule> ruleMap,
- AutoTuneTargetType targetType,
- String targetKey,
- Integer minValue,
- Integer maxValue,
- int maxStep,
- int cooldownMinutes,
- boolean dynamicMaxValue) {
- Rule rule = new Rule(targetType, targetKey, minValue, maxValue, maxStep, cooldownMinutes, dynamicMaxValue);
- ruleMap.put(buildKey(targetType.getCode(), targetKey), rule);
+ private static RuleSpec rule(AutoTuneTargetType targetType, String targetKey) {
+ return new RuleSpec(targetType, targetKey);
+ }
+
+ private static void add(LinkedHashMap<String, Rule> ruleMap, RuleSpec ruleSpec) {
+ Rule rule = ruleSpec.toRule();
+ ruleMap.put(buildKey(rule.getTargetType().getCode(), rule.getTargetKey()), rule);
}
private static String buildKey(String targetType, String targetKey) {
@@ -59,6 +96,8 @@
private final int maxStep;
private final int cooldownMinutes;
private final boolean dynamicMaxValue;
+ private final String dynamicMaxSource;
+ private final String note;
private Rule(AutoTuneTargetType targetType,
String targetKey,
@@ -66,7 +105,9 @@
Integer maxValue,
int maxStep,
int cooldownMinutes,
- boolean dynamicMaxValue) {
+ boolean dynamicMaxValue,
+ String dynamicMaxSource,
+ String note) {
this.targetType = targetType;
this.targetKey = targetKey;
this.minValue = minValue;
@@ -74,6 +115,8 @@
this.maxStep = maxStep;
this.cooldownMinutes = cooldownMinutes;
this.dynamicMaxValue = dynamicMaxValue;
+ this.dynamicMaxSource = dynamicMaxSource;
+ this.note = note;
}
public AutoTuneTargetType getTargetType() {
@@ -103,5 +146,73 @@
public boolean isDynamicMaxValue() {
return dynamicMaxValue;
}
+
+ public String getDynamicMaxSource() {
+ return dynamicMaxSource;
+ }
+
+ public String getNote() {
+ return note;
+ }
+ }
+
+ private static final class RuleSpec {
+ private final AutoTuneTargetType targetType;
+ private final String targetKey;
+ private Integer minValue;
+ private Integer maxValue;
+ private int maxStep;
+ private int cooldownMinutes;
+ private String dynamicMaxSource;
+ private String note = DEFAULT_RULE_NOTE;
+
+ private RuleSpec(AutoTuneTargetType targetType, String targetKey) {
+ this.targetType = targetType;
+ this.targetKey = targetKey;
+ }
+
+ private RuleSpec minValue(Integer minValue) {
+ this.minValue = minValue;
+ return this;
+ }
+
+ private RuleSpec maxValue(Integer maxValue) {
+ this.maxValue = maxValue;
+ return this;
+ }
+
+ private RuleSpec maxStep(int maxStep) {
+ this.maxStep = maxStep;
+ return this;
+ }
+
+ private RuleSpec cooldownMinutes(int cooldownMinutes) {
+ this.cooldownMinutes = cooldownMinutes;
+ return this;
+ }
+
+ private RuleSpec dynamicMaxSource(String dynamicMaxSource) {
+ this.dynamicMaxSource = dynamicMaxSource;
+ return this;
+ }
+
+ private RuleSpec note(String note) {
+ this.note = note;
+ return this;
+ }
+
+ private Rule toRule() {
+ return new Rule(
+ targetType,
+ targetKey,
+ minValue,
+ maxValue,
+ maxStep,
+ cooldownMinutes,
+ dynamicMaxSource != null,
+ dynamicMaxSource,
+ note
+ );
+ }
}
}
diff --git a/src/main/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImpl.java b/src/main/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImpl.java
index 8b56cf2..a609520 100644
--- a/src/main/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImpl.java
+++ b/src/main/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImpl.java
@@ -6,7 +6,6 @@
import com.zy.ai.domain.autotune.AutoTuneRuleSnapshotItem;
import com.zy.ai.domain.autotune.AutoTuneSnapshot;
import com.zy.ai.domain.autotune.AutoTuneStationRuntimeItem;
-import com.zy.ai.domain.autotune.AutoTuneTargetType;
import com.zy.ai.domain.autotune.AutoTuneTaskSnapshot;
import com.zy.ai.service.AutoTuneSnapshotService;
import com.zy.ai.service.FlowTopologySnapshotService;
@@ -105,29 +104,11 @@
item.setMaxStep(rule.getMaxStep());
item.setCooldownMinutes(rule.getCooldownMinutes());
item.setDynamicMaxValue(rule.isDynamicMaxValue());
- item.setDynamicMaxSource(resolveDynamicMaxSource(rule));
- item.setNote(resolveRuleNote(rule));
+ item.setDynamicMaxSource(rule.getDynamicMaxSource());
+ item.setNote(rule.getNote());
result.add(item);
}
return result;
- }
-
- private String resolveDynamicMaxSource(AutoTuneRuleDefinition.Rule rule) {
- if (!AutoTuneTargetType.STATION.equals(rule.getTargetType())) {
- return null;
- }
- if (!"outTaskLimit".equals(rule.getTargetKey())) {
- return null;
- }
- return "currentParameterSnapshot.stationOutBufferCapacities[targetId]";
- }
-
- private String resolveRuleNote(AutoTuneRuleDefinition.Rule rule) {
- if (AutoTuneTargetType.STATION.equals(rule.getTargetType())
- && "outTaskLimit".equals(rule.getTargetKey())) {
- return "鍗曟璋冩暣骞呭害涓嶈兘瓒呰繃 maxStep锛涘澶ф椂涓嶅緱瓒呰繃瀵瑰簲绔欑偣 outBufferCapacity銆�";
- }
- return "鍗曟璋冩暣骞呭害涓嶈兘瓒呰繃 maxStep銆�";
}
private AutoTuneTaskSnapshot buildTaskSnapshot() {
diff --git a/src/main/java/com/zy/ai/utils/AiPromptUtils.java b/src/main/java/com/zy/ai/utils/AiPromptUtils.java
index 4d8baa9..d7be3d2 100644
--- a/src/main/java/com/zy/ai/utils/AiPromptUtils.java
+++ b/src/main/java/com/zy/ai/utils/AiPromptUtils.java
@@ -9,6 +9,11 @@
@Component
public class AiPromptUtils {
+ private static final String AUTO_TUNE_RULE_SNAPSHOT_INSTRUCTIONS =
+ "Step 4 璇诲彇璋冨弬瑙勫垯\n" +
+ "- 蹇呴』璇诲彇 snapshot.ruleSnapshot 涓殑 minValue銆乵axValue銆乵axStep銆乧ooldownMinutes銆乨ynamicMaxValue 鍜� dynamicMaxSource銆俓n" +
+ "- 姣忎釜鐩爣鍙傛暟鐨勬柊鍊间笌褰撳墠鍊煎樊鍊间笉鑳借秴杩囧搴� maxStep锛沷utTaskLimit 鐨勪笂璋冭繕蹇呴』鍙� stationOutBufferCapacities[targetId] 绾︽潫銆�";
+
public String getDefaultPrompt(String sceneCode) {
AiPromptScene scene = AiPromptScene.ofCode(sceneCode);
if (scene == null) {
@@ -158,9 +163,7 @@
"- maxOutTask锛氬搴� asr_bas_crnp.max_out_task / asr_bas_dual_crnp.max_out_task\n" +
"- maxInTask锛氬搴� asr_bas_crnp.max_in_task / asr_bas_dual_crnp.max_in_task\n\n" +
"娉ㄦ剰锛歛sr_bas_station.out_buffer_capacity 鏄汉宸ョ淮鎶ょ殑鍑哄簱缂撳瓨瀹归噺锛屽彧鐢ㄤ簬璇佹槑 outTaskLimit 鍙笂璋冧笂闄愶紝Agent 涓嶅厑璁镐慨鏀硅瀛楁锛涘澶� outTaskLimit 鏃跺缓璁�间笉寰楄秴杩囧搴旂珯鐐� outBufferCapacity銆俓n\n" +
- "Step 4 璇诲彇璋冨弬瑙勫垯\n" +
- "- 蹇呴』璇诲彇 snapshot.ruleSnapshot 涓殑 minValue銆乵axValue銆乵axStep銆乧ooldownMinutes銆乨ynamicMaxValue 鍜� dynamicMaxSource銆俓n" +
- "- 姣忎釜鐩爣鍙傛暟鐨勬柊鍊间笌褰撳墠鍊煎樊鍊间笉鑳借秴杩囧搴� maxStep锛沷utTaskLimit 鐨勪笂璋冭繕蹇呴』鍙� stationOutBufferCapacities[targetId] 绾︽潫銆俓n\n" +
+ AUTO_TUNE_RULE_SNAPSHOT_INSTRUCTIONS + "\n\n" +
"Step 5 鎻愪氦鍙樻洿\n" +
"- 鍏堥�氳繃 wcs_local_dispatch_apply_auto_tune_changes 鎵ц dry-run銆俓n" +
"- dry-run 閫氳繃鍚庢墠鍏佽閫氳繃鍚屼竴宸ュ叿瀹為檯搴旂敤銆俓n" +
diff --git a/src/main/resources/sql/20260427_add_ai_auto_tune_console_menu.sql b/src/main/resources/sql/20260427_add_ai_auto_tune_console_menu.sql
deleted file mode 100644
index 771f0cf..0000000
--- a/src/main/resources/sql/20260427_add_ai_auto_tune_console_menu.sql
+++ /dev/null
@@ -1,72 +0,0 @@
--- AI鑷姩璋冨弬鎺у埗鍙拌彍鍗曞閲忚剼鏈�
--- 鎵ц鍚庤鍦ㄢ�滆鑹叉巿鏉冣�濋噷缁欏搴旇鑹插嬀閫� AI绠$悊 -> AI鑷姩璋冨弬鎺у埗鍙般��
-
-SET @ai_manage_id := COALESCE(
- (
- SELECT id
- FROM sys_resource
- WHERE code = 'aiManage' AND level = 1
- ORDER BY id
- LIMIT 1
- ),
- (
- SELECT id
- FROM sys_resource
- WHERE name = 'AI绠$悊' AND level = 1
- ORDER BY id
- LIMIT 1
- )
-);
-
-INSERT INTO sys_resource(code, name, resource_id, level, sort, status)
-SELECT 'ai/auto_tune.html', 'AI鑷姩璋冨弬鎺у埗鍙�', @ai_manage_id, 2, 4, 1
-FROM dual
-WHERE @ai_manage_id IS NOT NULL
- AND NOT EXISTS (
- SELECT 1
- FROM sys_resource
- WHERE code = 'ai/auto_tune.html' AND level = 2
- );
-
-UPDATE sys_resource
-SET name = 'AI鑷姩璋冨弬鎺у埗鍙�',
- resource_id = @ai_manage_id,
- level = 2,
- sort = 4,
- status = 1
-WHERE code = 'ai/auto_tune.html' AND level = 2;
-
-SET @ai_auto_tune_id := (
- SELECT id
- FROM sys_resource
- WHERE code = 'ai/auto_tune.html' AND level = 2
- ORDER BY id
- LIMIT 1
-);
-
-INSERT INTO sys_resource(code, name, resource_id, level, sort, status)
-SELECT 'ai/auto_tune.html#view', '鏌ョ湅', @ai_auto_tune_id, 3, 1, 1
-FROM dual
-WHERE @ai_auto_tune_id IS NOT NULL
- AND NOT EXISTS (
- SELECT 1
- FROM sys_resource
- WHERE code = 'ai/auto_tune.html#view' AND level = 3
- );
-
-UPDATE sys_resource
-SET name = '鏌ョ湅',
- resource_id = @ai_auto_tune_id,
- level = 3,
- sort = 1,
- status = 1
-WHERE code = 'ai/auto_tune.html#view' AND level = 3;
-
-SELECT id, code, name, resource_id, level, sort, status
-FROM sys_resource
-WHERE code IN (
- 'aiManage',
- 'ai/auto_tune.html',
- 'ai/auto_tune.html#view'
-)
-ORDER BY level, sort, id;
diff --git a/src/main/resources/sql/20260427_add_ai_auto_tune_sys_configs.sql b/src/main/resources/sql/20260427_add_ai_auto_tune_sys_configs.sql
deleted file mode 100644
index 2cc66b0..0000000
--- a/src/main/resources/sql/20260427_add_ai_auto_tune_sys_configs.sql
+++ /dev/null
@@ -1,47 +0,0 @@
--- WCS鑷姩璋冨弬绯荤粺閰嶇疆
-
-INSERT INTO sys_config(name, code, value, type, status, select_type)
-SELECT 'AI鑷姩璋冨弬寮�鍏�', 'aiAutoTuneEnabled', 'N', 1, 1, 'system'
-FROM dual
-WHERE NOT EXISTS (
- SELECT 1
- FROM sys_config
- WHERE code = 'aiAutoTuneEnabled'
-);
-
-INSERT INTO sys_config(name, code, value, type, status, select_type)
-SELECT 'AI鑷姩璋冨弬闂撮殧(鍒嗛挓)', 'aiAutoTuneIntervalMinutes', '10', 1, 1, 'system'
-FROM dual
-WHERE NOT EXISTS (
- SELECT 1
- FROM sys_config
- WHERE code = 'aiAutoTuneIntervalMinutes'
-);
-
-INSERT INTO sys_config(name, code, value, type, status, select_type)
-SELECT 'AI鑷姩璋冨弬Prompt鏃ュ織淇濈暀涓婇檺', 'aiAutoTunePromptLogLimit', '500', 1, 1, 'system'
-FROM dual
-WHERE NOT EXISTS (
- SELECT 1
- FROM sys_config
- WHERE code = 'aiAutoTunePromptLogLimit'
-);
-
-INSERT INTO sys_config(name, code, value, type, status, select_type)
-SELECT '杈撻�佺珯鍑哄簱浠诲姟鍏ㄥ眬涓婇檺', 'conveyorStationTaskLimit', '30', 1, 1, 'system'
-FROM dual
-WHERE NOT EXISTS (
- SELECT 1
- FROM sys_config
- WHERE code = 'conveyorStationTaskLimit'
-);
-
-SELECT id, name, code, value, type, status, select_type
-FROM sys_config
-WHERE code IN (
- 'aiAutoTuneEnabled',
- 'aiAutoTuneIntervalMinutes',
- 'aiAutoTunePromptLogLimit',
- 'conveyorStationTaskLimit'
-)
-ORDER BY code;
diff --git a/src/main/resources/sql/20260427_add_out_buffer_capacity_to_asr_bas_station.sql b/src/main/resources/sql/20260427_add_out_buffer_capacity_to_asr_bas_station.sql
deleted file mode 100644
index 5e82347..0000000
--- a/src/main/resources/sql/20260427_add_out_buffer_capacity_to_asr_bas_station.sql
+++ /dev/null
@@ -1,55 +0,0 @@
--- asr_bas_station 澧炲姞鍑哄簱缂撳瓨瀹归噺閰嶇疆锛屾浛浠� asr_station_flow_capacity
--- 鐢ㄩ�旓細璇佹槑鍑哄簱绔欑偣 out_task_limit 鐨勫彲涓婅皟涓婇檺
--- 閫傜敤鏁版嵁搴擄細MySQL
-
-SET @current_db := DATABASE();
-
-SET @out_buffer_capacity_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @current_db
- AND TABLE_NAME = 'asr_bas_station'
- AND COLUMN_NAME = 'out_buffer_capacity'
-);
-
-SET @add_out_buffer_capacity_sql := IF(
- @out_buffer_capacity_exists = 0,
- 'ALTER TABLE asr_bas_station ADD COLUMN out_buffer_capacity INT NULL COMMENT ''鍑哄簱缂撳瓨瀹归噺锛岀敤浜庤瘉鏄� out_task_limit 涓婇檺'' AFTER out_task_limit',
- 'SELECT ''column out_buffer_capacity already exists'' '
-);
-PREPARE stmt_out_buffer_capacity FROM @add_out_buffer_capacity_sql;
-EXECUTE stmt_out_buffer_capacity;
-DEALLOCATE PREPARE stmt_out_buffer_capacity;
-
-SET @station_flow_capacity_exists := (
- SELECT COUNT(1)
- FROM information_schema.TABLES
- WHERE TABLE_SCHEMA = @current_db
- AND TABLE_NAME = 'asr_station_flow_capacity'
-);
-
-SET @migrate_station_flow_capacity_sql := IF(
- @station_flow_capacity_exists > 0,
- 'UPDATE asr_bas_station station
- JOIN asr_station_flow_capacity capacity
- ON capacity.station_id = station.station_id
- AND capacity.direction_code = ''OUT''
- AND capacity.buffer_capacity IS NOT NULL
- SET station.out_buffer_capacity = capacity.buffer_capacity
- WHERE station.out_buffer_capacity IS NULL',
- 'SELECT ''table asr_station_flow_capacity not exists'' '
-);
-PREPARE stmt_migrate_station_flow_capacity FROM @migrate_station_flow_capacity_sql;
-EXECUTE stmt_migrate_station_flow_capacity;
-DEALLOCATE PREPARE stmt_migrate_station_flow_capacity;
-
-SET @drop_station_flow_capacity_sql := IF(
- @station_flow_capacity_exists > 0,
- 'DROP TABLE asr_station_flow_capacity',
- 'SELECT ''table asr_station_flow_capacity already removed'' '
-);
-PREPARE stmt_drop_station_flow_capacity FROM @drop_station_flow_capacity_sql;
-EXECUTE stmt_drop_station_flow_capacity;
-DEALLOCATE PREPARE stmt_drop_station_flow_capacity;
-
-SHOW COLUMNS FROM asr_bas_station LIKE 'out_buffer_capacity';
diff --git a/src/main/resources/sql/20260427_create_ai_auto_tune_tables.sql b/src/main/resources/sql/20260427_create_ai_auto_tune_tables.sql
deleted file mode 100644
index 275f5fd..0000000
--- a/src/main/resources/sql/20260427_create_ai_auto_tune_tables.sql
+++ /dev/null
@@ -1,47 +0,0 @@
-CREATE TABLE IF NOT EXISTS `sys_ai_auto_tune_job` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `trigger_type` VARCHAR(32) NOT NULL COMMENT '瑙﹀彂绫诲瀷:auto/manual/revert',
- `status` VARCHAR(32) NOT NULL COMMENT '鎵ц鐘舵��:running/success/failed/rejected',
- `start_time` DATETIME NOT NULL COMMENT '寮�濮嬫椂闂�',
- `finish_time` DATETIME DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
- `has_active_tasks` TINYINT NOT NULL DEFAULT 0 COMMENT '鎵ц鏃舵槸鍚﹀瓨鍦ㄦ椿鍔ㄤ换鍔�:1鏄�0鍚�',
- `prompt_scene_code` VARCHAR(64) NOT NULL COMMENT 'Prompt鍦烘櫙缂栫爜',
- `summary` VARCHAR(512) DEFAULT NULL COMMENT '鎵ц鎽樿',
- `reasoning_digest` MEDIUMTEXT COMMENT '鎺ㄧ悊鎽樿',
- `snapshot_digest` MEDIUMTEXT COMMENT '蹇収鎽樿',
- `interval_before` INT DEFAULT NULL COMMENT '璋冨弬鍓嶈嚜鍔ㄨ皟鍙傞棿闅斿垎閽�',
- `interval_after` INT DEFAULT NULL COMMENT '璋冨弬鍚庤嚜鍔ㄨ皟鍙傞棿闅斿垎閽�',
- `success_count` INT NOT NULL DEFAULT 0 COMMENT '鎴愬姛鍙樻洿鏁�',
- `reject_count` INT NOT NULL DEFAULT 0 COMMENT '鎷掔粷鍙樻洿鏁�',
- `error_message` VARCHAR(1024) DEFAULT NULL COMMENT '閿欒淇℃伅',
- `llm_call_count` INT NOT NULL DEFAULT 0 COMMENT 'LLM璋冪敤娆℃暟',
- `prompt_tokens` INT NOT NULL DEFAULT 0 COMMENT 'Prompt tokens',
- `completion_tokens` INT NOT NULL DEFAULT 0 COMMENT 'Completion tokens',
- `total_tokens` INT NOT NULL DEFAULT 0 COMMENT '鎬籺okens',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- PRIMARY KEY (`id`),
- KEY `idx_sys_ai_auto_tune_job_status` (`status`),
- KEY `idx_sys_ai_auto_tune_job_start_time` (`start_time`),
- KEY `idx_sys_ai_auto_tune_job_finish_time` (`finish_time`),
- KEY `idx_sys_ai_auto_tune_job_create_time` (`create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI鑷姩璋冨弬浠诲姟瀹¤琛�';
-
-CREATE TABLE IF NOT EXISTS `sys_ai_auto_tune_change` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `job_id` BIGINT NOT NULL COMMENT '鑷姩璋冨弬浠诲姟ID',
- `target_type` VARCHAR(64) NOT NULL COMMENT '鐩爣绫诲瀷:sys_config/station/crnp/dual_crnp',
- `target_id` VARCHAR(64) DEFAULT NULL COMMENT '鐩爣ID',
- `target_key` VARCHAR(128) NOT NULL COMMENT '鐩爣鍙傛暟閿�',
- `old_value` VARCHAR(255) DEFAULT NULL COMMENT '鍘熷��',
- `requested_value` VARCHAR(255) DEFAULT NULL COMMENT '鐢宠鍊�',
- `applied_value` VARCHAR(255) DEFAULT NULL COMMENT '瀹為檯搴旂敤鍊�',
- `result_status` VARCHAR(32) NOT NULL COMMENT '缁撴灉鐘舵��:success/rejected/failed/dry_run',
- `reject_reason` VARCHAR(512) DEFAULT NULL COMMENT '鎷掔粷鍘熷洜',
- `cooldown_expire_time` DATETIME DEFAULT NULL COMMENT '鍐峰嵈鎴鏃堕棿',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- PRIMARY KEY (`id`),
- KEY `idx_sys_ai_auto_tune_change_job_id` (`job_id`),
- KEY `idx_sys_ai_auto_tune_change_result_status` (`result_status`),
- KEY `idx_sys_ai_auto_tune_change_cooldown` (`cooldown_expire_time`),
- KEY `idx_sys_ai_auto_tune_change_create_time` (`create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI鑷姩璋冨弬鍙樻洿瀹¤琛�';
diff --git a/src/main/resources/sql/20260427_update_auto_tune_prompt_out_buffer_capacity.sql b/src/main/resources/sql/20260427_update_auto_tune_prompt_out_buffer_capacity.sql
deleted file mode 100644
index 16d9292..0000000
--- a/src/main/resources/sql/20260427_update_auto_tune_prompt_out_buffer_capacity.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-UPDATE sys_ai_prompt_block block
-JOIN sys_ai_prompt_template template ON template.id = block.template_id
-SET block.content = CONCAT(
- block.content,
- '\n娉ㄦ剰锛歛sr_bas_station.out_buffer_capacity 鏄汉宸ョ淮鎶ょ殑鍑哄簱缂撳瓨瀹归噺锛屽彧鐢ㄤ簬璇佹槑 outTaskLimit 鍙笂璋冧笂闄愶紝Agent 涓嶅厑璁镐慨鏀硅瀛楁锛涘澶� outTaskLimit 鏃跺缓璁�间笉寰楄秴杩囧搴旂珯鐐� outBufferCapacity銆�'
-)
-WHERE template.scene_code = 'wcs_auto_tune_dispatch'
- AND block.block_type = 'scene_playbook'
- AND block.content NOT LIKE '%out_buffer_capacity 鏄汉宸ョ淮鎶ょ殑鍑哄簱缂撳瓨瀹归噺%';
diff --git a/src/main/resources/sql/20260427_update_auto_tune_prompt_rule_snapshot.sql b/src/main/resources/sql/20260427_update_auto_tune_prompt_rule_snapshot.sql
deleted file mode 100644
index d043366..0000000
--- a/src/main/resources/sql/20260427_update_auto_tune_prompt_rule_snapshot.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-UPDATE sys_ai_prompt_block block
-JOIN sys_ai_prompt_template template ON template.id = block.template_id
-SET block.content = CONCAT(
- block.content,
- '\n琛ュ厖锛氳鍙栬皟鍙傝鍒橽n- 蹇呴』璇诲彇 snapshot.ruleSnapshot 涓殑 minValue銆乵axValue銆乵axStep銆乧ooldownMinutes銆乨ynamicMaxValue 鍜� dynamicMaxSource銆俓n- 姣忎釜鐩爣鍙傛暟鐨勬柊鍊间笌褰撳墠鍊煎樊鍊间笉鑳借秴杩囧搴� maxStep锛沷utTaskLimit 鐨勪笂璋冭繕蹇呴』鍙� stationOutBufferCapacities[targetId] 绾︽潫銆�'
-)
-WHERE template.scene_code = 'wcs_auto_tune_dispatch'
- AND block.block_type = 'scene_playbook'
- AND block.content NOT LIKE '%snapshot.ruleSnapshot%';
diff --git a/src/main/resources/sql/20260428_ai_auto_tune_consolidated.sql b/src/main/resources/sql/20260428_ai_auto_tune_consolidated.sql
new file mode 100644
index 0000000..632f917
--- /dev/null
+++ b/src/main/resources/sql/20260428_ai_auto_tune_consolidated.sql
@@ -0,0 +1,256 @@
+-- AI鑷姩璋冨弬鍚堝苟澧為噺鑴氭湰
+-- 鍚堝苟鑼冨洿锛�2026-04-27 鑷� 2026-04-28 鑷姩璋冨弬鐩稿叧 SQL 鍙樻洿銆�
+-- 鎵ц璇存槑锛氬湪鐩爣搴撲腑鎵ц鏈枃浠朵竴娆″嵆鍙紱鑴氭湰鎸夊箓绛夋柟寮忕紪鍐欙紝宸插瓨鍦ㄥ璞′細璺宠繃鎴栨洿鏂般��
+-- 涓嶅寘鍚凡搴熷純鐨� asr_station_flow_capacity 寤鸿〃鑴氭湰锛涘鍘嗗彶搴撳瓨鍦ㄨ琛紝浼氳縼绉� OUT 瀹归噺鍒� asr_bas_station.out_buffer_capacity 鍚庡垹闄ゆ棫琛ㄣ��
+-- 鏉ユ簮鑴氭湰锛�
+-- - 20260427_create_ai_auto_tune_tables.sql
+-- - 20260427_add_ai_auto_tune_sys_configs.sql
+-- - 20260427_add_out_buffer_capacity_to_asr_bas_station.sql
+-- - 20260427_add_ai_auto_tune_console_menu.sql
+-- - 20260427_update_auto_tune_prompt_out_buffer_capacity.sql
+-- - 20260427_update_auto_tune_prompt_rule_snapshot.sql
+
+-- 1. AI鑷姩璋冨弬瀹¤琛�
+CREATE TABLE IF NOT EXISTS `sys_ai_auto_tune_job` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `trigger_type` VARCHAR(32) NOT NULL COMMENT '瑙﹀彂绫诲瀷:auto/manual/revert',
+ `status` VARCHAR(32) NOT NULL COMMENT '鎵ц鐘舵��:running/success/failed/rejected',
+ `start_time` DATETIME NOT NULL COMMENT '寮�濮嬫椂闂�',
+ `finish_time` DATETIME DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
+ `has_active_tasks` TINYINT NOT NULL DEFAULT 0 COMMENT '鎵ц鏃舵槸鍚﹀瓨鍦ㄦ椿鍔ㄤ换鍔�:1鏄�0鍚�',
+ `prompt_scene_code` VARCHAR(64) NOT NULL COMMENT 'Prompt鍦烘櫙缂栫爜',
+ `summary` VARCHAR(512) DEFAULT NULL COMMENT '鎵ц鎽樿',
+ `reasoning_digest` MEDIUMTEXT COMMENT '鎺ㄧ悊鎽樿',
+ `snapshot_digest` MEDIUMTEXT COMMENT '蹇収鎽樿',
+ `interval_before` INT DEFAULT NULL COMMENT '璋冨弬鍓嶈嚜鍔ㄨ皟鍙傞棿闅斿垎閽�',
+ `interval_after` INT DEFAULT NULL COMMENT '璋冨弬鍚庤嚜鍔ㄨ皟鍙傞棿闅斿垎閽�',
+ `success_count` INT NOT NULL DEFAULT 0 COMMENT '鎴愬姛鍙樻洿鏁�',
+ `reject_count` INT NOT NULL DEFAULT 0 COMMENT '鎷掔粷鍙樻洿鏁�',
+ `error_message` VARCHAR(1024) DEFAULT NULL COMMENT '閿欒淇℃伅',
+ `llm_call_count` INT NOT NULL DEFAULT 0 COMMENT 'LLM璋冪敤娆℃暟',
+ `prompt_tokens` INT NOT NULL DEFAULT 0 COMMENT 'Prompt tokens',
+ `completion_tokens` INT NOT NULL DEFAULT 0 COMMENT 'Completion tokens',
+ `total_tokens` INT NOT NULL DEFAULT 0 COMMENT '鎬籺okens',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ PRIMARY KEY (`id`),
+ KEY `idx_sys_ai_auto_tune_job_status` (`status`),
+ KEY `idx_sys_ai_auto_tune_job_start_time` (`start_time`),
+ KEY `idx_sys_ai_auto_tune_job_finish_time` (`finish_time`),
+ KEY `idx_sys_ai_auto_tune_job_create_time` (`create_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI鑷姩璋冨弬浠诲姟瀹¤琛�';
+
+CREATE TABLE IF NOT EXISTS `sys_ai_auto_tune_change` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `job_id` BIGINT NOT NULL COMMENT '鑷姩璋冨弬浠诲姟ID',
+ `target_type` VARCHAR(64) NOT NULL COMMENT '鐩爣绫诲瀷:sys_config/station/crnp/dual_crnp',
+ `target_id` VARCHAR(64) DEFAULT NULL COMMENT '鐩爣ID',
+ `target_key` VARCHAR(128) NOT NULL COMMENT '鐩爣鍙傛暟閿�',
+ `old_value` VARCHAR(255) DEFAULT NULL COMMENT '鍘熷��',
+ `requested_value` VARCHAR(255) DEFAULT NULL COMMENT '鐢宠鍊�',
+ `applied_value` VARCHAR(255) DEFAULT NULL COMMENT '瀹為檯搴旂敤鍊�',
+ `result_status` VARCHAR(32) NOT NULL COMMENT '缁撴灉鐘舵��:success/rejected/failed/dry_run',
+ `reject_reason` VARCHAR(512) DEFAULT NULL COMMENT '鎷掔粷鍘熷洜',
+ `cooldown_expire_time` DATETIME DEFAULT NULL COMMENT '鍐峰嵈鎴鏃堕棿',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ PRIMARY KEY (`id`),
+ KEY `idx_sys_ai_auto_tune_change_job_id` (`job_id`),
+ KEY `idx_sys_ai_auto_tune_change_result_status` (`result_status`),
+ KEY `idx_sys_ai_auto_tune_change_cooldown` (`cooldown_expire_time`),
+ KEY `idx_sys_ai_auto_tune_change_create_time` (`create_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI鑷姩璋冨弬鍙樻洿瀹¤琛�';
+
+-- 2. AI鑷姩璋冨弬绯荤粺閰嶇疆
+INSERT INTO sys_config(name, code, value, type, status, select_type)
+SELECT 'AI鑷姩璋冨弬寮�鍏�', 'aiAutoTuneEnabled', 'N', 1, 1, 'system'
+FROM dual
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM sys_config
+ WHERE code = 'aiAutoTuneEnabled'
+);
+
+INSERT INTO sys_config(name, code, value, type, status, select_type)
+SELECT 'AI鑷姩璋冨弬闂撮殧(鍒嗛挓)', 'aiAutoTuneIntervalMinutes', '10', 1, 1, 'system'
+FROM dual
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM sys_config
+ WHERE code = 'aiAutoTuneIntervalMinutes'
+);
+
+INSERT INTO sys_config(name, code, value, type, status, select_type)
+SELECT 'AI鑷姩璋冨弬Prompt鏃ュ織淇濈暀涓婇檺', 'aiAutoTunePromptLogLimit', '500', 1, 1, 'system'
+FROM dual
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM sys_config
+ WHERE code = 'aiAutoTunePromptLogLimit'
+);
+
+INSERT INTO sys_config(name, code, value, type, status, select_type)
+SELECT '杈撻�佺珯鍑哄簱浠诲姟鍏ㄥ眬涓婇檺', 'conveyorStationTaskLimit', '30', 1, 1, 'system'
+FROM dual
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM sys_config
+ WHERE code = 'conveyorStationTaskLimit'
+);
+
+-- 3. asr_bas_station 澧炲姞鍑哄簱缂撳瓨瀹归噺閰嶇疆锛屾浛浠� asr_station_flow_capacity
+SET @current_db := DATABASE();
+
+SET @out_buffer_capacity_exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @current_db
+ AND TABLE_NAME = 'asr_bas_station'
+ AND COLUMN_NAME = 'out_buffer_capacity'
+);
+
+SET @add_out_buffer_capacity_sql := IF(
+ @out_buffer_capacity_exists = 0,
+ 'ALTER TABLE asr_bas_station ADD COLUMN out_buffer_capacity INT NULL COMMENT ''鍑哄簱缂撳瓨瀹归噺锛岀敤浜庤瘉鏄� out_task_limit 涓婇檺'' AFTER out_task_limit',
+ 'SELECT ''column out_buffer_capacity already exists'' '
+);
+PREPARE stmt_out_buffer_capacity FROM @add_out_buffer_capacity_sql;
+EXECUTE stmt_out_buffer_capacity;
+DEALLOCATE PREPARE stmt_out_buffer_capacity;
+
+SET @station_flow_capacity_exists := (
+ SELECT COUNT(1)
+ FROM information_schema.TABLES
+ WHERE TABLE_SCHEMA = @current_db
+ AND TABLE_NAME = 'asr_station_flow_capacity'
+);
+
+SET @migrate_station_flow_capacity_sql := IF(
+ @station_flow_capacity_exists > 0,
+ 'UPDATE asr_bas_station station
+ JOIN asr_station_flow_capacity capacity
+ ON capacity.station_id = station.station_id
+ AND capacity.direction_code = ''OUT''
+ AND capacity.buffer_capacity IS NOT NULL
+ SET station.out_buffer_capacity = capacity.buffer_capacity
+ WHERE station.out_buffer_capacity IS NULL',
+ 'SELECT ''table asr_station_flow_capacity not exists'' '
+);
+PREPARE stmt_migrate_station_flow_capacity FROM @migrate_station_flow_capacity_sql;
+EXECUTE stmt_migrate_station_flow_capacity;
+DEALLOCATE PREPARE stmt_migrate_station_flow_capacity;
+
+SET @drop_station_flow_capacity_sql := IF(
+ @station_flow_capacity_exists > 0,
+ 'DROP TABLE asr_station_flow_capacity',
+ 'SELECT ''table asr_station_flow_capacity already removed'' '
+);
+PREPARE stmt_drop_station_flow_capacity FROM @drop_station_flow_capacity_sql;
+EXECUTE stmt_drop_station_flow_capacity;
+DEALLOCATE PREPARE stmt_drop_station_flow_capacity;
+
+-- 4. AI鑷姩璋冨弬鎺у埗鍙拌彍鍗�
+-- 鎵ц鍚庤鍦ㄢ�滆鑹叉巿鏉冣�濋噷缁欏搴旇鑹插嬀閫� AI绠$悊 -> AI鑷姩璋冨弬鎺у埗鍙般��
+SET @ai_manage_id := COALESCE(
+ (
+ SELECT id
+ FROM sys_resource
+ WHERE code = 'aiManage' AND level = 1
+ ORDER BY id
+ LIMIT 1
+ ),
+ (
+ SELECT id
+ FROM sys_resource
+ WHERE name = 'AI绠$悊' AND level = 1
+ ORDER BY id
+ LIMIT 1
+ )
+);
+
+INSERT INTO sys_resource(code, name, resource_id, level, sort, status)
+SELECT 'ai/auto_tune.html', 'AI鑷姩璋冨弬鎺у埗鍙�', @ai_manage_id, 2, 4, 1
+FROM dual
+WHERE @ai_manage_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1
+ FROM sys_resource
+ WHERE code = 'ai/auto_tune.html' AND level = 2
+ );
+
+UPDATE sys_resource
+SET name = 'AI鑷姩璋冨弬鎺у埗鍙�',
+ resource_id = @ai_manage_id,
+ level = 2,
+ sort = 4,
+ status = 1
+WHERE code = 'ai/auto_tune.html' AND level = 2;
+
+SET @ai_auto_tune_id := (
+ SELECT id
+ FROM sys_resource
+ WHERE code = 'ai/auto_tune.html' AND level = 2
+ ORDER BY id
+ LIMIT 1
+);
+
+INSERT INTO sys_resource(code, name, resource_id, level, sort, status)
+SELECT 'ai/auto_tune.html#view', '鏌ョ湅', @ai_auto_tune_id, 3, 1, 1
+FROM dual
+WHERE @ai_auto_tune_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1
+ FROM sys_resource
+ WHERE code = 'ai/auto_tune.html#view' AND level = 3
+ );
+
+UPDATE sys_resource
+SET name = '鏌ョ湅',
+ resource_id = @ai_auto_tune_id,
+ level = 3,
+ sort = 1,
+ status = 1
+WHERE code = 'ai/auto_tune.html#view' AND level = 3;
+
+-- 5. 鍘嗗彶宸插彂甯� Prompt 琛ヤ竵锛歰utBufferCapacity 绾︽潫璇存槑
+UPDATE sys_ai_prompt_block block
+JOIN sys_ai_prompt_template template ON template.id = block.template_id
+SET block.content = CONCAT(
+ block.content,
+ '\n娉ㄦ剰锛歛sr_bas_station.out_buffer_capacity 鏄汉宸ョ淮鎶ょ殑鍑哄簱缂撳瓨瀹归噺锛屽彧鐢ㄤ簬璇佹槑 outTaskLimit 鍙笂璋冧笂闄愶紝Agent 涓嶅厑璁镐慨鏀硅瀛楁锛涘澶� outTaskLimit 鏃跺缓璁�间笉寰楄秴杩囧搴旂珯鐐� outBufferCapacity銆�'
+)
+WHERE template.scene_code = 'wcs_auto_tune_dispatch'
+ AND block.block_type = 'scene_playbook'
+ AND block.content NOT LIKE '%out_buffer_capacity 鏄汉宸ョ淮鎶ょ殑鍑哄簱缂撳瓨瀹归噺%';
+
+-- 6. 鍘嗗彶宸插彂甯� Prompt 琛ヤ竵锛歳uleSnapshot 瑙勫垯璇存槑
+-- 杩藉姞鏂囨湰闇�涓� AiPromptUtils 鐨勯粯璁よ鍒欒鏄庝繚鎸佷竴鑷淬��
+UPDATE sys_ai_prompt_block block
+JOIN sys_ai_prompt_template template ON template.id = block.template_id
+SET block.content = CONCAT(
+ block.content,
+ '\nStep 4 璇诲彇璋冨弬瑙勫垯\n- 蹇呴』璇诲彇 snapshot.ruleSnapshot 涓殑 minValue銆乵axValue銆乵axStep銆乧ooldownMinutes銆乨ynamicMaxValue 鍜� dynamicMaxSource銆俓n- 姣忎釜鐩爣鍙傛暟鐨勬柊鍊间笌褰撳墠鍊煎樊鍊间笉鑳借秴杩囧搴� maxStep锛沷utTaskLimit 鐨勪笂璋冭繕蹇呴』鍙� stationOutBufferCapacities[targetId] 绾︽潫銆�'
+)
+WHERE template.scene_code = 'wcs_auto_tune_dispatch'
+ AND block.block_type = 'scene_playbook'
+ AND block.content NOT LIKE '%snapshot.ruleSnapshot%';
+
+-- 7. 鎵ц鍚庢鏌�
+SELECT id, name, code, value, type, status, select_type
+FROM sys_config
+WHERE code IN (
+ 'aiAutoTuneEnabled',
+ 'aiAutoTuneIntervalMinutes',
+ 'aiAutoTunePromptLogLimit',
+ 'conveyorStationTaskLimit'
+)
+ORDER BY code;
+
+SHOW COLUMNS FROM asr_bas_station LIKE 'out_buffer_capacity';
+
+SELECT id, code, name, resource_id, level, sort, status
+FROM sys_resource
+WHERE code IN (
+ 'aiManage',
+ 'ai/auto_tune.html',
+ 'ai/auto_tune.html#view'
+)
+ORDER BY level, sort, id;
diff --git a/src/main/webapp/views/ai/auto_tune.html b/src/main/webapp/views/ai/auto_tune.html
index 1c52d1f..1113755 100644
--- a/src/main/webapp/views/ai/auto_tune.html
+++ b/src/main/webapp/views/ai/auto_tune.html
@@ -372,10 +372,13 @@
</div>
</div>
<div class="map-box">
- <div class="map-title">璋冨弬瑙勫垯 maxStep/cooldown</div>
+ <div class="map-title">
+ <span>璋冨弬瑙勫垯 ruleSnapshot</span>
+ <el-button type="text" size="mini" @click="openJsonDialog('璋冨弬瑙勫垯 ruleSnapshot', ruleSnapshot)">JSON</el-button>
+ </div>
<div class="pill-row">
<span class="kv-pill" v-for="item in ruleSnapshot" :key="'r_' + item.targetType + '_' + item.targetKey">
- {{ item.targetType }}/{{ item.targetKey }}: 姝{ item.maxStep }} / 鍐穥{ item.cooldownMinutes }}m
+ {{ formatRuleSnapshotText(item) }}
</span>
<span class="small-muted" v-if="ruleSnapshot.length === 0">鏆傛棤鏁版嵁</span>
</div>
@@ -786,6 +789,24 @@
}
return result;
},
+ formatRuleSnapshotText: function(rule) {
+ var safeRule = rule || {};
+ var targetName = this.valueOrDash(safeRule.targetType) + '/' + this.valueOrDash(safeRule.targetKey);
+ var minValue = this.valueOrDash(safeRule.minValue);
+ var maxValue = this.valueOrDash(safeRule.maxValue);
+ var dynamicMaxValue = this.valueOrDash(safeRule.dynamicMaxValue);
+ var maxStep = this.valueOrDash(safeRule.maxStep);
+ var cooldownMinutes = this.valueOrDash(safeRule.cooldownMinutes);
+ var dynamicMaxSource = this.valueOrDash(safeRule.dynamicMaxSource);
+
+ return targetName
+ + ': min=' + minValue
+ + ' / max=' + maxValue
+ + ' / dynamicMax=' + dynamicMaxValue
+ + ' / maxStep=' + maxStep
+ + ' / cooldown=' + cooldownMinutes + 'm'
+ + ' / dynamicMaxSource=' + dynamicMaxSource;
+ },
statusType: function(status) {
if (status === 'success') {
return 'success';
diff --git a/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java b/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
index 278b1ae..1620f70 100644
--- a/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
+++ b/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
@@ -163,35 +163,41 @@
}
@Test
- void rejectCrnOutBatchRunningLimitRangeAndStepCases() {
+ void crnOutBatchRunningLimitAllowsStepThreeAndRejectsRangeAndStepCases() {
when(configService.getOne(any(Wrapper.class))).thenReturn(config("crnOutBatchRunningLimit", "10"));
service.apply(request(true,
command("sys_config", null, "crnOutBatchRunningLimit", "13"),
+ command("sys_config", null, "crnOutBatchRunningLimit", "14"),
command("sys_config", null, "crnOutBatchRunningLimit", "21")
));
List<AiAutoTuneChange> changes = savedChanges();
- assertEquals("rejected", changes.get(0).getResultStatus());
- assertTrue(changes.get(0).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 2"));
+ assertEquals("dry_run", changes.get(0).getResultStatus());
+ assertEquals("13", changes.get(0).getRequestedValue());
assertEquals("rejected", changes.get(1).getResultStatus());
- assertTrue(changes.get(1).getRejectReason().contains("1~20"));
+ assertTrue(changes.get(1).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 3"));
+ assertEquals("rejected", changes.get(2).getResultStatus());
+ assertTrue(changes.get(2).getRejectReason().contains("1~20"));
}
@Test
- void rejectMaxInTaskRangeAndStepCases() {
+ void maxInTaskAllowsStepThreeAndRejectsRangeAndStepCases() {
when(basCrnpService.getById(1)).thenReturn(crn(1, 1, 5));
service.apply(request(true,
- command("crn", "1", "maxInTask", "7"),
+ command("crn", "1", "maxInTask", "8"),
+ command("crn", "1", "maxInTask", "9"),
command("crn", "1", "maxInTask", "11")
));
List<AiAutoTuneChange> changes = savedChanges();
- assertEquals("rejected", changes.get(0).getResultStatus());
- assertTrue(changes.get(0).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 1"));
+ assertEquals("dry_run", changes.get(0).getResultStatus());
+ assertEquals("8", changes.get(0).getRequestedValue());
assertEquals("rejected", changes.get(1).getResultStatus());
- assertTrue(changes.get(1).getRejectReason().contains("0~10"));
+ assertTrue(changes.get(1).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 3"));
+ assertEquals("rejected", changes.get(2).getResultStatus());
+ assertTrue(changes.get(2).getRejectReason().contains("0~10"));
}
@Test
diff --git a/src/test/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImplTest.java b/src/test/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImplTest.java
index 5aba3a8..52fab9a 100644
--- a/src/test/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImplTest.java
+++ b/src/test/java/com/zy/ai/service/impl/AutoTuneSnapshotServiceImplTest.java
@@ -73,17 +73,25 @@
AutoTuneRuleSnapshotItem stationOutTaskRule = findRule(result, "station", "outTaskLimit");
assertEquals(0, stationOutTaskRule.getMinValue());
assertNull(stationOutTaskRule.getMaxValue());
- assertEquals(1, stationOutTaskRule.getMaxStep());
+ assertEquals(3, stationOutTaskRule.getMaxStep());
assertEquals(10, stationOutTaskRule.getCooldownMinutes());
assertEquals(Boolean.TRUE, stationOutTaskRule.getDynamicMaxValue());
assertEquals("currentParameterSnapshot.stationOutBufferCapacities[targetId]",
stationOutTaskRule.getDynamicMaxSource());
+ assertEquals("鍗曟璋冩暣骞呭害涓嶈兘瓒呰繃 maxStep锛涘澶ф椂涓嶅緱瓒呰繃瀵瑰簲绔欑偣 outBufferCapacity銆�",
+ stationOutTaskRule.getNote());
AutoTuneRuleSnapshotItem crnMaxOutRule = findRule(result, "crn", "maxOutTask");
assertEquals(3, crnMaxOutRule.getMaxStep());
+ assertNull(crnMaxOutRule.getDynamicMaxSource());
+ assertEquals("鍗曟璋冩暣骞呭害涓嶈兘瓒呰繃 maxStep銆�", crnMaxOutRule.getNote());
AutoTuneRuleSnapshotItem crnMaxInRule = findRule(result, "crn", "maxInTask");
- assertEquals(1, crnMaxInRule.getMaxStep());
+ assertEquals(3, crnMaxInRule.getMaxStep());
+
+ assertRuleMaxStep(result, "sys_config", "crnOutBatchRunningLimit", 3);
+ assertRuleMaxStep(result, "dual_crn", "maxOutTask", 3);
+ assertRuleMaxStep(result, "dual_crn", "maxInTask", 3);
}
@Test
@@ -187,4 +195,12 @@
}
throw new AssertionError("rule not found: " + targetType + "/" + targetKey);
}
+
+ private void assertRuleMaxStep(List<AutoTuneRuleSnapshotItem> rules,
+ String targetType,
+ String targetKey,
+ int expectedMaxStep) {
+ AutoTuneRuleSnapshotItem rule = findRule(rules, targetType, targetKey);
+ assertEquals(expectedMaxStep, rule.getMaxStep());
+ }
}
--
Gitblit v1.9.1