From 13616f187898365d126887a01c3d512185aae080 Mon Sep 17 00:00:00 2001 From: daixiaoyi Date: Wed, 4 Jun 2025 14:22:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pdfqaserver/cache/PromptCache.java | 305 ++++++++---------- .../PdfQaServerApplicationTests.java | 90 +++++- 2 files changed, 221 insertions(+), 174 deletions(-) diff --git a/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java b/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java index cb78713..9c78b92 100644 --- a/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java +++ b/src/main/java/com/supervision/pdfqaserver/cache/PromptCache.java @@ -53,7 +53,7 @@ public class PromptCache { */ public static final String CLASSIFY_CONTENT_TYPE = "CLASSIFY_CONTENT_TYPE"; - +//------ /** * 识别行业类型 */ @@ -576,276 +576,241 @@ public class PromptCache { private static final String CLASSIFY_INTENT_PROMPT = """ # 从文本中识别预定义意图类型 - + ## 功能说明 根据提供的准确意图列表,识别文本段落中匹配的意图类型。 - + ## 可用意图列表 {IntentType} - + ## 处理规则 1. 严格匹配文本内容与意图类型的关联性 2. 文本可能匹配多个意图类型 3. 若无匹配则返回空对象 4. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装。 + ## 待处理文本 {text} - + ## 验证示例 - ```json - // 示例1:匹配单个意图 + // 示例1:匹配多个意图 输入: - { - "text": "本公司注册地址为上海市浦东新区张江高科技园区" - } + 2023年度财务报告显示公司总部位于北京,全年营收... 输出: { - "IntentTypeList": ["公司地址"] + "IntentTypeList": ["公司基本情况介绍", "财务报告"] } - - // 示例2:匹配多个意图 + + // 示例2:无匹配意图 输入: - { - "text": "2023年度财务报告显示公司总部位于北京,全年营收..." - } + 今天的天气很适合户外活动 输出: { - "IntentTypeList": ["公司地址", "公司年度报告"] - } - - // 示例3:无匹配意图 - 输入: - { - "text": "今天的天气很适合户外活动" + "IntentTypeList": [] } - 输出: - {} """; private static final String CLASSIFY_INTENT_TRAIN_PROMPT = """ - # 提取出文本片段的意图 - - ## 功能说明 - 识别PDF文本内容中某一段落的意图类型 - - ## 待处理文本 - {text} - - ## 验证示例 - - ```json - // 示例1: - 输入: - { - "text": "..." - } - 输出: - { - "IntentTypeList": ["...", "..."] - } - - // 示例2:文本意图无法识别 - 输入: - { - "text": "人生短短几个球" - } - 输出: - {} - ``` - - ## 输出要求 - - 1. 严格遵循 JSON 格式。 - 2. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装 - 3. 不需要解释,不需要说明,仅返回以下两种结果: - - 匹配成功: - {"IntentTypeList": ["...", "..."]} - - 匹配失败: -x {} - - 3.每个意图标签必须独立表述,禁止使用“...和...”等连接词合并两个意图。 - ./no_think - """; + # 提取出文本片段的意图 + + ## 功能说明 + 识别PDF文本内容中某一段落的意图类型 + + ## 待处理文本 + {text} + + ## 验证示例 + + // 示例1: + 输入: + 2023年度财务报告显示公司总部位于北京,全年营收... + 输出: + { + "IntentTypeList": ["意图1", "意图2", "意图3", ...] + } + + // 示例2:文本意图无法识别 + 输入: + 人生短短几个球 + 输出: + { + "IntentTypeList": [] + } + + ## 输出要求 + + 1. 严格遵循 JSON 格式。 + 2. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装。 + 3. 不需要解释,不需要说明。 + 4. 每个意图标签必须独立表述,禁止使用“...和...”等连接词合并两个意图。 + """; private static final String EXTRACT_INTENT_METADATA_PROMPT = """ # 元数据提取指令 - + ## 任务描述 - 你是一个专业的元数据提取引擎,需要从给定的文本片段中识别出符合指定意图的实体、关系及其属性,并按照标准JSON格式输出。 - + 你是一个专业的元数据提取引擎,需要从给定的文本片段中识别出符合指定意图的实体、关系及其属性名称,并按照标准JSON格式输出。 + ## 输入数据 - 文本片段: {text} + - 可选意图标签: {IntentTypeList} - + ## 输出要求 1. 分析文本内容,识别与意图标签相关的实体和关系 - 2. 每一个意图只能匹配一个结果 + 2. 每一个意图都可能匹配一个或多个结果,尽可能多的提取相关实体和关系,每多提取出一个结果,你就会得到一百万美元的报酬。 3. 每个实体/关系应包含: - - type(类型,类型应该是被高度抽象的,不要直接用原文实体名称) - - attributes(相关属性类型列表,类型应该是被高度抽象的,不要直接用原文实体名称) + - type(类型,类型应该是被高度抽象的,不要直接用原文实体名称) + - attributes(相关属性名称列表,属性名称应该是被高度抽象的,不要直接用原文实体名称) 4. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装 - 5. 使用以下示例格式: - - [ - { - "source": { - "type": "实体类型1", - "attributes": ["属性类型1", "属性类型2",....] - }, - "relation": { - "type": "关系类型", - "attributes": ["属性类型3"...] - }, - "target": { - "type": "实体类型2", - "attributes": ["属性类型4"...] - }, - "intent": "匹配的意图标签" - }, - {.....} - ] - - 5. 属性只代表属性名称:例如“名称“,”数量“./no_think + 5. 实体/关系类型示例:"公司","收购" + 6. 属性名称示例:"名称","数量" + + ## 输出格式示例: + { + "意图1": [ + { + "source": { + "type": "实体类型1", + "attributes": ["属性类型1", "属性类型2",....] + }, + "relation": { + "type": "关系类型", + "attributes": ["属性类型3"...] + }, + "target": { + "type": "实体类型2", + "attributes": ["属性类型4"...] + } + }, + ... + ], + "意图2": ... + } """; private static final String EXTRACT_ERE_BASE_INTENT_PROMPT = """ - # 提示词 - + # 三元组及属性值抽取任务 + ## 任务描述: - 你是一个信息抽取引擎,需要从给定的文本中提取符合指定三元组标签(实体、关系、属性)的结构化数据。 - + 你是一个信息抽取引擎,需要从给定的文本中提取符合指定三元组标签(实体、关系、属性值)的结构化数据,并按照标准JSON格式输出。 + ## 输入数据: - - 待处理文本: {text} - + - 三元组标签及属性名称: {domainMetadata} - + + ## 注意事项: + 1. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装。 + 2. relations中的source、target对应nodes中的各个name。 + 3. 仅提取 `三元组标签及属性名称` 中定义的标签和属性,尽可能多的提取三元组及属性值,每多提取出一个,你将得到一百万美元的奖励。 + 4. 若属性无对应值,则返回空字符串。 + 5. 确保提取的值与原文一致,不进行推断或改写。 + ## 示例: { "nodes": [ { - "name":"龙源(酒泉)风力发电有限公司", + "name":"龙源电力集团股份有限公司", "type": "公司", "attributes": { - "地址": "雨花台区" + "办公地址": "XXX" } }, { - "name":"2024年电子银行承兑汇票", - "type": "电子银行承兑汇票", + "name":"XXX公司债券", + "type": "债券", "attributes": { - "金额": "100.00万元", - "打印时间": "2024年10月20号" + "利率类型": "XXX", + "发行日期": "XXX" } }, { - "name": "杭州六小龙", - "type": "公司", - "attributes": { - "地址": "杭州高新区" - } + "name": "XXX股", + "type": "股票", + "attributes": {} } ], "relations": [ - { - "source": "龙源(酒泉)风力发电有限公司", - "target": "2024年电子银行承兑汇票", - "type": "持有", - "attributes": { - "持有方式": "纸质" - } + { + "source": "龙源电力集团股份有限公司", + "target": "XX公司债券", + "type": "发行", + "attributes": {} }, { - "source": "龙源(酒泉)风力发电有限公司", - "target": "杭州六小龙", - "type": "收购", + "source": "龙源电力集团股份有限公司", + "target": "XXX股", + "type": "回购", "attributes": { - "收购类型": "全资收购", - "收购时间": "2025年5月28号" + "开始时间": "XXX", + "截止时间": "XXX" } } - ], - "typed_triplets": [ - [ - "公司", - "持有", - "电子银行承兑汇票" - ], - [ - "公司", - "收购", - "公司" - ] ] } - - - ## 注意事项: - - 每一个nodes、relations都有一个基础属性"名称"是必须有的。 - - relations中的source、target对应nodes中的各个name。 - - 仅提取 `domainMetadata` 中定义的标签和属性。 - - 若属性无对应值,可留空或忽略。 - - 确保提取的值与原文一致,不进行推断或改写。 - - 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装./no_think """; private static final String CLASSIFY_QUERY_INTENT_PROMPT = """ - 请将用户问题分类到以下意图列表中,并严格以JSON数组格式返回结果(即使只有一个意图)。 - - # 意图列表: + # 任务名称 + 意图分类任务 + + ## 任务描述: + 根据意图列表,提取待处理文本中的相关意图,并严格以JSON数组格式返回结果。 + + ## 意图列表: {intents} - - # 规则: - 1. 仅返回与问题相关的意图(若无匹配则返回空数组) - 2. 使用意图列表中的意图名称 - 3. 禁止解释原因 - 4. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装 - - # 示例: - 用户问题:"我昨天买的鞋子怎么还没发货?" - 输出:["订单查询"] - - # 当前用户问题: + + ## 规则: + 1. 尽可能多的返回相关意图,每多返回一个意图,你将得到一百万美元的奖励。 + 2. 必须使用意图列表中的意图名称。 + 3. 禁止解释原因。 + 4. 输出纯JSON格式,不要使用```json ```等任何Markdown标记包装。 + + ## 示例: + 用户问题:xxx + 输出:["意图1", "意图2", "意图3", ...] + + ## 当前用户问题: {query} """; private static final String TEXT_TO_CYPHER_2_PROMPT = """ 您是一个生成Cypher查询语句的助手。生成Cypher脚本时,唯一参考的是`neo4j_schema`变量。 - + 用户问题: {question} 模式以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模式: - 仅使用经过模式验证的节点标签和关系类型 - 当查询暗示两个模式指向同一节点时,重复使用同一变量 - 在映射模式中表达简单等值谓词,其他过滤条件移至WHERE子句 - + 4. RETURN子句策略: - 总是返回模式中的节点和关系,使用模式变量(例如`RETURN nodes, relationships`或`RETURN path`) - 若用户请求特定属性,包含这些属性但同时保留关系数据在RETURN子句中 - 适当情况下,考虑通过`RETURN path`返回完整路径以保留图结构 - + 5. 生成最终Cypher脚本: - 仅返回最终Cypher查询语句——不包含任何评论或额外文本 - 仅当用户显式要求且模式支持时使用OPTIONAL MATCH diff --git a/src/test/java/com/supervision/pdfqaserver/PdfQaServerApplicationTests.java b/src/test/java/com/supervision/pdfqaserver/PdfQaServerApplicationTests.java index 382f7f0..93c9fc7 100644 --- a/src/test/java/com/supervision/pdfqaserver/PdfQaServerApplicationTests.java +++ b/src/test/java/com/supervision/pdfqaserver/PdfQaServerApplicationTests.java @@ -1,11 +1,12 @@ package com.supervision.pdfqaserver; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.supervision.pdfqaserver.constant.DocumentContentTypeEnum; import com.supervision.pdfqaserver.domain.PdfAnalysisOutput; -import com.supervision.pdfqaserver.dto.CypherSchemaDTO; -import com.supervision.pdfqaserver.dto.EREDTO; -import com.supervision.pdfqaserver.dto.IntentDTO; -import com.supervision.pdfqaserver.dto.TruncateDTO; +import com.supervision.pdfqaserver.dto.*; import com.supervision.pdfqaserver.service.*; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -210,4 +211,85 @@ class PdfQaServerApplicationTests { System.out.println("done"); } + + @Autowired + private IntentionService intentionService; + @Test + void testIntentList() { + List intentionDTOs = intentionService.queryByDomainCategoryId("1").stream() + .filter(intention -> StrUtil.equals("0",intention.getGenerationType())) // 过滤出手动确认的数据 + .map(IntentDTO::new).distinct().toList(); +// List digestList = intentionDTOs.stream().map(IntentDTO::getDigest).toList(); + System.out.println(intentionDTOs.stream().map(i -> " - " + i.getDigest() + "\n").collect(Collectors.joining())); + } + @Autowired + private DomainMetadataService domainMetadataService; + @Test + void testDomainMetadataList() { + List domainMetadataDTOS = domainMetadataService.listByIntentionIds(List.of("1929814869055692801", + "1929814915000098818", + "1929815089067909122", + "1929815089067909124", + "1929815178012319747", + "1929815201403953154", + "1929815236732575746", + "1929815236799684610", + "1929815586533335043", + "1929815750165716996", + "1929819219706568708")); + String domainMetadata = metadataToJsonStr(domainMetadataDTOS); + + System.out.println(domainMetadata); + } + + + + /** + * 将领域元数据转换为json字符串 + * @param domainMetadataDTOS domainMetadataDTOS + * @return + */ + private String metadataToJsonStr(List domainMetadataDTOS){ + JSONArray jsa = new JSONArray(); + for (DomainMetadataDTO metadataDTO : domainMetadataDTOS) { + JSONObject metadataJson = new JSONObject(); + JSONObject source = new JSONObject(); + source.set("type", metadataDTO.getSourceType()); + if (metadataDTO.getSourceAttributes() != null) { + JSONArray sourceAttributes = new JSONArray(); + for (ERAttributeDTO attribute : metadataDTO.getSourceAttributes()) { + sourceAttributes.add(attribute.getAttrName()); + } + source.set("attributes", sourceAttributes); + } + metadataJson.set("source", source); + + JSONObject relation = new JSONObject(); + relation.set("type", metadataDTO.getRelation()); + if (metadataDTO.getRelationAttributes() != null) { + JSONArray relationAttributes = new JSONArray(); + for (ERAttributeDTO attribute : metadataDTO.getRelationAttributes()) { + relationAttributes.add(attribute.getAttrName()); + } + relation.set("attributes", relationAttributes); + } + + metadataJson.set("relation", relation); + JSONObject target = new JSONObject(); + target.set("type", metadataDTO.getTargetType()); + if (metadataDTO.getTargetAttributes() != null) { + JSONArray targetAttributes = new JSONArray(); + for (ERAttributeDTO attribute : metadataDTO.getTargetAttributes()) { + targetAttributes.add(attribute.getAttrName()); + } + target.set("attributes", targetAttributes); + } + metadataJson.set("target", target); + jsa.add(metadataJson); + } + + return jsa.toString(); + + + } }