package com.gxwebsoft.ai.service.impl; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.gxwebsoft.ai.constants.AuditContent8InternalControlConstants; import com.gxwebsoft.ai.service.AuditContent8InternalControlService; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import cn.hutool.core.util.StrUtil; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @Slf4j @Service public class AuditContent8InternalControlServiceImpl extends AbstractAuditContentService implements AuditContent8InternalControlService { // 工作流配置 private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-R1GN6zKkrfBYVMtwz8c6pyRM"; // 审计测试方法 private static final List TEST_METHODS = Arrays.asList( "符合性测试", "穿行测试", "抽样测试", "观察询问", "文档查阅" ); @Override public JSONObject generateInternalControlTableData(String kbIds, String libraryKbIds, String projectLibrary, String userName, String history, String suggestion) { log.info("开始生成单位层面财务管理内部控制测试表数据 - 用户: {}, kbIds: {}, libraryIds: {}, projectLibrary: {}", userName, kbIds, libraryKbIds, projectLibrary); long startTime = System.currentTimeMillis(); try { // 异步并行处理每个控制环节 Map> futures = processCategoriesAsync( Arrays.asList(AuditContent8InternalControlConstants.CONTROL_LINKS), controlLink -> generateControlLinkDataAsync(controlLink, kbIds, libraryKbIds, projectLibrary, userName, history, suggestion) ); // 等待所有异步任务完成 CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])).join(); // 合并所有分类的结果 JSONArray allData = mergeCategoryResults(Arrays.asList(AuditContent8InternalControlConstants.CONTROL_LINKS), futures); log.info("单位层面财务管理内部控制测试表生成成功 - 记录数: {}, 处理时间: {}ms", allData.size(), (System.currentTimeMillis() - startTime)); return buildSuccessResponse(allData, startTime, "internal_control_audit"); } catch (Exception e) { log.error("生成单位层面财务管理内部控制测试表失败", e); return buildErrorResponse("生成单位层面财务管理内部控制测试表失败: " + e.getMessage()); } } /** * 异步生成单个控制环节的数据 */ @Async public CompletableFuture generateControlLinkDataAsync(String controlLink, String kbIds, String libraryKbIds, String projectLibrary, String userName, String history, String suggestion) { return CompletableFuture.supplyAsync(() -> { try { log.info("开始生成控制环节 {} 的数据", controlLink); // 1. 为当前控制环节召回相关知识 Map> knowledgeSources = retrieveKnowledgeForControlLink( controlLink, kbIds, libraryKbIds, projectLibrary ); // 2. 构建完整的知识上下文 String knowledgeContext = buildCompleteKnowledgeContext( controlLink, knowledgeSources, history, suggestion ); // 3. 调用工作流生成数据 JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName); JSONArray controlLinkData = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, requestBody, "内部控制-" + controlLink); log.info("控制环节 {} 数据生成完成,生成 {} 条记录", controlLink, controlLinkData.size()); return controlLinkData; } catch (Exception e) { log.error("生成控制环节 {} 数据失败", controlLink, e); return new JSONArray(); } }); } /** * 为单个控制环节检索相关知识 */ private Map> retrieveKnowledgeForControlLink(String controlLink, String kbIds, String libraryKbIds, String projectLibrary) { Map> knowledgeSources = new HashMap<>(); knowledgeSources.put("enterprise", new ArrayList<>()); knowledgeSources.put("regulation", new ArrayList<>()); knowledgeSources.put("auditCase", new ArrayList<>()); // 构建当前控制环节的查询词 List controlQueries = buildControlLinkQueries(controlLink); // 企业单位库检索 if (StrUtil.isNotBlank(kbIds)) { Arrays.stream(kbIds.split(",")) .map(String::trim) .filter(StrUtil::isNotBlank) .forEach(kbId -> knowledgeSources.get("enterprise") .addAll(queryKnowledgeBase(kbId, controlQueries, 120))); } // 公共法律法规库检索 if (StrUtil.isNotBlank(libraryKbIds)) { Arrays.stream(libraryKbIds.split(",")) .map(String::trim) .filter(StrUtil::isNotBlank) .forEach(libId -> knowledgeSources.get("regulation") .addAll(queryKnowledgeBase(libId, controlQueries, 100))); } // 审计案例库检索 if (StrUtil.isNotBlank(projectLibrary)) { knowledgeSources.get("auditCase").addAll( queryKnowledgeBase(projectLibrary, controlQueries, 80)); } // 智能去重和排序 knowledgeSources.forEach((key, list) -> { List processed = list.stream() .distinct() .sorted(this::internalControlComparator) .limit(getLimitBySourceType(key)) .collect(Collectors.toList()); knowledgeSources.put(key, processed); }); log.debug("控制环节 {} 知识检索完成 - 企业: {}条, 法规: {}条, 案例: {}条", controlLink, knowledgeSources.get("enterprise").size(), knowledgeSources.get("regulation").size(), knowledgeSources.get("auditCase").size()); return knowledgeSources; } /** * 构建控制环节特定的查询词 */ private List buildControlLinkQueries(String controlLink) { // 根据控制环节构建相关查询词 List queries = new ArrayList<>(); // 通用查询词 queries.add(controlLink); queries.add("内部控制 " + controlLink); queries.add("财务管理 " + controlLink); // 根据特定控制环节添加相关关键词 if (controlLink.contains("岗位")) { queries.add("岗位职责 不相容职务分离"); queries.add("岗位设置 职责划分"); } if (controlLink.contains("授权审批")) { queries.add("授权审批流程 审批权限"); queries.add("财务管理授权"); } if (controlLink.contains("重大事项")) { queries.add("重大事项决策 集体决策"); queries.add("三重一大 财务管理"); } if (controlLink.contains("会计")) { queries.add("会计核算 会计档案"); queries.add("会计凭证 会计账簿"); } if (controlLink.contains("信息系统")) { queries.add("财务信息系统 数据备份"); queries.add("信息安全 用户管理"); } if (controlLink.contains("风险")) { queries.add("财务风险管理 风险识别"); queries.add("风险评估 风险应对"); } if (controlLink.contains("内部审计")) { queries.add("内审部门 审计监督"); queries.add("审计检查 审计报告"); } if (controlLink.contains("反舞弊")) { queries.add("财务舞弊 举报投诉"); queries.add("舞弊防范 举报保护"); } return queries; } /** * 构建完整的知识上下文 */ private String buildCompleteKnowledgeContext(String controlLink, Map> knowledgeSources, String history, String suggestion) { StringBuilder context = new StringBuilder(); // 1. 单位层面财务管理内部控制测试要求 context.append("## 单位层面财务管理内部控制测试要求 - ").append(controlLink).append("\n"); context.append("请基于以下知识生成").append(controlLink).append("相关的单位层面财务管理内部控制测试数据:\n\n"); context.append("1. 控制环节:").append(controlLink).append("\n"); context.append("2. 控制要求:").append(AuditContent8InternalControlConstants.CONTROL_REQUIREMENTS.get(controlLink)).append("\n"); context.append("3. 控制活动描述:").append(AuditContent8InternalControlConstants.CONTROL_ACTIVITIES.get(controlLink)).append("\n"); context.append("4. 控制职责岗位:").append(AuditContent8InternalControlConstants.CONTROL_POSITIONS.get(controlLink)).append("\n"); context.append("5. 测试步骤:\n"); AuditContent8InternalControlConstants.TEST_STEPS.get(controlLink).forEach(step -> context.append(" ").append(step).append("\n")); context.append("\n"); context.append("## 审计测试要求\n"); context.append("1. 基于测试步骤逐项检查,评估内部控制的有效性\n"); context.append("2. 检查证据必须具体到查阅的文件名称、内容、检查过程和发现的问题\n"); context.append("3. 测试结果必须基于充分证据严格判断:\n"); context.append(" - 通过:所有测试步骤均得到有效执行且证据充分\n"); context.append(" - 不通过:任一测试步骤未执行、执行不到位或证据不足\n"); context.append("4. 工作底稿索引必须填写实际存在的完整文件名\n"); context.append("5. 重点关注货币资金管理、财务报销、资产管理、物资采购等关键环节\n\n"); // 2. 数据格式要求 context.append("## 数据格式要求\n"); context.append("需要生成").append(controlLink).append("控制环节的内部控制测试数据:\n\n"); context.append("**重要:每个测试步骤必须单独生成一条记录**\n\n"); context.append("每条记录应包含以下字段:\n"); context.append("- controlLink(控制环节):固定值,不要修改\n"); context.append("- controlRequirement(控制要求):固定值,不要修改\n"); context.append("- controlActivity(控制活动描述):固定值,不要修改\n"); context.append("- controlPosition(控制职责岗位):固定值,不要修改\n"); context.append("- testSteps(测试步骤):**只包含当前步骤内容**,如\"(1)是否有制度规定\"\n"); context.append("- checkEvidence(检查证据):针对当前测试步骤的详细检查证据\n"); context.append("- testResult(测试结果):基于当前测试步骤的检查证据严格判断,只有证据充分且完全符合要求才能判定为\"通过\",否则必须判定为\"不通过\"\n"); context.append("- workPaperIndex(工作底稿索引):实际存在的完整文件名,确保能在文件夹中搜索到\n\n"); context.append("**生成规则:**\n"); context.append("1. **每个测试步骤单独生成一条完整记录**\n"); context.append("2. 如果测试步骤中有多个小点(如(1)、(2)、(3)),必须为每个小点生成独立记录\n"); context.append("3. 每条记录的检查证据必须专门针对该测试步骤\n"); context.append("4. 每条记录的测试结果必须基于该步骤的检查证据独立判断\n"); context.append("5. 控制环节、控制要求、控制活动描述、控制职责岗位字段在所有相关记录中保持相同\n\n"); context.append("**注意:**\n"); context.append("1. 检查证据必须详细描述:针对当前测试步骤查阅了哪些制度文件、检查了哪些业务凭证、访谈了哪些人员、发现了什么问题\n"); context.append("2. 测试结果判定必须严格,对于制度不健全、执行不到位、证据不充分的情况必须判定为\"不通过\"\n"); context.append("3. 工作底稿索引必须准确对应实际审计工作底稿文件名称,不能使用章节标题\n"); context.append("4. 审计检查可采用:符合性测试、穿行测试、抽样测试、观察询问、文档查阅等方法\n"); context.append("5. 重点关注内部控制制度的建立健全性和执行的有效性\n\n"); // 3. 审计测试方法参考 context.append("## 审计测试方法参考\n"); context.append("审计时可采用的测试方法:\n"); TEST_METHODS.forEach(method -> context.append("- ").append(method).append("\n")); context.append("\n"); // 4. 历史内容 if (StrUtil.isNotBlank(history)) { context.append("## 历史生成内容\n"); context.append("以下是之前生成的内容,请基于此进行优化:\n"); context.append(history).append("\n\n"); } // 5. 用户建议 if (StrUtil.isNotBlank(suggestion)) { context.append("## 用户优化建议\n"); context.append("请根据以下建议对生成内容进行调整:\n"); context.append(suggestion).append("\n\n"); } // 6. 企业单位知识 if (!knowledgeSources.get("enterprise").isEmpty()) { context.append("## 企业单位知识\n"); knowledgeSources.get("enterprise").forEach(knowledge -> context.append(knowledge).append("\n")); context.append("\n"); } // 7. 法律法规知识 if (!knowledgeSources.get("regulation").isEmpty()) { context.append("## 法律法规知识\n"); knowledgeSources.get("regulation").forEach(knowledge -> context.append(knowledge).append("\n")); context.append("\n"); } // 8. 审计案例知识 if (!knowledgeSources.get("auditCase").isEmpty()) { context.append("## 审计案例知识\n"); knowledgeSources.get("auditCase").forEach(knowledge -> context.append(knowledge).append("\n")); } return context.toString(); } /** * 内部控制相关性比较器 */ private int internalControlComparator(String reg1, String reg2) { int score1 = calculateInternalControlRelevanceScore(reg1); int score2 = calculateInternalControlRelevanceScore(reg2); return Integer.compare(score2, score1); } /** * 计算内部控制相关性分数 */ private int calculateInternalControlRelevanceScore(String content) { return AuditContent8InternalControlConstants.KEYWORD_WEIGHTS.entrySet().stream() .filter(entry -> content.contains(entry.getKey())) .mapToInt(Map.Entry::getValue) .sum(); } private int getLimitBySourceType(String sourceType) { switch (sourceType) { case "enterprise": return 120; case "regulation": return 100; case "auditCase": return 80; default: return 50; } } }