{"record":{"id":"3eccdfa331f590c8","repo":"jeecgboot/JeecgBoot","slug":"error-3eccdf","errorCode":null,"errorMessage":"请先添加变量或者记忆后再次重试！","messagePattern":"请先添加变量或者记忆后再次重试！","errorType":"exception","errorClass":"JeecgBootBizTipException","httpStatus":null,"severity":"warning","filePath":"jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragAppServiceImpl.java","lineNumber":97,"sourceCode":"        params.setFrequencyPenalty(0.1);\n        if(blocking){\n            String promptValue = aiChatHandler.completionsByDefaultModel(messages, params);\n            if (promptValue == null || promptValue.isEmpty()) {\n                return Result.error(\"生成失败\");\n            }\n            return Result.OK(\"success\", promptValue);\n        }else{\n            //update-begin---author:wangshuai---date:2026-01-08---for: 将流式输出单独抽出去，变量和记忆也需要---\n            return startSseChat(messages, params);\n            //update-end---author:wangshuai---date:2026-01-08---for: 将流式输出单独抽出去，变量和记忆也需要---\n        }\n    }\n\n    //update-begin---author:wangshuai---date:2026-01-05---for:【QQYUN-14479】增加一个开启记忆的按钮。下面为提示词和记忆，将记忆提示词单独拆分---\n    @Override\n    public Object generateMemoryByAppId(String variables, String memoryId, boolean blocking) {\n        if(oConvertUtils.isEmpty(variables) && oConvertUtils.isEmpty(memoryId)){\n            throw new JeecgBootBizTipException(\"请先添加变量或者记忆后再次重试！\");\n        }\n        // 构建变量描述\n        StringBuilder variablesDesc = new StringBuilder();\n        if (oConvertUtils.isNotEmpty(variables)) {\n            List<AppVariableVo> variableList = JSONArray.parseArray(variables, AppVariableVo.class);\n            if (variableList != null && !variableList.isEmpty()) {\n                for (AppVariableVo var : variableList) {\n                    if (var.getEnable() != null && !var.getEnable()) {\n                        continue;\n                    }\n                    String name = var.getName();\n                    if (oConvertUtils.isNotEmpty(var.getAction())) {\n                        String action = var.getAction();\n                        if (oConvertUtils.isNotEmpty(name)) {\n                            try {\n                                // 使用正则替换未被{{}}包裹的变量名\n                                String regex = \"(?<!\\\\{\\\\{)\\\\b\" + Pattern.quote(name) + \"\\\\b(?!\\\\}\\\\})\";\n                                action = action.replaceAll(regex, \"{{\" + name + \"}}\");","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragAppServiceImpl.java#L79-L115","documentation":"This error is thrown by AiragAppServiceImpl.generateMemoryByAppId() when both the variables parameter and the memoryId parameter are empty. The method generates AI memory content by combining variable definitions and memory context; if neither is provided, there is nothing to generate from, so it rejects the request immediately.","triggerScenarios":"A call to generateMemoryByAppId(variables, memoryId, blocking) where variables is empty/null AND memoryId is empty/null. The method uses oConvertUtils.isEmpty() which treats null, empty string, and whitespace-only strings as empty. This is a pre-condition validation check before attempting any LLM call.","commonSituations":"The AI application's memory generation is triggered from a UI where the user hasn't configured any variables or selected a memory. A programmatic caller omits both parameters. The app configuration was reset or migrated and lost its variable/memory definitions.","solutions":["Ensure at least one of variables or memoryId is provided when calling generateMemoryByAppId.","If using the AI app UI, verify that the app has at least one variable defined or a memory configured before triggering memory generation.","If calling programmatically, pass the app's variable JSON array or a valid memoryId from the conversation context.","Check the calling code to ensure it passes the correct values from the request or session."],"exampleFix":"// before — calling without required inputs\nairagAppService.generateMemoryByAppId(null, null, true);\n\n// after — provide at least one input\nairagAppService.generateMemoryByAppId(appVariablesJson, memoryId, true);","handlingStrategy":"validation","validationCode":"// Validate inputs before calling generateMemoryByAppId\nif ((variables == null || variables.trim().isEmpty())\n    && (memoryId == null || memoryId.trim().isEmpty())) {\n    // Provide user-facing guidance instead of hitting the exception\n    return Result.error(\"请先配置变量或选择记忆后再试\");\n}\nairagAppService.generateMemoryByAppId(variables, memoryId, blocking);","typeGuard":"public static boolean hasMemoryInputs(String variables, String memoryId) {\n    boolean hasVars = variables != null && !variables.trim().isEmpty();\n    boolean hasMem = memoryId != null && !memoryId.trim().isEmpty();\n    return hasVars || hasMem;\n}","tryCatchPattern":"try {\n    Object result = airagAppService.generateMemoryByAppId(variables, memoryId, blocking);\n    return result;\n} catch (JeecgBootBizTipException e) {\n    if (e.getMessage().contains(\"请先添加变量或者记忆\")) {\n        // Return user-friendly guidance instead of propagating the exception\n        return Result.error(\"请先为应用配置变量或记忆\");\n    }\n    throw e;\n}","preventionTips":["Validate at the controller/UI layer that at least one input is provided before calling the service","Implement UI guards that disable the 'generate memory' button when no variables or memories are configured","Cache the app's variable/memory configuration to pre-check before API calls"],"tags":["airag","ai-app","validation","memory"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}