From fd4641cc4894622809fd20ac4c5fd76e41c2291e Mon Sep 17 00:00:00 2001 From: xueqingkun Date: Fri, 6 Jun 2025 10:33:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96text-to-cypher=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pdfqaserver/cache/PromptCache.java | 26 +++++++++---------- .../impl/TripleToCypherExecutorImpl.java | 20 ++++---------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java b/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java index 39bb91b..559e59a 100644 --- a/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java +++ b/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java @@ -793,38 +793,38 @@ public class PromptCache { private static final String TEXT_TO_CYPHER_2_PROMPT = """ 您是一个生成Cypher查询语句的助手。生成Cypher脚本时,唯一参考的是`neo4j_schema`变量。 - + 用户问题: {question} - 模式以JSON格式定义如下: + neo4j_schema以JSON格式定义如下: {schema} 请严格按照以下步骤处理每个用户查询: - + 1. 从用户查询中提取实体: - 解析问题中的领域概念,并通过同义词或上下文线索将其映射到模式元素 - 识别候选节点类型 - 识别候选关系类型 - 识别相关属性 - 识别约束条件(比较操作、标志位、时间过滤器、共享实体引用等) - + 2. 验证模式匹配性: - 确保每个节点标签、关系类型和属性在模式中完全存在(区分大小写和字符) - 如果缺少任何必需元素,请严格返回: '\\I could not generate a Cypher script; the required information is not part of the Neo4j schema.\\\\n\\n' - + 3. 构建MATCH模式: - - 仅使用经过模式验证的节点标签和关系类型 + - 仅使用经过模式验证的节点标签和关系类型,同时对节点、关系**添加变量名** + - **始终为关系分配显式变量**(例如`-[r:REL_TYPE]->`) - 当查询暗示两个模式指向同一节点时,重复使用同一变量 - 在映射模式中表达简单等值谓词,其他过滤条件移至WHERE子句 - + 4. RETURN子句策略: - - 总是返回模式中的节点和关系,使用模式变量(例如`RETURN nodes, relationships`或`RETURN path`) - - 若用户请求特定属性,包含这些属性但同时保留关系数据在RETURN子句中 - - 适当情况下,考虑通过`RETURN path`返回完整路径以保留图结构 - + - 返回模式中所有的的**节点变量**和**关系变量** + 5. 生成最终Cypher脚本: - - 仅返回最终Cypher查询语句——不包含任何评论或额外文本 + - 仅返回最终Cypher查询语句——不包含任何说明或者```cypher ```包装符 - 仅当用户显式要求且模式支持时使用OPTIONAL MATCH - - 确保RETURN子句包含关系数据,可通过显式列出关系变量或使用路径变量实现/no_think + - **确保**MATCH 子句包含**关系变量** + - 不要做出任何解释,不要对cypher进行任何包装,直接输出生成的cypher语句/no_think """; } diff --git a/src/main/java/com/supervision/pdfqaserver/service/impl/TripleToCypherExecutorImpl.java b/src/main/java/com/supervision/pdfqaserver/service/impl/TripleToCypherExecutorImpl.java index faec4e8..e8d349b 100644 --- a/src/main/java/com/supervision/pdfqaserver/service/impl/TripleToCypherExecutorImpl.java +++ b/src/main/java/com/supervision/pdfqaserver/service/impl/TripleToCypherExecutorImpl.java @@ -56,6 +56,7 @@ public class TripleToCypherExecutorImpl implements TripleToCypherExecutor { log.info("没有找到匹配的意图,query: {}", query); return null; } + log.info("找到匹配的意图,query: {}, relations: {}", query, relations.stream().map(Intention::getDigest).collect(Collectors.joining(","))); List domainMetadataDTOS = domainMetadataService.listByIntentionIds(relations.stream().map(Intention::getId).toList()); CypherSchemaDTO schemaDTO = this.queryRelationSchema(domainMetadataDTOS); if (CollUtil.isEmpty(schemaDTO.getRelations()) && CollUtil.isEmpty(schemaDTO.getNodes())) { @@ -64,6 +65,7 @@ public class TripleToCypherExecutorImpl implements TripleToCypherExecutor { } String prompt = promptMap.get(TEXT_TO_CYPHER_2); String format = StrUtil.format(prompt, Map.of("question", query, "schema", schemaDTO.format())); + log.info("生成Cypher脚本,query: {}, format: {}", query, format); String call = aiCallService.call(format); if (StrUtil.contains(call,"I could not generate a Cypher script; the required information is not part of the Neo4j schema.")){ log.info("大模型没能生成cypher,query: {}", query); @@ -209,19 +211,7 @@ public class TripleToCypherExecutorImpl implements TripleToCypherExecutor { if (null == rel){ continue; } - List relSourceType = cypherSchemaDTO.getRelations(sourceType); - List relTargetType = cypherSchemaDTO.getRelations(targetType); - - relSourceType.add(rel); - relSourceType.addAll(relTargetType); - for (RelationExtractionDTO relationExtractionDTO : relSourceType) { - boolean none = merged.stream().noneMatch(i -> StrUtil.equals(i.getRelation(), relationExtractionDTO.getRelation()) && - StrUtil.equals(i.getSourceType(), relationExtractionDTO.getSourceType()) && - StrUtil.equals(i.getTargetType(), relationExtractionDTO.getTargetType())); - if (none){ - merged.add(relationExtractionDTO); - } - } + merged.add(rel); } List entityExtractionDTOS = new ArrayList<>(); for (RelationExtractionDTO relationExtractionDTO : merged) { @@ -248,7 +238,7 @@ public class TripleToCypherExecutorImpl implements TripleToCypherExecutor { String prompt = promptMap.get(CLASSIFY_QUERY_INTENT); List result = new ArrayList<>(); log.info("开始分类意图,query: {}, intentions size: {}", query, intentions.size()); - List> intentionSplit = CollUtil.split(intentions, 200); + List> intentionSplit = CollUtil.split(intentions, 300); for (List intentionList : intentionSplit) { log.info("分类意图,query: {}, intentions size: {}", query, intentionList.size()); List intents = intentionList.stream().map(Intention::getDigest).toList(); @@ -256,7 +246,7 @@ public class TripleToCypherExecutorImpl implements TripleToCypherExecutor { "intents", JSONUtil.toJsonStr(intents)); String format = StrUtil.format(prompt, params); String call = aiCallService.call(format); - + log.info("classifyIntents:分类意图结果,query: {}, call: {}", query, call); if (StrUtil.isEmpty(call)) { return new ArrayList<>(); }