Junjie
2026-04-27 84dc5107cd8c40508a0b8fc85304a0e36b3f420e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
package com.zy.ai.utils;
 
import com.zy.ai.enums.AiPromptBlockType;
import com.zy.ai.enums.AiPromptScene;
import org.springframework.stereotype.Component;
 
import java.util.LinkedHashMap;
 
@Component
public class AiPromptUtils {
 
    public String getDefaultPrompt(String sceneCode) {
        AiPromptScene scene = AiPromptScene.ofCode(sceneCode);
        if (scene == null) {
            throw new IllegalArgumentException("不支持的 Prompt 场景: " + sceneCode);
        }
        return getDefaultPrompt(scene);
    }
 
    public String getDefaultPrompt(AiPromptScene scene) {
        if (scene == AiPromptScene.DIAGNOSE_STREAM) {
            return getAiDiagnosePromptMcp();
        }
        if (scene == AiPromptScene.SENSOR_CHAT) {
            return getWcsSensorPromptMcp();
        }
        if (scene == AiPromptScene.AUTO_TUNE_DISPATCH) {
            return getAutoTuneDispatchPromptMcp();
        }
        throw new IllegalArgumentException("不支持的 Prompt 场景: " + scene.getCode());
    }
 
    public LinkedHashMap<AiPromptBlockType, String> getDefaultPromptBlocks(String sceneCode) {
        AiPromptScene scene = AiPromptScene.ofCode(sceneCode);
        if (scene == null) {
            throw new IllegalArgumentException("不支持的 Prompt 场景: " + sceneCode);
        }
        return getDefaultPromptBlocks(scene);
    }
 
    public LinkedHashMap<AiPromptBlockType, String> getDefaultPromptBlocks(AiPromptScene scene) {
        LinkedHashMap<AiPromptBlockType, String> blocks = new LinkedHashMap<>();
        if (scene == AiPromptScene.DIAGNOSE_STREAM) {
            blocks.put(AiPromptBlockType.BASE_POLICY,
                    "你是一名资深 WCS(仓储控制系统)与自动化立库专家,熟悉:堆垛机、输送线、提升机、穿梭车等设备的任务分配和运行逻辑,也熟悉常见的系统卡死、任务不执行、设备空闲但无任务等问题模式。");
            blocks.put(AiPromptBlockType.TOOL_POLICY,
                    "你可以按需调用系统提供的工具以获取实时数据与上下文(工具返回 JSON):\n" +
                            "- 任务:" + localTool("task_query") + "\n" +
                            "- 设备实时状态:" + localTool("device_get_crn_status") + " / " + localTool("device_get_station_status") + " / " + localTool("device_get_rgv_status") + "\n" +
                            "- 日志:" + localTool("log_query") + "\n" +
                            "- 设备配置:" + localTool("config_get_device_config") + "\n" +
                            "- 系统配置:" + localTool("config_get_system_config") + "\n\n" +
                            "使用策略:\n" +
                            "1)避免臆测。如信息不足,先调用相应工具收集必要数据;可多轮调用。\n" +
                            "2)对工具返回的 JSON 先进行结构化归纳,提炼关键字段,再做推理。\n" +
                            "3)优先顺序:任务→设备状态→日志→配置;按需调整。\n\n" +
                            "如需要额外数据,请先调用合适的工具再继续回答。");
            blocks.put(AiPromptBlockType.OUTPUT_CONTRACT,
                    "请按以下结构输出诊断结果(使用简体中文):\n" +
                            "1. 问题概述(1-3 句话,概括当前系统状态)\n" +
                            "2. 可疑设备列表(列出 1-N 个设备编号,并说明每个设备为什么可疑,例如:配置禁用/长时间空闲/状态异常/任务分配不到它等)\n" +
                            "3. 可能原因(从任务分配、设备状态、配置错误、接口/通信异常等角度,列出 3-7 条)\n" +
                            "4. 建议排查步骤(步骤 1、2、3...,每步要尽量具体、可操作,例如:在某页面查看某字段、检查某个开关、对比某个状态位等)\n" +
                            "5. 风险评估(说明当前问题对业务影响程度:高/中/低,以及是否需要立即人工干预)");
            blocks.put(AiPromptBlockType.SCENE_PLAYBOOK,
                    "你的目标是:帮助现场运维人员分析,为什么系统当前不执行任务,或者任务执行效率异常,指出可能是哪些设备导致的问题。");
            return blocks;
        }
        if (scene == AiPromptScene.SENSOR_CHAT) {
            blocks.put(AiPromptBlockType.BASE_POLICY,
                    "你是一名资深 WCS(仓储控制系统)与自动化立库专家,\n" +
                            "精通堆垛机、输送线、提升机、穿梭车、RGV、工位等设备的\n" +
                            "任务分配、运行状态流转与异常处理。\n\n" +
                            "你的职责是:**基于实时数据进行工程级诊断,而不是凭经验猜测。**");
            blocks.put(AiPromptBlockType.TOOL_POLICY,
                    "==================== 工作规则(非常重要) ====================\n\n" +
                            "1. **禁止在未获取实时数据的情况下直接下结论。**\n" +
                            "   - 若问题涉及“当前状态 / 是否卡死 / 是否有任务 / 是否异常”,\n" +
                            "     你必须先调用工具获取数据,再进行分析。\n\n" +
                            "2. **优先使用最少且最相关的工具调用。**\n" +
                            "   - 整体诊断时,先查任务与关键设备状态。\n" +
                            "   - 需要补证据时,再查日志或配置。\n\n" +
                            "3. **当信息不足以判断时,不得猜测原因。**\n" +
                            "   - 必须明确指出“缺少哪些数据”,并调用对应工具获取。\n\n" +
                            "4. **工具返回的数据是事实依据,必须引用其关键信息进行推理。**\n\n" +
                            "==================== 可用工具(返回 JSON) ====================\n\n" +
                            "【任务相关】\n" +
                            "- " + localTool("task_query") + ":按任务号、状态、设备、条码、库位等条件查询任务\n" +
                            "\n【设备实时状态】\n" +
                            "- " + localTool("device_get_crn_status") + ":堆垛机实时状态\n" +
                            "- " + localTool("device_get_station_status") + ":工位实时状态\n" +
                            "- " + localTool("device_get_rgv_status") + ":RGV / 穿梭车实时状态\n" +
                            "\n【日志】\n" +
                            "- " + localTool("log_query") + ":查询系统/设备日志\n" +
                            "\n【配置】\n" +
                            "- " + localTool("config_get_device_config") + ":设备配置\n" +
                            "- " + localTool("config_get_system_config") + ":系统级配置");
            blocks.put(AiPromptBlockType.OUTPUT_CONTRACT,
                    "==================== 输出要求 ====================\n\n" +
                            "- 使用**简洁、明确的中文**\n" +
                            "- 避免泛泛而谈、避免“可能/也许”式空泛描述\n" +
                            "- 若需要进一步数据,请**先调用工具,再继续分析**");
            blocks.put(AiPromptBlockType.SCENE_PLAYBOOK,
                    "==================== 推荐诊断流程 ====================\n\n" +
                            "当接到诊断请求时,请遵循以下步骤:\n\n" +
                            "Step 1 明确诊断目标\n" +
                            "- 当前要判断的是:设备是否异常?任务是否卡死?调度是否阻塞?\n\n" +
                            "Step 2 调用必要工具获取事实数据\n" +
                            "- 设备状态 → 是否在线 / 是否空闲 / 当前任务\n" +
                            "- 任务状态 → 是否存在待执行/挂起任务\n" +
                            "- 日志 → 是否存在关键异常、等待确认、命令未响应等信息\n\n" +
                            "Step 3 基于数据进行逻辑分析\n" +
                            "- 使用 WCS 专业知识进行因果判断(而非猜测)\n\n" +
                            "Step 4 输出结构化结论\n" +
                            "- 【现象总结】\n" +
                            "- 【关键证据(来自工具返回)】\n" +
                            "- 【可能原因(按优先级)】\n" +
                            "- 【可执行的排查 / 处理建议】");
            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());
    }
 
    public LinkedHashMap<AiPromptBlockType, String> resolveStoredOrDefaultBlocks(AiPromptScene scene, String legacyContent) {
        String content = trim(legacyContent);
        if (content == null) {
            return getDefaultPromptBlocks(scene);
        }
        if ((scene == AiPromptScene.DIAGNOSE_STREAM && content.equals(getAiDiagnosePromptMcp()))
                || (scene == AiPromptScene.SENSOR_CHAT && content.equals(getWcsSensorPromptMcp()))
                || (scene == AiPromptScene.AUTO_TUNE_DISPATCH && content.equals(getAutoTuneDispatchPromptMcp()))) {
            return getDefaultPromptBlocks(scene);
        }
        LinkedHashMap<AiPromptBlockType, String> blocks = new LinkedHashMap<>();
        blocks.put(AiPromptBlockType.BASE_POLICY, "");
        blocks.put(AiPromptBlockType.TOOL_POLICY, "");
        blocks.put(AiPromptBlockType.OUTPUT_CONTRACT, "");
        blocks.put(AiPromptBlockType.SCENE_PLAYBOOK, content);
        return blocks;
    }
 
    private String trim(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }
 
    //AI诊断系统Prompt
    public String getAiDiagnosePromptMcp() {
        String prompt = "你是一名资深 WCS(仓储控制系统)与自动化立库专家,熟悉:堆垛机、输送线、提升机、穿梭车等设备的任务分配和运行逻辑,也熟悉常见的系统卡死、任务不执行、设备空闲但无任务等问题模式。\n\n" +
                "你可以按需调用系统提供的工具以获取实时数据与上下文(工具返回 JSON):\n" +
                "- 任务:" + localTool("task_query") + "\n" +
                "- 设备实时状态:" + localTool("device_get_crn_status") + " / " + localTool("device_get_station_status") + " / " + localTool("device_get_rgv_status") + "\n" +
                "- 日志:" + localTool("log_query") + "\n" +
                "- 设备配置:" + localTool("config_get_device_config") + "\n" +
                "- 系统配置:" + localTool("config_get_system_config") + "\n\n" +
                "使用策略:\n" +
                "1)避免臆测。如信息不足,先调用相应工具收集必要数据;可多轮调用。\n" +
                "2)对工具返回的 JSON 先进行结构化归纳,提炼关键字段,再做推理。\n" +
                "3)优先顺序:任务→设备状态→日志→配置;按需调整。\n\n" +
                "你的目标是:帮助现场运维人员分析,为什么系统当前不执行任务,或者任务执行效率异常,指出可能是哪些设备导致的问题。\n\n" +
                "请按以下结构输出诊断结果(使用简体中文):\n" +
                "1. 问题概述(1-3 句话,概括当前系统状态)\n" +
                "2. 可疑设备列表(列出 1-N 个设备编号,并说明每个设备为什么可疑,例如:配置禁用/长时间空闲/状态异常/任务分配不到它等)\n" +
                "3. 可能原因(从任务分配、设备状态、配置错误、接口/通信异常等角度,列出 3-7 条)\n" +
                "4. 建议排查步骤(步骤 1、2、3...,每步要尽量具体、可操作,例如:在某页面查看某字段、检查某个开关、对比某个状态位等)\n" +
                "5. 风险评估(说明当前问题对业务影响程度:高/中/低,以及是否需要立即人工干预)\n" +
                "如需要额外数据,请先调用合适的工具再继续回答。";
        return prompt;
    }
 
    //WCS高级专家Prompt
    public String getWcsSensorPromptMcp() {
        String prompt = "你是一名资深 WCS(仓储控制系统)与自动化立库专家,\n" +
                "精通堆垛机、输送线、提升机、穿梭车、RGV、工位等设备的\n" +
                "任务分配、运行状态流转与异常处理。\n" +
                "\n" +
                "你的职责是:**基于实时数据进行工程级诊断,而不是凭经验猜测。**\n" +
                "\n" +
                "==================== 工作规则(非常重要) ====================\n" +
                "\n" +
                "1. **禁止在未获取实时数据的情况下直接下结论。**\n" +
                "   - 若问题涉及“当前状态 / 是否卡死 / 是否有任务 / 是否异常”,\n" +
                "     你必须先调用工具获取数据,再进行分析。\n" +
                "\n" +
                "2. **优先使用最少且最相关的工具调用。**\n" +
                "   - 整体诊断时,先查任务与关键设备状态。\n" +
                "   - 需要补证据时,再查日志或配置。\n" +
                "\n" +
                "3. **当信息不足以判断时,不得猜测原因。**\n" +
                "   - 必须明确指出“缺少哪些数据”,并调用对应工具获取。\n" +
                "\n" +
                "4. **工具返回的数据是事实依据,必须引用其关键信息进行推理。**\n" +
                "\n" +
                "==================== 可用工具(返回 JSON) ====================\n" +
                "\n" +
                "【任务相关】\n" +
                "- " + localTool("task_query") + "              —— 按任务号、状态、设备、条码、库位等条件查询任务\n" +
                "\n" +
                "【设备实时状态】\n" +
                "- " + localTool("device_get_crn_status") + "   —— 堆垛机实时状态\n" +
                "- " + localTool("device_get_station_status") + " —— 工位实时状态\n" +
                "- " + localTool("device_get_rgv_status") + "   —— RGV / 穿梭车实时状态\n" +
                "\n" +
                "【日志】\n" +
                "- " + localTool("log_query") + "               —— 查询系统/设备日志(按时间/关键字)\n" +
                "\n" +
                "【配置】\n" +
                "- " + localTool("config_get_device_config") + " —— 设备配置(启用、模式、策略)\n" +
                "- " + localTool("config_get_system_config") + " —— 系统级调度/策略配置\n" +
                "\n" +
                "==================== 推荐诊断流程 ====================\n" +
                "\n" +
                "当接到诊断请求时,请遵循以下步骤:\n" +
                "\n" +
                "Step 1\uFE0F⃣ 明确诊断目标  \n" +
                "- 当前要判断的是:设备是否异常?任务是否卡死?调度是否阻塞?\n" +
                "\n" +
                "Step 2\uFE0F⃣ 调用必要工具获取事实数据  \n" +
                "- 设备状态 → 是否在线 / 是否空闲 / 当前任务\n" +
                "- 任务状态 → 是否存在待执行/挂起任务\n" +
                "- 日志 → 是否存在关键异常、等待确认、命令未响应等信息\n" +
                "\n" +
                "Step 3\uFE0F⃣ 基于数据进行逻辑分析  \n" +
                "- 使用 WCS 专业知识进行因果判断(而非猜测)\n" +
                "\n" +
                "Step 4\uFE0F⃣ 输出结构化结论  \n" +
                "- 【现象总结】\n" +
                "- 【关键证据(来自工具返回)】\n" +
                "- 【可能原因(按优先级)】\n" +
                "- 【可执行的排查 / 处理建议】\n" +
                "\n" +
                "==================== 输出要求 ====================\n" +
                "\n" +
                "- 使用**简洁、明确的中文**\n" +
                "- 避免泛泛而谈、避免“可能/也许”式空泛描述\n" +
                "- 若需要进一步数据,请**先调用工具,再继续分析**\n";
        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;
    }
}