SystemPromptGenerator.java 5.75 KB
package com.xly.agent;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.xly.entity.ParamRule;
import com.xly.entity.UserSceneSession;

import java.util.List;
import java.util.stream.Collectors;

public class SystemPromptGenerator {

    public static String generate(String toolName, UserSceneSession session) {
        StringBuilder sb = new StringBuilder();

        sb.append("你是一个无情的参数提取器,不是聊天助手。\n\n");
        sb.append("【核心任务】\n");
        sb.append("从用户输入中提取参数,并立即调用工具 ").append(toolName).append("。\n\n");
        sb.append("【绝对指令】\n");
        sb.append("1. 严禁与用户对话,严禁输出任何纯文本回复。\n");
        sb.append("2. 无论参数缺失多么严重,都必须直接调用工具,缺失字段填空字符串或0。\n");
        sb.append("3. 不要引导用户,后端程序会处理引导逻辑。\n\n");
        sb.append("【参数提取规则】\n");
        sb.append("用户输入格式为 \"参数名: 值\" 或 \"参数名 值\",你必须识别参数名并提取对应的值。\n\n");
        sb.append("【可提取的参数列表】\n");
        List<ParamRule> dynamicParamRuleAll = session.getCurrentTool().getParamRuleListAll();
        // 从参数定义中提取
        for (ParamRule paramRule : dynamicParamRuleAll) {
            sb.append("- ").append(paramRule.getSParam()).append("\n");
        }
        sb.append("\n【提取示例】\n");
        // 动态生成示例(取前3个参数作为示例)
        int count = 0;
        for (ParamRule paramRule : dynamicParamRuleAll) {
            if (count++ >= 3) break;
            sb.append("- 用户输入 \"").append(paramRule.getSParam()).append(": {值}\" → 提取 ").append(paramRule.getSParam()).append("\n");
        }

        if(ObjectUtil.isNotEmpty(session.getArgs())){
            sb.append("【已提取参数】\n");
            sb.append(JSON.toJSONString(session.getArgs(), JSONWriter.Feature.PrettyFormat));
        }
        sb.append("\n【工具调用规则】\n");
        sb.append("1. 每次只调用一次工具\n");
        sb.append("2. 调用后立即停止,不要重复调用\n");
        sb.append("3. 不要总结,不要回复用户,只调用工具");

        return sb.toString();
    }

    /**
     * 缺失参数统一提示模板:强制AI调用自定义方法,一次性回填所有参数
     */
    public static String buildMissParamPrompt(UserSceneSession session, List<ParamRule> paramRuleDataMiss) {
        String methodNo = session.getCurrentTool().getSMethodNo();
        // 1. 拼接缺失参数的描述(增加“参数名”和“英文名”的对应,方便模型映射)
        String paramDesc = paramRuleDataMiss.stream()
                .map(p -> String.format("- 参数名:%s (对应字段: %s),示例值:%s",
                        p.getSParam(), p.getSParamValue(), p.getSExampleValue()))
                .collect(Collectors.joining("\n"));
        // 但根据你的需求,其实 prompt 里并不需要强行插入一个空的 JSON 片段,
        // 直接告诉模型去“合并”即可。
        return String.format("""
            请你根据用户最新的输入,补充缺失的参数,并带着【所有完整参数】立即发起工具调用。
            
            【核心执行规则】
            1. **参数合并(至关重要)**:你必须保留上一轮对话中已经获取的参数(如 sSlaveId, operateType 等),并将用户本次提供的新参数与旧参数合并。
            2. **必须调用工具**:必须调用工具 `%s`。绝对禁止直接输出 JSON 文本,也绝对禁止向用户反问或索要信息。
            3. **完整调用**:请直接生成包含所有参数的 tool_calls 请求。
            【已获取数据】
            %s
            【当前缺失的参数说明】
            %s
            """, methodNo,JSONObject.toJSONString(session.getArgs()), paramDesc);
    }

    public static String buildDynamicSystemPrompt(UserSceneSession session) {
        // 获取当前工具编号(用于 JSON 的 name 字段)
        String methodNo = session.getCurrentTool().getSMethodNo();
        return """
            【极强约束·必须执行】
            1. 禁止说话!禁止解释!
            2. 必须调用工具!
            3. 只输出标准工具调用JSON!
            
            ### 任务背景 ###
            用户会输入自然语言指令(如“第1行确认”、“全部合并”等)。
            你的任务是:解析出【操作类型】和【目标行号】。
            
            ### 解析规则(必须严格遵守) ###
            
            1. **操作类型 (operateType)**:
               - 如果用户说“全部确认”、“生成多个单据”,识别为:"全部确认"
               - 如果用户说“合并确认”、“生成一个单据”,识别为:"合并确认"
               - 其他情况,默认为:"单行确认"
            
            2. **行号提取 (rowNumbers)**:
               - 单选:如“第5行”,提取为 [5]
               - 多选:如“第1、3、5行”,提取为 [1, 3, 5]
               - 范围:如“第2到4行”,提取为 [2, 3, 4]
               - 全选:如“全部”、“所有”,提取为 ["ALL"]
            
            ### 输出格式规范 ###
            请直接输出以下 JSON(不要任何 Markdown 格式,不要 ```json):
            {"name": "%s", "parameters": {"operateType": "解析出的类型", "rowNumbers": [行号数组或"ALL"]}}
            
            """.formatted(methodNo);
    }

}