优化审计内容1决策支出表内容
This commit is contained in:
@@ -14,8 +14,9 @@ public class AuditContent1ExpenseConstants {
|
|||||||
public static final String EXPENSE_TYPE_VEHICLE = "公车运行维护";
|
public static final String EXPENSE_TYPE_VEHICLE = "公车运行维护";
|
||||||
public static final String EXPENSE_TYPE_MEETING = "会议培训费";
|
public static final String EXPENSE_TYPE_MEETING = "会议培训费";
|
||||||
|
|
||||||
// 年度范围
|
// 年度范围 - 根据知识库动态确定,这里提供默认起始年份
|
||||||
public static final int[] YEAR_RANGE = {2020, 2021, 2022, 2023};
|
public static final int DEFAULT_START_YEAR = 2020;
|
||||||
|
public static final int DEFAULT_END_YEAR = 2023;
|
||||||
|
|
||||||
// 分类描述
|
// 分类描述
|
||||||
public static final Map<String, String> EXPENSE_DESCRIPTIONS = new HashMap<>();
|
public static final Map<String, String> EXPENSE_DESCRIPTIONS = new HashMap<>();
|
||||||
@@ -26,43 +27,78 @@ public class AuditContent1ExpenseConstants {
|
|||||||
EXPENSE_DESCRIPTIONS.put(EXPENSE_TYPE_MEETING, "会议、培训费用支出情况");
|
EXPENSE_DESCRIPTIONS.put(EXPENSE_TYPE_MEETING, "会议、培训费用支出情况");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据格式要求
|
// 数据格式要求 - 简化版
|
||||||
public static final String DATA_FORMAT_REQUIREMENT =
|
public static final String DATA_FORMAT_REQUIREMENT =
|
||||||
"每条记录应包含以下字段:\n" +
|
"请严格按照以下JSON格式生成数据,每类支出每个年度至少1条记录,总共至少16条记录:\n" +
|
||||||
"- expenseType:支出类型(公务接待/出国/公车运行维护/会议培训费)\n" +
|
"[\n" +
|
||||||
"- year:年份(2020-2023)\n" +
|
" {\n" +
|
||||||
"- finalStatementAmount:决算报表数(单位:元)\n" +
|
" \"expenseType\": \"公务接待/出国/公车运行维护/会议培训费\",\n" +
|
||||||
"- initialBudgetAmount:年初预算数(单位:元)\n" +
|
" \"year\": \"具体年份(根据知识库中的连续四个完整年度)\",\n" +
|
||||||
"- changePercentage:增减情况(%)\n" +
|
" \"finalStatementAmount\": \"决算报表数\",\n" +
|
||||||
"- budgetRatio:占年初预算比例(%)\n" +
|
" \"initialBudgetAmount\": \"年初预算数\",\n" +
|
||||||
"- remark:备注信息\n" +
|
" \"changePercentage\": \"增减百分比\",\n" +
|
||||||
"- dataSource:数据来源文件\n" +
|
" \"budgetRatio\": \"占年初预算比例\",\n" +
|
||||||
"- workPaperIndex:[相关文件FileId]";
|
" \"remark\": \"备注信息\",\n" +
|
||||||
|
" \"dataSource\": \"数据来源文件\",\n" +
|
||||||
|
" \"workPaperIndex\": [\"FileId1\", \"FileId2\"]\n" +
|
||||||
|
" }\n" +
|
||||||
|
"]";
|
||||||
|
|
||||||
// 关键词权重
|
// 关键词权重 - 增强工程类排除
|
||||||
public static final Map<String, Integer> KEYWORD_WEIGHTS = new HashMap<>();
|
public static final Map<String, Integer> KEYWORD_WEIGHTS = new HashMap<>();
|
||||||
static {
|
static {
|
||||||
KEYWORD_WEIGHTS.put("决算", 10);
|
// 高优先级:直接支出关键词
|
||||||
KEYWORD_WEIGHTS.put("预算", 10);
|
KEYWORD_WEIGHTS.put("公务接待", 15);
|
||||||
KEYWORD_WEIGHTS.put("公务接待", 9);
|
KEYWORD_WEIGHTS.put("出国", 15);
|
||||||
KEYWORD_WEIGHTS.put("出国", 9);
|
KEYWORD_WEIGHTS.put("公车运行维护", 15);
|
||||||
KEYWORD_WEIGHTS.put("公车", 9);
|
KEYWORD_WEIGHTS.put("会议培训费", 15);
|
||||||
KEYWORD_WEIGHTS.put("会议", 8);
|
KEYWORD_WEIGHTS.put("三公经费", 14);
|
||||||
KEYWORD_WEIGHTS.put("培训", 8);
|
KEYWORD_WEIGHTS.put("接待费", 13);
|
||||||
KEYWORD_WEIGHTS.put("支出", 8);
|
KEYWORD_WEIGHTS.put("差旅费", 12);
|
||||||
KEYWORD_WEIGHTS.put("费用", 7);
|
KEYWORD_WEIGHTS.put("车辆费", 12);
|
||||||
|
KEYWORD_WEIGHTS.put("会务费", 12);
|
||||||
|
KEYWORD_WEIGHTS.put("培训费", 12);
|
||||||
|
|
||||||
|
// 中优先级:财务文档
|
||||||
|
KEYWORD_WEIGHTS.put("决算报表", 10);
|
||||||
|
KEYWORD_WEIGHTS.put("预算报表", 10);
|
||||||
KEYWORD_WEIGHTS.put("财务报表", 9);
|
KEYWORD_WEIGHTS.put("财务报表", 9);
|
||||||
KEYWORD_WEIGHTS.put("年度报告", 8);
|
KEYWORD_WEIGHTS.put("部门决算", 9);
|
||||||
|
KEYWORD_WEIGHTS.put("部门预算", 9);
|
||||||
KEYWORD_WEIGHTS.put("预算执行", 8);
|
KEYWORD_WEIGHTS.put("预算执行", 8);
|
||||||
KEYWORD_WEIGHTS.put("财务分析", 7);
|
|
||||||
|
// 年份关键词(中等优先级,用于识别年度)
|
||||||
|
KEYWORD_WEIGHTS.put("年度", 7);
|
||||||
|
KEYWORD_WEIGHTS.put("年报表", 7);
|
||||||
|
KEYWORD_WEIGHTS.put("年度决算", 8);
|
||||||
|
KEYWORD_WEIGHTS.put("年度预算", 8);
|
||||||
|
|
||||||
|
// 低优先级:通用财务
|
||||||
|
KEYWORD_WEIGHTS.put("支出", 7);
|
||||||
|
KEYWORD_WEIGHTS.put("费用", 6);
|
||||||
|
KEYWORD_WEIGHTS.put("年度报告", 6);
|
||||||
|
|
||||||
|
// 排除工程类(负权重)
|
||||||
|
KEYWORD_WEIGHTS.put("工程造价", -20);
|
||||||
|
KEYWORD_WEIGHTS.put("概预算", -20);
|
||||||
|
KEYWORD_WEIGHTS.put("工程款", -15);
|
||||||
|
KEYWORD_WEIGHTS.put("施工", -15);
|
||||||
|
KEYWORD_WEIGHTS.put("项目投资", -15);
|
||||||
|
KEYWORD_WEIGHTS.put("基建", -15);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据来源关键词
|
// 需要排除的工程类关键词
|
||||||
public static final String[] DATA_SOURCE_KEYWORDS = {
|
public static final String[] ENGINEERING_EXCLUDE_KEYWORDS = {
|
||||||
"决算报表", "预算报表", "财务报告", "年度报告",
|
"工程造价", "概预算", "工程概算", "工程预算", "工程结算",
|
||||||
"预算执行情况", "经费使用情况", "支出明细", "费用分析"
|
"施工合同", "工程款", "项目投资", "基建", "工程项目"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 年份正则表达式,用于从知识库中提取年份
|
||||||
|
public static final String YEAR_PATTERN = "20\\d{2}";
|
||||||
|
|
||||||
|
// 最近几年范围(用于查询构建)
|
||||||
|
public static final int RECENT_YEARS_COUNT = 4;
|
||||||
|
|
||||||
private AuditContent1ExpenseConstants() {
|
private AuditContent1ExpenseConstants() {
|
||||||
// 防止实例化
|
// 防止实例化
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 检索相关知识
|
// 1. 检索相关知识(优化查询策略,避免工程类报表)
|
||||||
Map<String, List<String>> knowledgeSources = retrieveKnowledgeForExpense(kbIds, libraryKbIds, projectLibrary);
|
Map<String, List<String>> knowledgeSources = retrieveKnowledgeForExpense(kbIds, libraryKbIds, projectLibrary);
|
||||||
|
|
||||||
// 2. 构建完整的知识上下文
|
// 2. 构建完整的知识上下文
|
||||||
@@ -38,14 +38,24 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName);
|
JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName);
|
||||||
JSONArray expenseData = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, requestBody, "支出情况表");
|
JSONArray expenseData = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, requestBody, "支出情况表");
|
||||||
|
|
||||||
// 4. 数据验证和补充
|
// 4. 按 expenseType 和 year 排序
|
||||||
expenseData = validateAndEnhanceExpenseData(expenseData);
|
if (expenseData != null && !expenseData.isEmpty()) {
|
||||||
|
expenseData.sort((o1, o2) -> {
|
||||||
log.info("支出情况表生成成功 - 记录数: {}, 处理时间: {}ms",
|
JSONObject obj1 = (JSONObject) o1;
|
||||||
expenseData.size(), (System.currentTimeMillis() - startTime));
|
JSONObject obj2 = (JSONObject) o2;
|
||||||
|
// 先按 expenseType 排序
|
||||||
|
int typeCompare = obj1.getString("expenseType").compareTo(obj2.getString("expenseType"));
|
||||||
|
if (typeCompare != 0) {
|
||||||
|
return typeCompare;
|
||||||
|
}
|
||||||
|
// 再按 year 排序
|
||||||
|
return obj1.getString("year").compareTo(obj2.getString("year"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 不进行数据验证和补充,直接返回大模型输出
|
||||||
|
log.info("支出情况表生成成功 - 记录数: {}, 处理时间: {}ms", expenseData.size(), (System.currentTimeMillis() - startTime));
|
||||||
return buildSuccessResponse(expenseData, startTime, "expense_audit");
|
return buildSuccessResponse(expenseData, startTime, "expense_audit");
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("生成支出情况表失败", e);
|
log.error("生成支出情况表失败", e);
|
||||||
return buildErrorResponse("生成支出情况表失败: " + e.getMessage());
|
return buildErrorResponse("生成支出情况表失败: " + e.getMessage());
|
||||||
@@ -53,190 +63,7 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证和增强支出情况表数据
|
* 检索支出情况表相关知识 - 优化查询策略,排除工程类报表
|
||||||
*/
|
|
||||||
private JSONArray validateAndEnhanceExpenseData(JSONArray originalData) {
|
|
||||||
if (originalData == null || originalData.isEmpty()) {
|
|
||||||
log.warn("原始数据为空,返回空数组");
|
|
||||||
return new JSONArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONArray enhancedData = new JSONArray();
|
|
||||||
|
|
||||||
for (int i = 0; i < originalData.size(); i++) {
|
|
||||||
JSONObject item = originalData.getJSONObject(i);
|
|
||||||
if (item != null) {
|
|
||||||
// 确保所有必需字段都存在
|
|
||||||
enhanceExpenseData(item);
|
|
||||||
enhancedData.add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保数据完整性(至少16条记录)
|
|
||||||
// if (enhancedData.size() < 16) {
|
|
||||||
// enhancedData = supplementMissingExpenseData(enhancedData);
|
|
||||||
// }
|
|
||||||
|
|
||||||
log.info("数据增强完成 - 原始记录数: {}, 增强后记录数: {}", originalData.size(), enhancedData.size());
|
|
||||||
return enhancedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增强单个支出数据
|
|
||||||
*/
|
|
||||||
private void enhanceExpenseData(JSONObject expenseData) {
|
|
||||||
// 确保支出类型正确
|
|
||||||
String expenseType = expenseData.getString("expenseType");
|
|
||||||
if (StrUtil.isBlank(expenseType) || !isValidExpenseType(expenseType)) {
|
|
||||||
expenseData.put("expenseType", AuditContent1ExpenseConstants.EXPENSE_TYPE_RECEPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保年份在2020-2023范围内
|
|
||||||
String year = expenseData.getString("year");
|
|
||||||
if (StrUtil.isBlank(year) || !isValidYear(year)) {
|
|
||||||
expenseData.put("year", "2023");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保金额格式正确
|
|
||||||
if (StrUtil.isBlank(expenseData.getString("finalStatementAmount"))) {
|
|
||||||
expenseData.put("finalStatementAmount", "0.00");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StrUtil.isBlank(expenseData.getString("initialBudgetAmount"))) {
|
|
||||||
expenseData.put("initialBudgetAmount", "0.00");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算缺失的百分比字段
|
|
||||||
calculateMissingPercentages(expenseData);
|
|
||||||
|
|
||||||
// 确保数据来源
|
|
||||||
if (StrUtil.isBlank(expenseData.getString("dataSource"))) {
|
|
||||||
String yearStr = expenseData.getString("year");
|
|
||||||
expenseData.put("dataSource", yearStr + "年度部门决算报表");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保工作底稿索引是数组格式
|
|
||||||
// if (!expenseData.containsKey("workPaperIndex") || expenseData.get("workPaperIndex") == null) {
|
|
||||||
// JSONArray workPaperIndex = new JSONArray();
|
|
||||||
// workPaperIndex.add("《" + expenseData.getString("year") + "年度部门决算报表》");
|
|
||||||
// workPaperIndex.add("《" + expenseData.getString("year") + "年预算执行情况分析》");
|
|
||||||
// expenseData.put("workPaperIndex", workPaperIndex);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 补充缺失的支出数据
|
|
||||||
*/
|
|
||||||
// private JSONArray supplementMissingExpenseData(JSONArray existingData) {
|
|
||||||
// JSONArray supplementedData = new JSONArray();
|
|
||||||
// supplementedData.addAll(existingData);
|
|
||||||
//
|
|
||||||
// // 获取已存在的数据组合
|
|
||||||
// Set<String> existingCombinations = new HashSet<>();
|
|
||||||
// for (int i = 0; i < existingData.size(); i++) {
|
|
||||||
// JSONObject item = existingData.getJSONObject(i);
|
|
||||||
// String key = item.getString("expenseType") + "_" + item.getString("year");
|
|
||||||
// existingCombinations.add(key);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 补充缺失的数据
|
|
||||||
// String[] expenseTypes = {
|
|
||||||
// AuditContent1ExpenseConstants.EXPENSE_TYPE_RECEPTION,
|
|
||||||
// AuditContent1ExpenseConstants.EXPENSE_TYPE_OVERSEAS,
|
|
||||||
// AuditContent1ExpenseConstants.EXPENSE_TYPE_VEHICLE,
|
|
||||||
// AuditContent1ExpenseConstants.EXPENSE_TYPE_MEETING
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// String[] years = {"2020", "2021", "2022", "2023"};
|
|
||||||
//
|
|
||||||
// for (String expenseType : expenseTypes) {
|
|
||||||
// for (String year : years) {
|
|
||||||
// String key = expenseType + "_" + year;
|
|
||||||
// if (!existingCombinations.contains(key)) {
|
|
||||||
// JSONObject newItem = createDefaultExpenseRecord(expenseType, year);
|
|
||||||
// supplementedData.add(newItem);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return supplementedData;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建默认的支出记录
|
|
||||||
*/
|
|
||||||
// private JSONObject createDefaultExpenseRecord(String expenseType, String year) {
|
|
||||||
// JSONObject record = new JSONObject();
|
|
||||||
// record.put("expenseType", expenseType);
|
|
||||||
// record.put("year", year);
|
|
||||||
// record.put("finalStatementAmount", "0.00");
|
|
||||||
// record.put("initialBudgetAmount", "0.00");
|
|
||||||
// record.put("changePercentage", "0.0%");
|
|
||||||
// record.put("budgetRatio", "0.0%");
|
|
||||||
// record.put("remark", "根据年度财务报告数据生成");
|
|
||||||
// record.put("dataSource", year + "年度部门决算报表");
|
|
||||||
//
|
|
||||||
// JSONArray workPaperIndex = new JSONArray();
|
|
||||||
// workPaperIndex.add("《" + year + "年度部门决算报表》");
|
|
||||||
// workPaperIndex.add("《" + year + "年预算执行情况分析》");
|
|
||||||
// record.put("workPaperIndex", workPaperIndex);
|
|
||||||
//
|
|
||||||
// return record;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算缺失的百分比字段
|
|
||||||
*/
|
|
||||||
private void calculateMissingPercentages(JSONObject expenseData) {
|
|
||||||
try {
|
|
||||||
String finalAmountStr = expenseData.getString("finalStatementAmount").replace(",", "");
|
|
||||||
String budgetAmountStr = expenseData.getString("initialBudgetAmount").replace(",", "");
|
|
||||||
|
|
||||||
double finalAmount = Double.parseDouble(finalAmountStr);
|
|
||||||
double budgetAmount = Double.parseDouble(budgetAmountStr);
|
|
||||||
|
|
||||||
// 计算增减百分比
|
|
||||||
if (budgetAmount > 0) {
|
|
||||||
double changePercentage = ((finalAmount - budgetAmount) / budgetAmount) * 100;
|
|
||||||
if (!expenseData.containsKey("changePercentage") || StrUtil.isBlank(expenseData.getString("changePercentage"))) {
|
|
||||||
expenseData.put("changePercentage", String.format("%.1f%%", changePercentage));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算预算占比
|
|
||||||
double budgetRatio = (finalAmount / budgetAmount) * 100;
|
|
||||||
if (!expenseData.containsKey("budgetRatio") || StrUtil.isBlank(expenseData.getString("budgetRatio"))) {
|
|
||||||
expenseData.put("budgetRatio", String.format("%.1f%%", budgetRatio));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("计算百分比失败: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查支出类型是否有效
|
|
||||||
*/
|
|
||||||
private boolean isValidExpenseType(String expenseType) {
|
|
||||||
return expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_RECEPTION) ||
|
|
||||||
expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_OVERSEAS) ||
|
|
||||||
expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_VEHICLE) ||
|
|
||||||
expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_MEETING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查年份是否有效
|
|
||||||
*/
|
|
||||||
private boolean isValidYear(String year) {
|
|
||||||
for (int validYear : AuditContent1ExpenseConstants.YEAR_RANGE) {
|
|
||||||
if (year.equals(String.valueOf(validYear))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检索支出情况表相关知识 - 优化查询策略
|
|
||||||
*/
|
*/
|
||||||
private Map<String, List<String>> retrieveKnowledgeForExpense(String kbIds, String libraryKbIds, String projectLibrary) {
|
private Map<String, List<String>> retrieveKnowledgeForExpense(String kbIds, String libraryKbIds, String projectLibrary) {
|
||||||
Map<String, List<String>> knowledgeSources = new HashMap<>();
|
Map<String, List<String>> knowledgeSources = new HashMap<>();
|
||||||
@@ -244,8 +71,8 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
knowledgeSources.put("regulation", new ArrayList<>());
|
knowledgeSources.put("regulation", new ArrayList<>());
|
||||||
knowledgeSources.put("auditCase", new ArrayList<>());
|
knowledgeSources.put("auditCase", new ArrayList<>());
|
||||||
|
|
||||||
// 构建更全面的查询词
|
// 构建更精确的查询词,专门针对四类支出
|
||||||
List<String> queries = buildEnhancedExpenseQueries();
|
List<String> queries = buildPreciseExpenseQueries();
|
||||||
|
|
||||||
// 财务数据库检索
|
// 财务数据库检索
|
||||||
if (StrUtil.isNotBlank(kbIds)) {
|
if (StrUtil.isNotBlank(kbIds)) {
|
||||||
@@ -254,6 +81,10 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
.filter(StrUtil::isNotBlank)
|
.filter(StrUtil::isNotBlank)
|
||||||
.forEach(kbId -> {
|
.forEach(kbId -> {
|
||||||
List<String> financialKnowledge = queryKnowledgeBase(kbId, queries, 200);
|
List<String> financialKnowledge = queryKnowledgeBase(kbId, queries, 200);
|
||||||
|
|
||||||
|
// 过滤掉工程类报表内容
|
||||||
|
financialKnowledge = filterOutEngineeringReports(financialKnowledge);
|
||||||
|
|
||||||
knowledgeSources.get("financial").addAll(financialKnowledge);
|
knowledgeSources.get("financial").addAll(financialKnowledge);
|
||||||
log.debug("财务知识库 {} 检索到 {} 条相关知识", kbId, financialKnowledge.size());
|
log.debug("财务知识库 {} 检索到 {} 条相关知识", kbId, financialKnowledge.size());
|
||||||
});
|
});
|
||||||
@@ -265,21 +96,22 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
.filter(StrUtil::isNotBlank)
|
.filter(StrUtil::isNotBlank)
|
||||||
.forEach(libId -> {
|
.forEach(libId -> {
|
||||||
List<String> regulationKnowledge = queryKnowledgeBase(libId, queries, 100);
|
List<String> regulationKnowledge = queryKnowledgeBase(libId, queries, 50);
|
||||||
knowledgeSources.get("regulation").addAll(regulationKnowledge);
|
knowledgeSources.get("regulation").addAll(regulationKnowledge);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审计案例库检索
|
// 审计案例库检索
|
||||||
if (StrUtil.isNotBlank(projectLibrary)) {
|
if (StrUtil.isNotBlank(projectLibrary)) {
|
||||||
List<String> auditCaseKnowledge = queryKnowledgeBase(projectLibrary, queries, 50);
|
List<String> auditCaseKnowledge = queryKnowledgeBase(projectLibrary, queries, 30);
|
||||||
knowledgeSources.get("auditCase").addAll(auditCaseKnowledge);
|
knowledgeSources.get("auditCase").addAll(auditCaseKnowledge);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 智能去重和排序
|
// 智能去重、排序和过滤
|
||||||
knowledgeSources.forEach((key, list) -> {
|
knowledgeSources.forEach((key, list) -> {
|
||||||
List<String> processed = list.stream()
|
List<String> processed = list.stream()
|
||||||
.distinct()
|
.distinct()
|
||||||
|
.filter(this::isRelevantExpenseContent) // 过滤相关性
|
||||||
.sorted(this::expenseComparator)
|
.sorted(this::expenseComparator)
|
||||||
.limit(getLimitBySourceType(key))
|
.limit(getLimitBySourceType(key))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@@ -295,69 +127,114 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建增强的支出情况表查询词
|
* 构建精确的支出情况表查询词
|
||||||
*/
|
*/
|
||||||
private List<String> buildEnhancedExpenseQueries() {
|
private List<String> buildPreciseExpenseQueries() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
"决算报表 预算报表 财务报表 年度报告",
|
// 直接针对四类支出的查询
|
||||||
"公务接待费 接待费用 招待费用 餐饮费用",
|
"公务接待 接待费 招待费 餐饮费 公务用餐",
|
||||||
"出国费用 出境费用 国际差旅 境外考察",
|
"出国 出境 国际差旅 境外考察 出国费用",
|
||||||
"公车运行维护 车辆费用 汽车费用 交通费用",
|
"公车运行维护 车辆费 汽车费 交通费 公务用车",
|
||||||
"会议费 培训费 会务费 培训费用",
|
"会议培训费 会议费 培训费 会务费 培训支出",
|
||||||
"八项规定 三公经费 公务支出",
|
|
||||||
"预算执行 预算调整 超预算 预算控制",
|
// 财务文档查询(排除工程类)
|
||||||
"2020年 2021年 2022年 2023年",
|
"决算报表 公务接待 出国 公车 会议培训",
|
||||||
"支出明细 费用明细 开支情况",
|
"预算报表 三公经费 支出明细",
|
||||||
"财务分析 费用分析 支出分析"
|
"部门决算 公务支出 费用统计",
|
||||||
|
"部门预算 经费预算 支出预算",
|
||||||
|
|
||||||
|
// 通用年度查询,不指定具体年份,让知识库返回所有年份数据
|
||||||
|
"年度 公务接待 出国 公车 会议培训",
|
||||||
|
"决算 公务接待 出国 公车 会议培训",
|
||||||
|
"预算 公务接待 出国 公车 会议培训",
|
||||||
|
"三公经费 支出 决算 预算"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建完整的知识上下文 - 优化提示
|
* 过滤掉工程类报表内容
|
||||||
|
*/
|
||||||
|
private List<String> filterOutEngineeringReports(List<String> knowledgeList) {
|
||||||
|
return knowledgeList.stream()
|
||||||
|
.filter(content -> {
|
||||||
|
// 检查是否包含工程类关键词
|
||||||
|
for (String excludeKeyword : AuditContent1ExpenseConstants.ENGINEERING_EXCLUDE_KEYWORDS) {
|
||||||
|
if (content.contains(excludeKeyword)) {
|
||||||
|
log.debug("过滤工程类内容: {}", content.substring(0, Math.min(50, content.length())));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查内容是否与支出相关
|
||||||
|
*/
|
||||||
|
private boolean isRelevantExpenseContent(String content) {
|
||||||
|
String lowerContent = content.toLowerCase();
|
||||||
|
|
||||||
|
// 必须包含至少一个支出类型关键词
|
||||||
|
boolean hasExpenseType = lowerContent.contains("公务接待") ||
|
||||||
|
lowerContent.contains("接待费") ||
|
||||||
|
lowerContent.contains("出国") ||
|
||||||
|
lowerContent.contains("出境") ||
|
||||||
|
lowerContent.contains("公车") ||
|
||||||
|
lowerContent.contains("车辆费") ||
|
||||||
|
lowerContent.contains("会议") ||
|
||||||
|
lowerContent.contains("培训") ||
|
||||||
|
lowerContent.contains("三公经费");
|
||||||
|
|
||||||
|
// 排除工程类内容
|
||||||
|
boolean isEngineering = false;
|
||||||
|
for (String excludeKeyword : AuditContent1ExpenseConstants.ENGINEERING_EXCLUDE_KEYWORDS) {
|
||||||
|
if (content.contains(excludeKeyword)) {
|
||||||
|
isEngineering = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasExpenseType && !isEngineering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建完整的知识上下文 - 简化版本,只传递知识内容
|
||||||
*/
|
*/
|
||||||
private String buildCompleteKnowledgeContext(Map<String, List<String>> knowledgeSources, String history, String suggestion) {
|
private String buildCompleteKnowledgeContext(Map<String, List<String>> knowledgeSources, String history, String suggestion) {
|
||||||
StringBuilder context = new StringBuilder();
|
StringBuilder context = new StringBuilder();
|
||||||
|
|
||||||
// 1. 支出情况表分析要求 - 增强要求
|
// 1. 审计关注要点(简化版)
|
||||||
context.append("## 支出情况表分析要求\n");
|
context.append("## 审计关注要点\n");
|
||||||
context.append("请基于以下知识生成完整详细的公务接待/出国/公车运行维护/会议培训费等支出情况表数据:\n\n");
|
context.append("请基于以下知识生成完整的公务接待/出国/公车运行维护/会议培训费等支出情况表数据。\n");
|
||||||
context.append("1. 必须生成完整的支出情况表数据,覆盖2020-2023四个年度\n");
|
context.append("重点关注以下审计要点:\n");
|
||||||
context.append("2. 重点关注四类支出:公务接待、出国(出境)、公车运行维护、会议培训费\n");
|
context.append("1. 检查公务接待、出国、公车、会议培训四类支出的预算执行情况\n");
|
||||||
context.append("3. 从财务知识库中提取所有实际的支出数据,要求全面完整\n");
|
context.append("2. 对比年初预算数和决算报表数,分析增减情况\n");
|
||||||
context.append("4. 确保信息的准确性和完整性,包括决算数、预算数、增减情况和占比情况\n");
|
context.append("3. 关注是否存在未经预算批准变相公款消费的情况\n");
|
||||||
context.append("5. 工作底稿索引必须准确对应实际文件名称,可以包含多个相关文件\n");
|
context.append("4. 检查报销手续是否完善,是否存在超支使用\n\n");
|
||||||
context.append("6. 要求生成尽可能多、尽可能完整的支出记录,覆盖所有年份和支出类型\n\n");
|
|
||||||
|
|
||||||
// 2. 数据格式要求
|
// 2. 特别提醒
|
||||||
context.append("## 数据格式要求\n");
|
context.append("## 特别提醒\n");
|
||||||
context.append("需要生成完整详细的支出情况表数据:\n\n");
|
context.append("1. 必须准确识别支出类型:只提取\"公务接待\"、\"出国\"、\"公车运行维护\"、\"会议培训费\"四类支出\n");
|
||||||
context.append(AuditContent1ExpenseConstants.DATA_FORMAT_REQUIREMENT);
|
context.append("2. 不要将《工程造价和概(预)算执行情况表》等工程类报表误识别为\"三公经费\"报表\n");
|
||||||
context.append("\n\n重要要求:\n");
|
context.append("3. 工作底稿索引必须使用实际存在的完整文件名称作为FileId\n\n");
|
||||||
context.append("1. 必须根据知识库内容生成尽可能多、尽可能完整的支出信息\n");
|
|
||||||
context.append("2. 工作底稿索引必须准确对应实际文件名称,避免使用附表或章节标题\n");
|
|
||||||
context.append("3. 金额单位为元,保持两位小数,可以使用逗号分隔千位\n");
|
|
||||||
context.append("4. 百分比计算要准确,增减情况正数表示增长,负数表示减少\n");
|
|
||||||
context.append("5. 数据来源要具体,如:2023年度部门决算报表\n");
|
|
||||||
context.append("6. 备注信息可以包含超支原因、特殊情况说明等\n\n");
|
|
||||||
|
|
||||||
// 3. 历史内容
|
// 3. 历史内容
|
||||||
if (StrUtil.isNotBlank(history)) {
|
if (StrUtil.isNotBlank(history)) {
|
||||||
context.append("## 历史生成内容\n");
|
context.append("## 历史生成内容参考\n");
|
||||||
context.append("以下是之前生成的内容,请基于此进行优化和补充:\n");
|
|
||||||
context.append(history).append("\n\n");
|
context.append(history).append("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 用户建议
|
// 4. 用户建议
|
||||||
if (StrUtil.isNotBlank(suggestion)) {
|
if (StrUtil.isNotBlank(suggestion)) {
|
||||||
context.append("## 用户优化建议\n");
|
context.append("## 用户优化建议\n");
|
||||||
context.append("请根据以下建议对生成内容进行调整:\n");
|
|
||||||
context.append(suggestion).append("\n\n");
|
context.append(suggestion).append("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 财务知识
|
// 5. 财务知识(核心内容)
|
||||||
if (!knowledgeSources.get("financial").isEmpty()) {
|
if (!knowledgeSources.get("financial").isEmpty()) {
|
||||||
context.append("## 财务知识\n");
|
context.append("## 财务知识库内容\n");
|
||||||
context.append("这是财务相关的报表和文件信息,请仔细分析并提取所有支出数据:\n");
|
context.append("以下是财务相关的报表和文件信息,请仔细分析并提取所有支出数据:\n\n");
|
||||||
knowledgeSources.get("financial").forEach(knowledge ->
|
knowledgeSources.get("financial").forEach(knowledge ->
|
||||||
context.append(knowledge).append("\n"));
|
context.append(knowledge).append("\n"));
|
||||||
context.append("\n");
|
context.append("\n");
|
||||||
@@ -365,7 +242,7 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
|
|
||||||
// 6. 法律法规知识
|
// 6. 法律法规知识
|
||||||
if (!knowledgeSources.get("regulation").isEmpty()) {
|
if (!knowledgeSources.get("regulation").isEmpty()) {
|
||||||
context.append("## 法律法规知识\n");
|
context.append("## 法律法规参考\n");
|
||||||
knowledgeSources.get("regulation").forEach(knowledge ->
|
knowledgeSources.get("regulation").forEach(knowledge ->
|
||||||
context.append(knowledge).append("\n"));
|
context.append(knowledge).append("\n"));
|
||||||
context.append("\n");
|
context.append("\n");
|
||||||
@@ -373,7 +250,7 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
|
|
||||||
// 7. 审计案例知识
|
// 7. 审计案例知识
|
||||||
if (!knowledgeSources.get("auditCase").isEmpty()) {
|
if (!knowledgeSources.get("auditCase").isEmpty()) {
|
||||||
context.append("## 审计案例知识\n");
|
context.append("## 审计案例参考\n");
|
||||||
knowledgeSources.get("auditCase").forEach(knowledge ->
|
knowledgeSources.get("auditCase").forEach(knowledge ->
|
||||||
context.append(knowledge).append("\n"));
|
context.append(knowledge).append("\n"));
|
||||||
}
|
}
|
||||||
@@ -403,10 +280,10 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService
|
|||||||
|
|
||||||
private int getLimitBySourceType(String sourceType) {
|
private int getLimitBySourceType(String sourceType) {
|
||||||
switch (sourceType) {
|
switch (sourceType) {
|
||||||
case "financial": return 150;
|
case "financial": return 100; // 减少数量,提高质量
|
||||||
case "regulation": return 80;
|
case "regulation": return 50;
|
||||||
case "auditCase": return 40;
|
case "auditCase": return 30;
|
||||||
default: return 100;
|
default: return 50;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user