feat: add auto tune schema and prompt scaffolding
| | |
| | | public enum AiPromptScene { |
| | | |
| | | DIAGNOSE_STREAM("wcs_diagnose_stream", "WCS巡检诊断"), |
| | | SENSOR_CHAT("wcs_sensor_chat", "WCS专家问答"); |
| | | SENSOR_CHAT("wcs_sensor_chat", "WCS专家问答"), |
| | | AUTO_TUNE_DISPATCH("wcs_auto_tune_dispatch", "WCS自动调参"); |
| | | |
| | | private final String code; |
| | | private final String label; |
| | |
| | | if (scene == AiPromptScene.SENSOR_CHAT) { |
| | | return getWcsSensorPromptMcp(); |
| | | } |
| | | if (scene == AiPromptScene.AUTO_TUNE_DISPATCH) { |
| | | return getAutoTuneDispatchPromptMcp(); |
| | | } |
| | | throw new IllegalArgumentException("不支持的 Prompt 场景: " + scene.getCode()); |
| | | } |
| | | |
| | |
| | | "- 【可执行的排查 / 处理建议】"); |
| | | return blocks; |
| | | } |
| | | if (scene == AiPromptScene.AUTO_TUNE_DISPATCH) { |
| | | blocks.put(AiPromptBlockType.BASE_POLICY, |
| | | "你是 WCS 自动调参 Agent,职责是在后台基于系统快照、历史调参记录和 MCP 工具事实,谨慎优化调度容量参数。\n\n" + |
| | | "你的目标是降低出库拥塞、减少无效堆积和过度并发,不追求一次性大幅调整。所有调参必须可审计、可回滚、可解释。"); |
| | | blocks.put(AiPromptBlockType.TOOL_POLICY, |
| | | "==================== 可用 MCP 工具 ====================\n\n" + |
| | | "你只能使用以下 MCP 工具进行自动调参工作:\n" + |
| | | "- dispatch_get_auto_tune_snapshot:获取当前调度、设备、站点、容量与可写参数快照\n" + |
| | | "- dispatch_get_recent_auto_tune_jobs:获取近期自动调参任务和变更结果\n" + |
| | | "- dispatch_apply_auto_tune_changes:提交调参变更,必须先 dry-run 再实际应用\n" + |
| | | "- dispatch_revert_last_auto_tune_job:仅在明确需要回滚最近一次调参时使用\n\n" + |
| | | "禁止调用上述列表之外的工具完成调参。禁止输出自由格式 JSON 让外层解析后调参;所有参数读取、试算、应用和回滚都必须通过 MCP 工具完成。\n\n" + |
| | | "实际应用前必须先调用 dispatch_apply_auto_tune_changes 执行 dry-run。只有 dry-run 返回允许应用且没有高风险拒绝原因时,才可以再次调用 dispatch_apply_auto_tune_changes 执行实际应用。"); |
| | | blocks.put(AiPromptBlockType.OUTPUT_CONTRACT, |
| | | "==================== 输出要求 ====================\n\n" + |
| | | "输出必须使用简体中文,并保持审计友好:\n" + |
| | | "1. 快照摘要:说明本轮依据的关键事实\n" + |
| | | "2. 调整计划:列出目标参数、原值、建议值和原因\n" + |
| | | "3. dry-run 结果:说明允许、拒绝或需要人工处理的原因\n" + |
| | | "4. 实际应用结果:只汇总 MCP 工具返回的应用状态\n" + |
| | | "5. 风险与观察点:说明下一轮应重点观察的指标\n\n" + |
| | | "如果没有足够事实支撑调参,输出“不调整”并说明缺少哪些 MCP 快照事实。"); |
| | | blocks.put(AiPromptBlockType.SCENE_PLAYBOOK, |
| | | "==================== 自动调参规则 ====================\n\n" + |
| | | "Step 1 获取事实\n" + |
| | | "- 先调用 dispatch_get_auto_tune_snapshot 获取后端快照/MCP facts。\n" + |
| | | "- 如需判断近期调参影响,再调用 dispatch_get_recent_auto_tune_jobs。\n" + |
| | | "- 方向与容量事实必须来自后端快照或 MCP facts,禁止从前端地图推断。\n\n" + |
| | | "Step 2 分析站点运行态\n" + |
| | | "- 运行时站点分析只能使用 autoing、loading、taskNo。\n" + |
| | | "- 禁止使用 taskWriteIdx 或 taskBufferItems 作为调参依据。\n\n" + |
| | | "Step 3 限制可写参数\n" + |
| | | "- sys_config.crnOutBatchRunningLimit\n" + |
| | | "- sys_config.conveyorStationTaskLimit\n" + |
| | | "- sys_config.aiAutoTuneIntervalMinutes\n" + |
| | | "- asr_bas_station.out_task_limit\n" + |
| | | "- asr_bas_crnp.maxOutTask\n" + |
| | | "- asr_bas_dual_crnp.maxOutTask\n" + |
| | | "- asr_bas_crnp.maxInTask\n" + |
| | | "- asr_bas_dual_crnp.maxInTask\n\n" + |
| | | "Step 4 提交变更\n" + |
| | | "- 先通过 dispatch_apply_auto_tune_changes 执行 dry-run。\n" + |
| | | "- dry-run 通过后才允许通过同一工具实际应用。\n" + |
| | | "- 如果工具返回拒绝、冷却中、存在活动任务风险或参数不在白名单内,必须停止实际应用。\n\n" + |
| | | "Step 5 回滚边界\n" + |
| | | "- 只有当最近一次自动调参被 MCP facts 明确证明造成异常,才允许调用 dispatch_revert_last_auto_tune_job。\n" + |
| | | "- 不得臆测回滚原因。"); |
| | | return blocks; |
| | | } |
| | | throw new IllegalArgumentException("不支持的 Prompt 场景: " + scene.getCode()); |
| | | } |
| | | |
| | |
| | | return getDefaultPromptBlocks(scene); |
| | | } |
| | | if ((scene == AiPromptScene.DIAGNOSE_STREAM && content.equals(getAiDiagnosePromptMcp())) |
| | | || (scene == AiPromptScene.SENSOR_CHAT && content.equals(getWcsSensorPromptMcp()))) { |
| | | || (scene == AiPromptScene.SENSOR_CHAT && content.equals(getWcsSensorPromptMcp())) |
| | | || (scene == AiPromptScene.AUTO_TUNE_DISPATCH && content.equals(getAutoTuneDispatchPromptMcp()))) { |
| | | return getDefaultPromptBlocks(scene); |
| | | } |
| | | LinkedHashMap<AiPromptBlockType, String> blocks = new LinkedHashMap<>(); |
| | |
| | | return prompt; |
| | | } |
| | | |
| | | //WCS自动调参Prompt |
| | | public String getAutoTuneDispatchPromptMcp() { |
| | | LinkedHashMap<AiPromptBlockType, String> blocks = getDefaultPromptBlocks(AiPromptScene.AUTO_TUNE_DISPATCH); |
| | | return String.join("\n\n", |
| | | blocks.get(AiPromptBlockType.BASE_POLICY), |
| | | blocks.get(AiPromptBlockType.TOOL_POLICY), |
| | | blocks.get(AiPromptBlockType.SCENE_PLAYBOOK), |
| | | blocks.get(AiPromptBlockType.OUTPUT_CONTRACT)); |
| | | } |
| | | |
| | | private String localTool(String name) { |
| | | return "wcs_local_" + name; |
| | | } |
| New file |
| | |
| | | -- 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' |
| | | ); |
| | | |
| | | SELECT id, name, code, value, type, status, select_type |
| | | FROM sys_config |
| | | WHERE code IN ( |
| | | 'aiAutoTuneEnabled', |
| | | 'aiAutoTuneIntervalMinutes', |
| | | 'aiAutoTunePromptLogLimit' |
| | | ) |
| | | ORDER BY code; |
| New file |
| | |
| | | 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 '总tokens', |
| | | `created_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_created_time` (`created_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 '冷却截止时间', |
| | | `created_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_created_time` (`created_time`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI自动调参变更审计表'; |
| New file |
| | |
| | | CREATE TABLE IF NOT EXISTS `asr_station_flow_capacity` ( |
| | | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键', |
| | | `station_id` INT NOT NULL COMMENT '站点ID', |
| | | `direction_code` VARCHAR(32) NOT NULL COMMENT '方向编码', |
| | | `buffer_capacity` INT NOT NULL DEFAULT 0 COMMENT '方向缓冲容量', |
| | | `memo` VARCHAR(255) DEFAULT NULL COMMENT '备注', |
| | | `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', |
| | | `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `uk_asr_station_flow_capacity_station_direction` (`station_id`, `direction_code`), |
| | | KEY `idx_asr_station_flow_capacity_station` (`station_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站点方向缓冲容量配置'; |