From be203b191bd153f35aae8679f31f88abef5e020b Mon Sep 17 00:00:00 2001 From: qianbao Date: Thu, 30 Jul 2026 23:41:40 +0800 Subject: [PATCH] 添加未清选择 改成动态引导语 --- src/main/java/com/xly/agent/DynamicPartAiAgent.java | 21 +++++++++++++++++++++ src/main/java/com/xly/agent/SystemPromptGenerator.java | 34 +++++++++++++++++++++++++++++++++- src/main/java/com/xly/config/ModelConfig.java | 20 ++++++++++++++++---- src/main/java/com/xly/entity/SceneDto.java | 2 -- src/main/java/com/xly/entity/ToolMeta.java | 3 +++ src/main/java/com/xly/entity/UserSceneSession.java | 8 ++++++++ src/main/java/com/xly/mapper/SceneMapper.java | 2 +- src/main/java/com/xly/mapper/ToolMetaMapper.java | 2 +- src/main/java/com/xly/service/DynamicPartService.java | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/com/xly/service/XlyErpService.java | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- src/main/java/com/xly/tool/DynamicToolProvider.java | 30 +++++++++++++++++++++++++----- 11 files changed, 499 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/xly/agent/DynamicPartAiAgent.java create mode 100644 src/main/java/com/xly/service/DynamicPartService.java diff --git a/src/main/java/com/xly/agent/DynamicPartAiAgent.java b/src/main/java/com/xly/agent/DynamicPartAiAgent.java new file mode 100644 index 0000000..6665822 --- /dev/null +++ b/src/main/java/com/xly/agent/DynamicPartAiAgent.java @@ -0,0 +1,21 @@ +package com.xly.agent; + +import dev.langchain4j.service.*; + +public interface DynamicPartAiAgent { + + /*** + * @Author 钱豹 + * @Date 12:52 2026/7/30 + * @Param [userId, userInput, sSystemPrompt] + * @return dev.langchain4j.service.Result + * @Description 动态部件构造器 + **/ + @SystemMessage("{{sSystemPrompt}}") + @UserMessage("用户输入:{{userInput}}") + Result getDynamicPartMethod( + @MemoryId String userId, + @V("userInput") String userInput, + @V("sSystemPrompt") String sSystemPrompt + ); +} \ No newline at end of file diff --git a/src/main/java/com/xly/agent/SystemPromptGenerator.java b/src/main/java/com/xly/agent/SystemPromptGenerator.java index 98d3d7c..dbfc7ef 100644 --- a/src/main/java/com/xly/agent/SystemPromptGenerator.java +++ b/src/main/java/com/xly/agent/SystemPromptGenerator.java @@ -1,6 +1,7 @@ package com.xly.agent; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONWriter; @@ -8,6 +9,7 @@ import com.xly.entity.ParamRule; import com.xly.entity.ToolMeta; import com.xly.entity.UserSceneSession; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -166,5 +168,35 @@ public class SystemPromptGenerator { return sb.toString(); } - + /*** + * @Author 钱豹 + * @Date 21:59 2026/7/30 + * @Param [partList] + * @return java.lang.String + * @Description 动态部件获取提示【印刷行业|增强校验版】 + **/ + public static String generateChoicePartPrompt(List partList) { + StringBuilder sb = new StringBuilder(); + sb.append("你是印刷行业部件提取工具。你的职责是理解印刷工艺需求文本,筛选部件名称,内文就是内页。\n\n"); + sb.append("【执行顺序&强制规则(严格按顺序执行)】\n"); + sb.append("第一步:逐条遍历【部件列表】内所有名称,逐一核对用户文本,收集所有匹配部件,不得跳过任何列表项。\n"); + sb.append("第二步:处理名称转换:识别到“内文”统一替换为“内页”,最终结果禁止出现\"内文\"\n"); + sb.append("第三步:扩展提取:扫描全文,如果存在印刷书刊部件名词,附带材质、克重、P数、工艺等描述,但该名词不在【部件列表】中,追加该部件名称;无配套描述则不追加。\n\n"); + sb.append("【任务】\n"); + sb.append("阅读用户印刷需求输入,提取所有符合规则的部件名称,全部输出,一个都不能少。\n"); + sb.append("【输出要求】\n"); + sb.append("- 只输出一个 JSON 数组,如:[\"封面\",\"内页\",\"拉页\"]\n"); + sb.append("- 如果用户输入中明确提到了某个部件,即使措辞略有不同,也要输出匹配的列表项\n"); + sb.append("- 如果没有任何部件匹配,输出 \"none\"\n"); + sb.append("- 不要输出解释、思考过程或 JSON 以外的任何文字。\n\n"); + sb.append("【部件列表】\n"); + sb.append(JSONUtil.toJsonStr(partList)); + sb.append("\n\n【印刷业务示例】\n"); + sb.append("- 用户输入:封面工艺:烫金,内文用纸80g双胶 → [\"封面\",\"内页\"]\n"); + sb.append("- 用户输入:内文250g铜版纸,插页8P、157g哑粉,封面157g哑粉烫金 → [\"内页\",\"封面\",\"插页\"]\n"); + sb.append("- 用户输入:护封材质特种纸,夹页4色印刷 → [\"护封\",\"夹页\"]\n"); + sb.append("- 用户输入\"你好\" → \"none\"\n"); + sb.append("\n**重要**:务必逐条核对部件列表,禁止遗漏列表内匹配项;不要受示例限制。\n"); + return sb.toString(); + } } \ No newline at end of file diff --git a/src/main/java/com/xly/config/ModelConfig.java b/src/main/java/com/xly/config/ModelConfig.java index 4ec9bdd..e974d0e 100644 --- a/src/main/java/com/xly/config/ModelConfig.java +++ b/src/main/java/com/xly/config/ModelConfig.java @@ -4,10 +4,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.xly.agent.ChatiAgent; -import com.xly.agent.DynamicTableNl2SqlAiAgent; -import com.xly.agent.SceneSelectorAiAgent; -import com.xly.agent.SecMethodAiAgent; +import com.xly.agent.*; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.ollama.OllamaChatModel; import dev.langchain4j.model.ollama.OllamaStreamingChatModel; @@ -188,4 +185,19 @@ public class ModelConfig { .maxSequentialToolsInvocations(1) .build(); } + + /** + * 方法选择 Agent(二级路由):从数据中获取到对应的 添加的部件名称,删除的部件名称 + * 分类任务,用极短记忆窗口避免被上文惯性带偏。 + */ + @Bean + public DynamicPartAiAgent dynamicPartAiAgent( + @Qualifier("chatLanguageModel") OllamaChatModel chatLanguageModel) { + return AiServices.builder(DynamicPartAiAgent.class) + .chatModel(chatLanguageModel) + .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(2)) + .maxSequentialToolsInvocations(1) + .build(); + } + } \ No newline at end of file diff --git a/src/main/java/com/xly/entity/SceneDto.java b/src/main/java/com/xly/entity/SceneDto.java index eb3958b..1ab057a 100644 --- a/src/main/java/com/xly/entity/SceneDto.java +++ b/src/main/java/com/xly/entity/SceneDto.java @@ -42,8 +42,6 @@ public class SceneDto { private String sSceneContext; - private String sKnowledgeBase; - private String sStatus; diff --git a/src/main/java/com/xly/entity/ToolMeta.java b/src/main/java/com/xly/entity/ToolMeta.java index c123ac5..843c99b 100644 --- a/src/main/java/com/xly/entity/ToolMeta.java +++ b/src/main/java/com/xly/entity/ToolMeta.java @@ -56,4 +56,7 @@ public class ToolMeta { private Boolean sQue = false; private Boolean bQuo = false; + private String sKnowledgeBase; + private String sdynamicMemo; + } diff --git a/src/main/java/com/xly/entity/UserSceneSession.java b/src/main/java/com/xly/entity/UserSceneSession.java index 7957225..18af617 100644 --- a/src/main/java/com/xly/entity/UserSceneSession.java +++ b/src/main/java/com/xly/entity/UserSceneSession.java @@ -2,6 +2,7 @@ package com.xly.entity; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import lombok.Data; import java.util.List; @@ -36,6 +37,9 @@ public class UserSceneSession { private List sUserQuestionList; private List authTool; + + //需要确认的动态部件 + private List dynamicPartList; /** * 是否已选择场景(true=已选,进入专属场景交互;false=未选,先展示选择界面) */ @@ -119,6 +123,10 @@ public class UserSceneSession { **/ private Boolean toolExecuted=false; + private Boolean bConfirmedDynamicPart =false; + private Boolean bConfirmedDynamicPartFist =false; + private String sDynamicPartUp= StrUtil.EMPTY; + /** * 构建场景选择提示语:展示权限内场景,引导用户选择 * @return 自然语言提示语 diff --git a/src/main/java/com/xly/mapper/SceneMapper.java b/src/main/java/com/xly/mapper/SceneMapper.java index ac5c9bd..78c6bde 100644 --- a/src/main/java/com/xly/mapper/SceneMapper.java +++ b/src/main/java/com/xly/mapper/SceneMapper.java @@ -11,6 +11,6 @@ import java.util.List; public interface SceneMapper { // XML配置方式 - @Select("SELECT A.*,fun_ai_getsKnowledgeBase(A.sId) AS sKnowledgeBase FROM ai_agent AS A order by iOrder") + @Select("SELECT A.* FROM ai_agent AS A order by iOrder") List findAll(); } \ No newline at end of file diff --git a/src/main/java/com/xly/mapper/ToolMetaMapper.java b/src/main/java/com/xly/mapper/ToolMetaMapper.java index 9bebb69..6a026f1 100644 --- a/src/main/java/com/xly/mapper/ToolMetaMapper.java +++ b/src/main/java/com/xly/mapper/ToolMetaMapper.java @@ -13,6 +13,6 @@ import java.util.List; public interface ToolMetaMapper { // XML配置方式 - @Select("SELECT A.* FROM ai_tool AS A order by iOrder") + @Select("SELECT A.*,fun_ai_getsKnowledgeBase(A.sSceneId,A.sId) AS sKnowledgeBase FROM ai_tool AS A order by iOrder") List findAll(); } \ No newline at end of file diff --git a/src/main/java/com/xly/service/DynamicPartService.java b/src/main/java/com/xly/service/DynamicPartService.java new file mode 100644 index 0000000..95d5ca2 --- /dev/null +++ b/src/main/java/com/xly/service/DynamicPartService.java @@ -0,0 +1,336 @@ +package com.xly.service; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSONObject; +import com.xly.agent.DynamicPartAiAgent; +import com.xly.agent.SystemPromptGenerator; +import com.xly.entity.ParamRule; +import com.xly.entity.UserSceneSession; +import com.xly.tool.DynamicToolProvider; +import com.xly.util.PinyinUtil; +import com.xly.util.Validator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/*** + * @Author 钱豹 + * @Date 22:39 2026/1/30 + * @Param + * @return + * @Description 动态部件提取类 + **/ +@Slf4j +@Service("dynamicPartService") +@RequiredArgsConstructor +public class DynamicPartService { + private final DynamicToolProvider dynamicToolProvider; + + private final DynamicPartAiAgent aiAgent; + + /*** + * @Author 钱豹 + * @Date 23:07 2026/7/29 + * @Description AI识别获取方法(二级路由:在当前场景内选出一个 sMethodNo) + **/ + public List dynamicPartDTOChoiceResult(String userId, String userInput, UserSceneSession session) { + //判断输入 + Boolean isConfirmed = dynamicToolProvider.isConfirmed(userInput,session); + if(ObjectUtil.isNotEmpty(session.getDynamicPartList())){ + List partList =session.getDynamicPartList(); + List partListBs = getPartBs(session); + // 移除 partList 中存在于 partListBs 的所有元素 + partList.removeAll(partListBs); + // 找出 partList 中存在于 partListPz 的元素 + List result = new ArrayList<>(partList); + List partListPz = getPartPz(session); + List partListAdd = new ArrayList<>(); + if(isConfirmed){ + //方法添加动态参数 + partListAdd.addAll(partList); + partList =null; + session.setBConfirmedDynamicPartFist(true); + } + if(!isConfirmed){ + //添加再配置中的动态 + result.retainAll(partListPz); + partListAdd.addAll(result); + partList =null; + session.setBConfirmedDynamicPartFist(true); + } + if(ObjectUtil.isNotEmpty(partListAdd)){ + //部件添加数据 + addToolMethod( partListAdd, session); + } + return partList; + } + + //如果存在动态部件 + if(ObjectUtil.isEmpty(session.getCurrentTool()) + || ObjectUtil.isEmpty(session.getCurrentTool().getSdynamicMemo()) + || session.getBConfirmedDynamicPart() + ){ + return null; + } + + List partList = getPart(session); + + // 5. 生成系统提示词 + String sSystemPrompt = SystemPromptGenerator.generateChoicePartPrompt(partList); + + // 3. 调大模型 + String raw = aiAgent.getDynamicPartMethod(userId, userInput, sSystemPrompt).content(); + log.debug("方法获取动态部件: userId={}, raw={}", userId, raw); + + // 4. 解析(含 ```json 容错) + List result = parseChoice(raw); + if (result == null || ObjectUtil.isEmpty(result)) { + return null; + } + // 5. none / 阈值 / 白名单 三重校验 + if ("none".equalsIgnoreCase(raw)) { + log.info("方法动态方法:无匹配部件, input={}", userInput); + return null; + } + session.setDynamicPartList(result); + return result; + } + + /*** + * @Author 钱豹 + * @Date 20:01 2026/7/30 + * @Param [partListAdd, session] + * @return void + * @Description 动态方法 添加参数 + **/ + private void addToolMethod(List partListAdd, UserSceneSession session) { + if (ObjectUtil.isEmpty(partListAdd)) { + return; + } + List paramRuleDataAll = new ArrayList<>(session.getCurrentTool().getParamRuleListAll()); + // 获取已有的动态部件名称,用于去重 + Set existingDynamicParts = new HashSet<>(); + // 筛选标准参数(只筛选一次,提高性能) + List standardParams = paramRuleDataAll.stream() + .filter(d -> ObjectUtil.isNotEmpty(d.getSGroup()) + && !d.getBDynamicParam() + && "部件".equals(d.getSGroup()) + && d.getBStandardParam()) + .collect(Collectors.toList()); + + if (ObjectUtil.isEmpty(standardParams)) { + log.warn("未找到部件标准参数,无法添加动态部件"); + return; + } + for (String sVal : partListAdd) { + // 去重:如果该部件已存在,跳过 + if (existingDynamicParts.contains(sVal)) { + log.debug("部件已存在,跳过: {}", sVal); + continue; + } + // 拼音转换 + String firstLetters = ""; + try { + firstLetters = PinyinUtil.convertToPinyin(sVal); + } catch (Exception e) { + log.warn("拼音转换失败: {}", sVal, e); + firstLetters = sVal.length() > 0 ? sVal.substring(0, 1).toUpperCase() : ""; + } + + // 遍历标准参数,生成动态参数 + for (ParamRule standard : standardParams) { + ParamRule copy = new ParamRule(); + BeanUtils.copyProperties(standard, copy); + + // 解析参数名:取 "-" 后的部分 + String paramName = standard.getSParam(); + if (paramName != null && paramName.contains("-")) { + String[] parts = paramName.split("-"); + paramName = parts.length > 1 ? parts[1] : parts[0]; + } + + copy.setSParam(sVal + "-" + paramName); + copy.setSParamValue(firstLetters + standard.getSParamValue()); + copy.setIOrder(standard.getIOrder() + 100000); + copy.setBDynamicParam(true); + copy.setSDynamicParam(sVal); + copy.setSDynamicParamName("sDynamicPart"); + + paramRuleDataAll.add(copy); + } + // 记录已添加的部件 + existingDynamicParts.add(sVal); + } + + // 重新筛选分类列表 + List paramRuleList = paramRuleDataAll.stream() + .filter(one -> Boolean.TRUE.equals(one.getBTipModel())) + .collect(Collectors.toList()); + + List paramRuleListCheck = paramRuleDataAll.stream() + .filter(one -> Boolean.TRUE.equals(one.getBEmpty())) + .collect(Collectors.toList()); + + // 更新 session + session.getCurrentTool().setParamRuleListAll(paramRuleDataAll); + session.getCurrentTool().setParamRuleListCheck(paramRuleListCheck); + session.getCurrentTool().setParamRuleList(paramRuleList); + + // 更新 args + Map args = new HashMap<>(); + if (ObjectUtil.isNotEmpty(session.getArgs())) { + args.putAll(session.getArgs()); + } + args.put("sDynamicPart", JSONUtil.toJsonStr(partListAdd)); + session.setArgs(args); + } + + + + /*** + * @Author 钱豹 + * @Date 18:13 2026/7/30 + * @Param [session] + * @return java.util.List + * @Description 获取部件 + **/ + private List getPart( UserSceneSession session){ + // 1. 获取参数规则列表 + List paramRuleAll = session.getCurrentTool().getParamRuleList(); + // 2. 从 ParamRule 中提取符合条件的部件名称 + Set partSet = new HashSet<>(); + if (ObjectUtil.isNotEmpty(paramRuleAll)) { + for (ParamRule rule : paramRuleAll) { + String sGroup = rule.getSGroup(); + String sParam = rule.getSParam(); + if ("部件".equals(sGroup) + && !"动态部件".equals(sParam) + && !"删除动态部件".equals(sParam)) { + // 取 "-" 前的部分作为部件名称 + String partName = sParam.contains("-") ? sParam.split("-")[0] : sParam; + partSet.add(partName); + } + } + } + + // 3. 从 sSdynamicMemo 中获取已保存的部件 + String sSdynamicMemo = session.getCurrentTool().getSdynamicMemo(); + Set mergedSet = new LinkedHashSet<>(); + + // 先加入 sSdynamicMemo 中的部件(保持原有顺序) + if (ObjectUtil.isNotEmpty(sSdynamicMemo)) { + String[] memoParts = sSdynamicMemo.split(","); + for (String part : memoParts) { + String trimmed = part.trim(); + if (!trimmed.isEmpty()) { + mergedSet.add(trimmed); + } + } + } + + // 再加入从 ParamRule 提取的部件(自动去重) + mergedSet.addAll(partSet); + + // 4. 转为 List + List partList = new ArrayList<>(mergedSet); + return partList; + } + + /*** + * @Author 钱豹 + * @Date 18:13 2026/7/30 + * @Param [session] + * @return java.util.List + * @Description 获取部件 + **/ + private List getPartBs( UserSceneSession session){ + // 1. 获取参数规则列表 + List paramRuleAll = session.getCurrentTool().getParamRuleList(); + // 2. 从 ParamRule 中提取符合条件的部件名称 + Set partSet = new HashSet<>(); + if (ObjectUtil.isNotEmpty(paramRuleAll)) { + for (ParamRule rule : paramRuleAll) { + String sGroup = rule.getSGroup(); + String sParam = rule.getSParam(); + if ("部件".equals(sGroup) + && !"动态部件".equals(sParam) + && !"删除动态部件".equals(sParam)) { + // 取 "-" 前的部分作为部件名称 + String partName = sParam.contains("-") ? sParam.split("-")[0] : sParam; + partSet.add(partName); + } + } + } + return new ArrayList<>(partSet); + } + + private List getPartPz( UserSceneSession session){ + String sSdynamicMemo = session.getCurrentTool().getSdynamicMemo(); + Set mergedSet = new LinkedHashSet<>(); + + // 先加入 sSdynamicMemo 中的部件(保持原有顺序) + if (ObjectUtil.isNotEmpty(sSdynamicMemo)) { + String[] memoParts = sSdynamicMemo.split(","); + for (String part : memoParts) { + String trimmed = part.trim(); + if (!trimmed.isEmpty()) { + mergedSet.add(trimmed); + } + } + } + return new ArrayList<>(mergedSet); + } + + /*** + * @Author 钱豹 + * @Date 23:07 2026/7/29 + * @Description + **/ + public String doCheckDynamicPart(String userId,String userInput,UserSceneSession session) { + List partList = getPart(session); + //判断是否存返回的部件是否有不存在 + List dDynamicPartList = session.getDynamicPartList(); + // 判断 dDynamicPartList 中不存在于 partList 的数据(即多余的、已失效的部件) + List invalidParts = new ArrayList<>(); + if (ObjectUtil.isNotEmpty(dDynamicPartList)) { + // 将 partList 转为 Set 提高查询效率 + Set partSet = new HashSet<>(partList); + for (String dynamicPart : dDynamicPartList) { + if (!partSet.contains(dynamicPart)) { + invalidParts.add(dynamicPart); + } + } + } + //存在动态部件,没有采集 需要添加参数 + if (ObjectUtil.isNotEmpty(dDynamicPartList) && ObjectUtil.isEmpty(invalidParts)) { + List partListBs = getPartBs(session); + // 移除 partList 中存在于 partListBs 的所有元素 + dDynamicPartList.removeAll(partListBs); + List partListAdd = new ArrayList<>(dDynamicPartList); + addToolMethod(partListAdd,session); + } + if(ObjectUtil.isNotEmpty(invalidParts)){ + return String.join(",", invalidParts)+"部件不存在,是否是部件,如果是,输入是,否则输入否"; + } + return null; + } + + + /** 解析模型输出,兼容被 ```json ... ``` 包裹或前后带杂字符的情况 */ + private List parseChoice(String raw) { + if (ObjectUtil.isEmpty(raw)) return null; + try { + return JSONUtil.toList(raw,String.class); + } catch (Exception e) { + log.error("方法路由结果解析失败, raw={}", raw, e); + return null; + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/xly/service/XlyErpService.java b/src/main/java/com/xly/service/XlyErpService.java index 409b6e4..55b62d1 100644 --- a/src/main/java/com/xly/service/XlyErpService.java +++ b/src/main/java/com/xly/service/XlyErpService.java @@ -49,6 +49,7 @@ import java.util.stream.IntStream; public class XlyErpService { //中文对话模型 private final OllamaChatModel chatModel; + private final DynamicPartService dynamicPartService; private final ChatiAgent chatiAgent; private final SceneSelectorAiAgent sceneSelectorAiAgent; private final UserSceneSessionService userSceneSessionService; @@ -340,8 +341,9 @@ public class XlyErpService { } List metaAll = dynamicToolProvider.metaAll; if(ObjectUtil.isNotEmpty(metaAll)){ + String finalInput = input; List metaOne = metaAll.stream().filter(m-> - userInput.equals(m.getSMethodName().trim()) || ("查询"+userInput).equals(m.getSMethodName().trim()) + finalInput.equals(m.getSMethodName().trim()) || ("查询"+ finalInput).equals(m.getSMethodName().trim()) ).collect(Collectors.toUnmodifiableList()); if(ObjectUtil.isNotEmpty(metaOne)){ session.setCurrentTool(metaOne.get(0)); @@ -363,13 +365,48 @@ public class XlyErpService { ErpAiAgent aiAgent = null; //不存在方法需要选择方法 if(ObjectUtil.isEmpty(session.getCurrentTool())){ - MethodChoiceResult mr = methodChoiceResult(userId, userInput, session); + MethodChoiceResult mr = methodChoiceResult(userId, input, session); if(ObjectUtil.isNotEmpty(mr) && ObjectUtil.isNotEmpty(mr.getSMethodNo())){ List metaOne = metaAll.stream().filter(m-> mr.getSMethodNo().equals(m.getSMethodNo().trim()) ).collect(Collectors.toUnmodifiableList()); session.setCurrentTool(metaOne.get(0)); } } + + //AI根据构件库 获取部件的名称获取到的数据放入动态部件参数 、然后方法添加动态部件 + if(ObjectUtil.isNotEmpty(session) + && ObjectUtil.isNotEmpty(session.getCurrentTool()) + && session.getCurrentTool().getBQuo() + && !session.getBConfirmedDynamicPart() + ){ + List dt = dynamicPartService.dynamicPartDTOChoiceResult(userId,input,session); + if(ObjectUtil.isNotEmpty(dt)){ + String sResponMessage = dynamicPartService.doCheckDynamicPart(userId,input,session); + if(ObjectUtil.isNotEmpty(sResponMessage)){ + session.setSDynamicPartUp(input); + return AiResponseDTO.builder().sSceneName(sceneName) + .sMethodName(session.getCurrentTool().getSMethodName()) + .aiText(sResponMessage) + .sCopyTo(session.getSCopyTo()) + .sCopyToSrcId(session.getSCopyToSrcId()) + .dbType(session.getDbType()) + .dbCach(session.getDbCach()) + .sReturnType(sReturnType) + .build(); + } + } + //返回上一次确认数据 + if(ObjectUtil.isNotEmpty(session.getSDynamicPartUp())){ + input = session.getSDynamicPartUp(); + } + } + //确认了动态部件 + session.setBConfirmedDynamicPart(true); + //如果输入的文字等于方法描述的文字,直接锁定方法 返回提示语 +// String sSceneId = session.getCurrentScene().getSId(); + String sResponMessage = StrUtil.EMPTY; + //用户输入添加方法(如果没有方法,动态SQL方法不需要) + Boolean isConfirmed = dynamicToolProvider.isConfirmed(input,session) && !session.getBConfirmedDynamicPartFist(); //还是不存在方法走老的方式兜底 if(ObjectUtil.isEmpty(session.getCurrentTool())){ // 4. 构建Agent,执行业务交互,如果返回为null,说明大模型没有判段出场景,必判断出后才能继续 @@ -379,20 +416,19 @@ public class XlyErpService { return getChatiAgent (input,session); } } - //如果输入的文字等于方法描述的文字,直接锁定方法 返回提示语 -// String sSceneId = session.getCurrentScene().getSId(); - String sResponMessage = StrUtil.EMPTY; - //用户输入添加方法(如果没有方法,动态SQL方法不需要) - Boolean isConfirmed = dynamicToolProvider.isConfirmed(input,session); if(!(ObjectUtil.isNotEmpty(session.getCurrentTool()) && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) ){ String sSystemPrompt =AgentSystemPrompt.sSystemPrompt; - if(ObjectUtil.isNotEmpty(session) && ObjectUtil.isNotEmpty(session.getCurrentScene()) - && "quotemanage".equals(session.getCurrentScene().getSSceneNo())){ + if(ObjectUtil.isNotEmpty(session) + && ObjectUtil.isNotEmpty(session.getCurrentTool()) + && ObjectUtil.isNotEmpty(session.getCurrentScene()) + && "quotemanage".equals(session.getCurrentScene().getSSceneNo()) + ){ sSystemPrompt =AgentSystemPrompt.sSystemPromptQuo; - sSystemPrompt = StrUtil.format(sSystemPrompt,session.getCurrentScene().getSKnowledgeBase()); + sSystemPrompt = StrUtil.format(sSystemPrompt,session.getCurrentTool().getSKnowledgeBase()); + } //如果客户输入了确认/生成 切换引导语言 if(ObjectUtil.isNotEmpty(session.getSSystemPrompt()) && isConfirmed){ @@ -404,12 +440,15 @@ public class XlyErpService { //报价每次定义参数 if(!isConfirmed && ObjectUtil.isNotEmpty(session) && ObjectUtil.isNotEmpty(session.getCurrentTool()) && session.getCurrentTool().getBQuo()){ - sSystemPrompt = SystemPromptGenerator.generate(session.getCurrentTool().getSMethodName(),session,session.getCurrentScene().getSKnowledgeBase()); + sSystemPrompt = SystemPromptGenerator.generate(session.getCurrentTool().getSMethodName(),session,session.getCurrentTool().getSKnowledgeBase()); aiAgent = createConfirmeAgent(session); } Result rs = aiAgent.chat(userId, input,sSystemPrompt); sResponMessage = rs.content(); } + //确认动态部件重置 + session.setBConfirmedDynamicPartFist(false); + session.setSDynamicPartUp(StrUtil.EMPTY); methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSMethodName():StrUtil.EMPTY; if(ObjectUtil.isNotEmpty(session.getCurrentTool()) && !ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) @@ -988,7 +1027,9 @@ public class XlyErpService { * @Description AI识别获取方法(二级路由:在当前场景内选出一个 sMethodNo) **/ private MethodChoiceResult methodChoiceResult(String userId, String userInput, UserSceneSession session) { - + if(ObjectUtil.isEmpty(session.getCurrentScene())){ + return null; + } // 1. 取当前场景下的可选方法(方法树扁平集合) List metaOne = dynamicToolProvider.metaAll.stream() .filter(m -> session.getCurrentScene().getSId().equals(m.getSSceneId())) @@ -1000,7 +1041,8 @@ public class XlyErpService { } // 2. 生成方法选择 prompt(行业知识库按需注入) - String sKnowledgeBase = session.getCurrentScene().getSKnowledgeBase(); // 无此字段就传 null + String sKnowledgeBase = StrUtil.EMPTY; + //session.getCurrentScene().getSKnowledgeBase(); // 无此字段就传 null String sSystemPrompt = SystemPromptGenerator.generateChoiceMethodPrompt(metaOne, sKnowledgeBase); // 3. 调大模型 diff --git a/src/main/java/com/xly/tool/DynamicToolProvider.java b/src/main/java/com/xly/tool/DynamicToolProvider.java index 8e3c59b..6c38695 100644 --- a/src/main/java/com/xly/tool/DynamicToolProvider.java +++ b/src/main/java/com/xly/tool/DynamicToolProvider.java @@ -211,7 +211,10 @@ public class DynamicToolProvider implements ToolProvider { if(ObjectUtil.isNotEmpty(sDynamicValueOld)){ List data = new ArrayList<>(); if (JSONUtil.isTypeJSONArray(sDynamicValueOld)) { - data = JSONUtil.toList(sDynamicValueOld, String.class); + try{ + data = JSONUtil.toList(sDynamicValueOld, String.class); + }catch (Exception e){} + } else { data.add(sDynamicValueOld); } @@ -220,7 +223,10 @@ public class DynamicToolProvider implements ToolProvider { if(ObjectUtil.isNotEmpty(sDynamicValue)){ List data = new ArrayList<>(); if (JSONUtil.isTypeJSONArray(sDynamicValue)) { - data = JSONUtil.toList(sDynamicValue, String.class); + try{ + data = JSONUtil.toList(sDynamicValue,String.class); + }catch (Exception e){ + } } else { data.add(sDynamicValue); } @@ -354,7 +360,12 @@ public class DynamicToolProvider implements ToolProvider { List addValue = new ArrayList<>(); if (JSONUtil.isTypeJSONArray(sValue)) { - addValue = JSONUtil.toList(sValue, String.class); + try{ + addValue = JSONUtil.toList(sValue, String.class); + }catch (Exception e){ + e.printStackTrace();; + } + } else { addValue.add(sValue); } @@ -437,7 +448,11 @@ public class DynamicToolProvider implements ToolProvider { : StrUtil.EMPTY; if (ObjectUtil.isNotEmpty(sValueDel)) { if (JSONUtil.isTypeJSONArray(sValueDel)) { - sDynamicPartDelValue = JSONUtil.toList(sValueDel, String.class); + try{ + sDynamicPartDelValue = JSONUtil.toList(sValueDel, String.class); + }catch (Exception e){ + e.printStackTrace();; + } } else { sDynamicPartDelValue.add(sValueDel); } @@ -459,7 +474,11 @@ public class DynamicToolProvider implements ToolProvider { List addValueOld = new ArrayList<>(); if(ObjectUtil.isNotEmpty(sValue)){ if (JSONUtil.isTypeJSONArray(sValue)) { - addValueOld = JSONUtil.toList(sValue, String.class); + try{ + addValueOld = JSONUtil.toList(sValue, String.class); + }catch (Exception e){ + e.printStackTrace();; + } } else { addValueOld.add(sValue); } @@ -521,6 +540,7 @@ public class DynamicToolProvider implements ToolProvider { log.info("动态部件已存在,跳过: {}", sVal); } } + // 移除不在 addValue 中的动态部件 // paramRuleDataAllNew = paramRuleDataAllNew.stream() // .filter(p -> { -- libgit2 0.22.2