From bb7515471b9d1f80b357bbc86f9d3e9e96eaccb9 Mon Sep 17 00:00:00 2001
From: liu <liujiatong112@163.com>
Date: Wed, 24 Jul 2024 15:16:36 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=AC=94=E5=BD=95=E6=8B=86?=
 =?UTF-8?q?=E5=88=86=E5=88=86=E7=B1=BB=E7=9A=84=E7=9B=B8=E5=85=B3=E4=BB=A3?=
 =?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../config/TransactionManagerConfig.java      |   8 ++
 .../supervision/police/domain/NotePrompt.java |   2 +
 .../impl/ExtractTripleInfoServiceImpl.java    |   6 +-
 .../impl/ModelRecordTypeServiceImpl.java      | 125 ++++++++++++++----
 .../thread/TripleExtractThread.java           |  97 +++++++++-----
 src/main/resources/application-dev.yml        |   2 +
 6 files changed, 180 insertions(+), 60 deletions(-)

diff --git a/src/main/java/com/supervision/config/TransactionManagerConfig.java b/src/main/java/com/supervision/config/TransactionManagerConfig.java
index 0ad1a6f..8cdfc54 100644
--- a/src/main/java/com/supervision/config/TransactionManagerConfig.java
+++ b/src/main/java/com/supervision/config/TransactionManagerConfig.java
@@ -26,4 +26,12 @@ public class TransactionManagerConfig {
         //可以设置其他事务管理器属性
         return transactionManager;
     }
+
+    @Bean("testTransactionManager")
+    public DataSourceTransactionManager testTransactionManager(DataSource dataSource) {
+        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
+        transactionManager.setDataSource(dataSource);
+        //可以设置其他事务管理器属性
+        return transactionManager;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/supervision/police/domain/NotePrompt.java b/src/main/java/com/supervision/police/domain/NotePrompt.java
index 922a54c..faa92b3 100644
--- a/src/main/java/com/supervision/police/domain/NotePrompt.java
+++ b/src/main/java/com/supervision/police/domain/NotePrompt.java
@@ -32,6 +32,8 @@ public class NotePrompt implements Serializable {
 
     private String startEntityType;
 
+    private String relType;
+
     private String endEntityType;
 
     /**
diff --git a/src/main/java/com/supervision/police/service/impl/ExtractTripleInfoServiceImpl.java b/src/main/java/com/supervision/police/service/impl/ExtractTripleInfoServiceImpl.java
index 088a7eb..730b331 100644
--- a/src/main/java/com/supervision/police/service/impl/ExtractTripleInfoServiceImpl.java
+++ b/src/main/java/com/supervision/police/service/impl/ExtractTripleInfoServiceImpl.java
@@ -21,6 +21,7 @@ import org.springframework.ai.ollama.OllamaChatClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StopWatch;
 
 import java.time.LocalDateTime;
@@ -52,6 +53,7 @@ public class ExtractTripleInfoServiceImpl implements ExtractTripleInfoService {
 
 
     @Async
+    @Transactional(transactionManager = "testTransactionManager",rollbackFor = Exception.class)
     public void extractTripleInfo(String caseId, String name, String recordId) {
         // 首先获取所有切分后的笔录
         List<NoteRecordSplit> recordSplitList = noteRecordSplitService.lambdaQuery().eq(StrUtil.isNotBlank(recordId), NoteRecordSplit::getNoteRecordsId, recordId)
@@ -150,7 +152,9 @@ public class ExtractTripleInfoServiceImpl implements ExtractTripleInfoService {
             tripleInfoService.lambdaUpdate().eq(TripleInfo::getRecordId, recordId).remove();
             // TODO 这里,如果已经生成了图谱,怎么办?
             // 首先要把这个笔录已经提取过的三元组记录删除掉,删除掉之后才可以重新提取
-            tripleInfoService.saveBatch(tripleInfos);
+            for (TripleInfo tripleInfo : tripleInfos) {
+                tripleInfoService.save(tripleInfo);
+            }
         }
         if (CollUtil.isNotEmpty(futures)) {
             // 将任务标记为成功
diff --git a/src/main/java/com/supervision/police/service/impl/ModelRecordTypeServiceImpl.java b/src/main/java/com/supervision/police/service/impl/ModelRecordTypeServiceImpl.java
index d9e063e..e664935 100644
--- a/src/main/java/com/supervision/police/service/impl/ModelRecordTypeServiceImpl.java
+++ b/src/main/java/com/supervision/police/service/impl/ModelRecordTypeServiceImpl.java
@@ -1,5 +1,6 @@
 package com.supervision.police.service.impl;
 
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.druid.util.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -116,6 +117,9 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
 
     @Override
     public List<TripleInfo> getThreeInfo(String caseId, String name, String recordId) {
+        if (StrUtil.isBlank(recordId)){
+            throw new RuntimeException("笔录ID不能为空");
+        }
         boolean taskStatus = taskExtractStatusCheck(caseId, recordId);
         // 如果校验结果为false,则说明需要进行提取三元组操作
         if (!taskStatus) {
@@ -130,7 +134,8 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
      */
     private boolean taskExtractStatusCheck(String caseId, String recordId) {
         // 首先查询是否存在任务,如果不存在,就新建
-        Optional<CaseTaskRecord> caseTaskRecordOpt = caseTaskRecordService.lambdaQuery().eq(CaseTaskRecord::getType, 2).eq(CaseTaskRecord::getCaseId, caseId).eq(CaseTaskRecord::getRecordId, recordId).oneOpt();
+        Optional<CaseTaskRecord> caseTaskRecordOpt = caseTaskRecordService.lambdaQuery()
+                .eq(CaseTaskRecord::getType, 2).eq(CaseTaskRecord::getCaseId, caseId).eq(CaseTaskRecord::getRecordId, recordId).oneOpt();
         if (caseTaskRecordOpt.isEmpty()) {
             CaseTaskRecord newCaseTaskRecord = new CaseTaskRecord();
             newCaseTaskRecord.setType(2);
@@ -167,19 +172,100 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
 
     @Override
     public void testExtractThreeInfo() {
+//        -------------------------
+//        DEMO_0:山东团队的版本,每次提取多个三元组,经过测试,提取质量较差,基本无法正常提取.需要改成每次提取一个,进行TEST_DEMO_1尝试
+//        请分析以下内容中所有规定的三元组信息并补充完整,
+//        要求:1.返回式:
+//        {result:
+//                   [
+//            {startNodeType:'LawActor',entity:'',endNodeType:'FictionalOrgan',property:'',value:'冒充' },
+//            {startNodeType:'LawActor',entity:'',endNodeType:'Seal',property:'',value:'伪造'},
+//            {startNodeType:'LawActor',entity:'',endNodeType:'BusinessLicense',property:'',value:'伪造'}
+//                   ]
+//        }。
+//        2.必须考虑上下文语境分析。
+//        3.对话中不包含此类型三元组则返回{ "result": [] }。
+//        例子1:办案警官问:你为了骗取更多的钱都做了哪些准备?裴金禄回答:我刚开始我就是自己想了一些关于骗钱的点子,后面为了更不容易让别人识破我为了更佳逼真,我就从网上随便搜了一家租赁公司,我就搜到了兰州胜利机械租赁有限公司,被讯问人:裴金禄我又想到了我管理的中铁北京局和中铁电气化局施工公司。我先是通过百度搜索了“办证”之后就在网页上面弹出了一个页面上面有一个QQ号,我就加上了。加上之后我就将我的要求给他说了,要求他给我刻两个假的公章,一个是兰州胜利机械租赁有限公司合同专用章,另一个是中铁北京局集团有限公司合同专用章。我还要求他给我伪造了一张兰州胜利机械租赁有限公司的营业执照。
+//        回答:{"result":[{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"FictionalOrgan","property":"兰州胜利机械租赁有限公司","value":"冒充"},{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"Seal","property":"兰州胜利机械租赁有限公司合同专用章","value":"伪造"},{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"Seal","property":"中铁北京局集团有限公司合同专用章","value":"伪造"},{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"BusinessLicense","property":"兰州胜利机械租赁有限公司营业执照","value":"伪造"}]}。
+//        例子2:办案警官问:你为什么要在中卫市沙坡头区签订这些合同?裴金禄回答:因为我在这边上班,我在中卫市沙坡头区签订合同更能有说服力,这样才能更好地骗到钱。回答:{ "result": [] }。
+
+//        -------------------------
+//        TEST_DEMO_1:结果:效果较差,容易出现混淆,会把例子中的实体给返回出来.如果提取不到,会把定义的关系返回出来,所以不行.PASS
+//        请从
+//        ---
+//        办案警官问:你是如何想到这个方法骗钱的? 裴金禄回答:因为我是在中卫市沙坡头区中兰铁路上做监理人员,我这样说的话别人会更容易相信。
+//        ---
+//        这段话中按(主体类型:行为人姓名;关系:伪造;客体类型:合同名称)提取特定的三元组信息。
+//        如果未提取到或关系不匹配或客体类型不匹配,则返回空的json即可。
+//        如果可以提取到三元组关系,则返回格式为{"主体":"主体名称","关系":"关系名称","客体":"客体名称"}。
+//        例如‘办案警官问:描述一下事情的经过。行为人小明答:我做了一份假的租车合同,然后骗小刚签了这个合同’,该示例存在给定的三元组关系.则结果为:{"主体":"小明","关系":"伪造","客体":"租车合同"}。
+//        例如‘办案警官问:办案警官问:讲一下那个软件的名称?小明回答:现在叫畅聊。‘该示例不存在给定的三元组关系,则结果为:{}
+//        请保证提取准确且完整,主体和客体要具体明确,不能是宽泛的概念。提取的客体要必须属于客体类型!
+//        -------------------------
+//        TEST_DEMO_2:结果:有一些结果可以,但总体正确率较低,问题:不能有效的对给定的三元组进行提取,会出现给定三元组关系之外的三元组.会出现文章中不存在的三元组或错误的三元组
+//        三元组提取任务:从给定对话中根据给定实体类型和关系提取对应的三元组。
+//        给定的头实体类型为"{headEntityType}";给定的尾实体类型为"{relation}",给定的关系为"{tailEntityType}"。
+//        请仔细分析以下的文本内容,精准找出符合给定关系且头尾实体类型相符的三元组,并进行提取。如果没有识别给定的三元组关系,请返回json:{"result":[]}。
+//        ---
+//        为您提供一个示例供学习:
+//        例如给定关系:给定三元组类型为:头实体类型:"行为人"关系:"伪造",尾实体类型:"合同"
+//        例如QA:办案警官问:描述一下事情的经过。 行为人小明答:我做了一份假的购房合同。
+//        本示例中应提取给定关系为"伪造"的三元组,则最终应提取的三元组为:{"result":[{"headEntity": {"type": "行为人","name":"小明"},"relation": "伪造","tailEntity": {"type": "合同","name": "假的购房合同"}}]}。
+//        ---
+//        需要分析提取的QA对如下:
+//        {question}
+//        {answer}
+//        ---
+//        在提取三元组时,请务必严格遵循以下要求:
+//        1. 确保提取的三元组包括**给定的头实体类型**和**尾实体类型**。
+//        2. 提取的三元组必须明确体现给定的**关系**。
+//        3. 头实体和尾实体的名称必须在对话文本中找到。
+//        4. 对于每个提取出的三元组,确保关系({relation})与实体类型完全匹配。
+//        5. 如果文本中没有符合要求的三元组,请确保返回空结果,即 {"result": []}。
+//        返回格式为必须为以下的json格式:
+//        {"result":[{"headEntity": {"type": "给定头类型","name":"提取到的头实体内容1"},"relation": "给定关系","tailEntity": {"type": "给定尾类型","name": "提取到的尾实体内容1"}}]}
+//        -------------------------
+//        TEST_DEMO_3:尝试给定所有关系和头实体,只提取尾实体.结论:效果差,会把不相关的不符合的都提取出来,PASS.回退到DEMO2继续调整吧!
+//        给定指标的存在性判断任务:给定一个指标,对给定QA进行判断是否符合,符合则为true,并把符合需实体类型的实体返回,不符合则为false
+//        指标为:裴金禄是否{relation}{tailEntityType}(需提取实体类型为:{tailEntityType})
+//        ---
+//        为你提供一个实例进行学习:
+//        示例QA:办案警官问:描述一下事情的经过。 行为人小明答:我做了一份假的购房合同。
+//        示例指标:小明是否伪造合同(需提取实体为:合同)
+//        示例结果:{"result":ture,"entity":["购房合同"]}
+//        ---
+//        需要分析的QA对如下:
+//        {question}
+//        {answer}
+//        ---
+//        请从需要分析的QA中进行判断提取!!!
+//        在判断时,请务必仔细理解需要分析的QA文本的含义,确保提取的信息准确、合理。同时,尽量遵循常见的语义和逻辑规则,避免过度解读或不合理的关系推断。
+//        返回格式为必须json格式,格式定义如下:
+//        {"result":ture/false,"entity":["对应实体类型的实体"]}
+
         String prompt = """
-                请从
+                三元组提取任务:从给定对话中根据给定实体类型和关系提取对应的三元组。
+                给定的头实体类型为"{headEntityType}";给定的尾实体类型为"{relation}",给定的关系为"{tailEntityType}"。
+                请仔细分析以下的文本内容,精准找出符合给定关系且头尾实体类型相符的三元组,并进行提取。如果没有识别给定的三元组关系,请返回json:{"result":[]}。
                 ---
-                办案警官问:你是如何想到这个方法骗钱的? 裴金禄回答:因为我是在中卫市沙坡头区中兰铁路上做监理人员,我这样说的话别人会更容易相信。
+                为您提供一个示例供学习:
+                例如给定关系:给定三元组类型为:头实体类型:"行为人"关系:"伪造",尾实体类型:"合同"
+                例如QA:办案警官问:描述一下事情的经过。 行为人小明答:我做了一份假的购房合同。
+                本示例中应提取给定关系为"伪造"的三元组,则最终应提取的三元组为:{"result":[{"headEntity": {"type": "行为人","name":"小明"},"relation": "伪造","tailEntity": {"type": "合同","name": "假的购房合同"}}]}。
                 ---
-                这段话中按(主体类型:行为人姓名;关系:伪造;客体类型:合同名称)提取特定的三元组信息。
-                如果未提取到或关系不匹配或客体类型不匹配,则返回空的json即可。
-                如果可以提取到三元组关系,则返回格式为{"主体":"主体名称","关系":"关系名称","客体":"客体名称"}。
-                例如‘办案警官问:描述一下事情的经过。行为人小明答:我做了一份假的租车合同,然后骗小刚签了这个合同’,该示例存在给定的三元组关系.则结果为:{"主体":"小明","关系":"伪造","客体":"租车合同"}。
-                例如‘办案警官问:办案警官问:讲一下那个软件的名称?小明回答:现在叫畅聊。‘该示例不存在给定的三元组关系,则结果为:{}
-                请保证提取准确且完整,主体和客体要具体明确,不能是宽泛的概念。提取的客体要必须属于客体类型!
-
-                以只返回JSON数据
+                需要分析提取的QA对如下:
+                {question}
+                {answer}
+                ---
+                在提取三元组时,请务必严格遵循以下要求:
+                1. 确保提取的三元组包括**给定的头实体类型**和**尾实体类型**。
+                2. 提取的三元组必须明确体现给定的**关系**。
+                3. 头实体和尾实体的名称必须在对话文本中找到。
+                4. 对于每个提取出的三元组,确保提取到的实体与给定实体类型完全匹配。
+                5. 对于每个提取出的三元组,确保提取到的关系完全等于给定关系,如不等于,则提取错误。
+                5. 如果文本中没有符合要求的三元组,请确保返回空结果,即 {"result": []}。
+                返回格式为必须为以下的json格式:
+                {"result":[{"headEntity": {"type": "给定头实体类型","name":"提取到的对应头实体内容1"},"relation": "给定关系","tailEntity": {"type": "给定实体尾类型","name": "提取到的对应尾实体内容1"}}]}
                 """;
         // 抽取的客体名称一定属于给定的客体类型分类,且抽取的关系完全等于给定的关系。
         Prompt ask = new Prompt(new UserMessage(prompt));
@@ -191,23 +277,6 @@ public class ModelRecordTypeServiceImpl extends ServiceImpl<ModelRecordTypeMappe
         log.info("耗时:{}", stopWatch.getTotalTimeSeconds());
         String content = call.getResult().getOutput().getContent();
         log.info("分析的结果是:{}", content);
-
-        String oldPrompt = """
-                请分析以下内容中所有规定的三元组信息并补充完整,
-                要求:1.返回式:
-                {result:
-                   [
-                       {startNodeType:'LawActor',entity:'',endNodeType:'FictionalOrgan',property:'',value:'冒充' },
-                       {startNodeType:'LawActor',entity:'',endNodeType:'Seal',property:'',value:'伪造'},
-                       {startNodeType:'LawActor',entity:'',endNodeType:'BusinessLicense',property:'',value:'伪造'}
-                   ]
-                }。
-                2.必须考虑上下文语境分析。
-                3.对话中不包含此类型三元组则返回{ "result": [] }。
-                例子1:办案警官问:你为了骗取更多的钱都做了哪些准备?裴金禄回答:我刚开始我就是自己想了一些关于骗钱的点子,后面为了更不容易让别人识破我为了更佳逼真,我就从网上随便搜了一家租赁公司,我就搜到了兰州胜利机械租赁有限公司,被讯问人:裴金禄我又想到了我管理的中铁北京局和中铁电气化局施工公司。我先是通过百度搜索了“办证”之后就在网页上面弹出了一个页面上面有一个QQ号,我就加上了。加上之后我就将我的要求给他说了,要求他给我刻两个假的公章,一个是兰州胜利机械租赁有限公司合同专用章,另一个是中铁北京局集团有限公司合同专用章。我还要求他给我伪造了一张兰州胜利机械租赁有限公司的营业执照。
-                回答:{"result":[{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"FictionalOrgan","property":"兰州胜利机械租赁有限公司","value":"冒充"},{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"Seal","property":"兰州胜利机械租赁有限公司合同专用章","value":"伪造"},{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"Seal","property":"中铁北京局集团有限公司合同专用章","value":"伪造"},{"startNodeType":"LawActor","entity":"裴金禄","endNodeType":"BusinessLicense","property":"兰州胜利机械租赁有限公司营业执照","value":"伪造"}]}。
-                例子2:办案警官问:你为什么要在中卫市沙坡头区签订这些合同?裴金禄回答:因为我在这边上班,我在中卫市沙坡头区签订合同更能有说服力,这样才能更好地骗到钱。回答:{ "result": [] }。
-                """;
     }
 
 
diff --git a/src/main/java/com/supervision/thread/TripleExtractThread.java b/src/main/java/com/supervision/thread/TripleExtractThread.java
index 0b97a8a..bd989a0 100644
--- a/src/main/java/com/supervision/thread/TripleExtractThread.java
+++ b/src/main/java/com/supervision/thread/TripleExtractThread.java
@@ -1,18 +1,13 @@
 package com.supervision.thread;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.supervision.police.domain.NotePrompt;
 import com.supervision.police.domain.TripleInfo;
-import com.supervision.springaidemo.domain.ModelMetric;
-import com.supervision.springaidemo.domain.NoteCheckRecord;
-import com.supervision.springaidemo.dto.MetricResultDTO;
-import com.supervision.police.service.NoteCheckRecordService;
+import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
-import org.json.JSONArray;
-import org.json.JSONObject;
 import org.springframework.ai.chat.ChatResponse;
-import org.springframework.ai.chat.Generation;
 import org.springframework.ai.chat.messages.UserMessage;
 import org.springframework.ai.chat.prompt.Prompt;
 import org.springframework.ai.ollama.OllamaChatClient;
@@ -20,6 +15,7 @@ import org.springframework.util.StopWatch;
 
 import java.time.LocalDateTime;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.Callable;
 
 @Slf4j
@@ -51,6 +47,30 @@ public class TripleExtractThread implements Callable<TripleInfo> {
         this.recordId = recordId;
     }
 
+
+    /**
+     * 三元组提取任务:从给定对话中根据给定实体类型和关系提取对应关系的三元组。
+     * 给定的头实体类型为"{headEntityType}";给定的尾实体类型为"{tailEntityType}",给定的关系为"{relation}"。
+     * 请仔细分析以下的文本内容,精准找出符合给定关系且头尾实体类型相符的三元组,并进行提取。如果没有识别给定的三元组关系,请返回json:{"result":[]}。
+     * ---
+     * 为您提供一个示例供学习:
+     * 给定三元组类型为:头实体类型:"行为人"关系:"伪造",尾实体类型:"合同"
+     * 办案警官问:描述一下事情的经过。 行为人小明答:我做了一份假的购房合同。
+     * 本示例中应提取给定关系为"伪造"的三元组,则最终应提取的三元组为{"result":[{"headEntity": {"type": "行为人","name":"小明"},"relation": "伪造","tailEntity": {"type": "合同","name": "假的购房合同"}}]}。
+     * ---
+     * 需要分析提取的QA对如下:
+     * {question}
+     * {answer}
+     * ---
+     * 在提取三元组时,请务必严格遵循以下要求:
+     * 1. 精准理解需要分析的QA文本的含义,确保提取的信息准确无误、合理恰当。
+     * 2. 只提取给定的实体类型和关系,不要提取给定关系和实体之外的三元组。
+     * 3. 尽量遵循常见的语义和逻辑规则,杜绝过度解读或不合理的关系推断。
+     * 4. 例子仅供参考,不要简单地返回示例中的结果。
+     * 5. 提取之后,再检查一遍,提取的关系和实体是否与给定关系和实体类型对应
+     * 返回格式为必须为以下的json格式:
+     * {"result":[{"headEntity": {"type": "{headEntityType}","name":"提取到的头实体内容1"},"relation": "{relation}","tailEntity": {"type": "{tailEntityType}","name": "提取到的尾实体内容1"}}]}
+     */
     @Override
     public TripleInfo call() {
         try {
@@ -58,44 +78,59 @@ public class TripleExtractThread implements Callable<TripleInfo> {
             // 分析三元组
             stopWatch.start();
             HashMap<String, String> paramMap = new HashMap<>();
-            paramMap.put("qaRecord", question + answer);
+            paramMap.put("headEntityType", prompt.getStartEntityType());
+            paramMap.put("relation", prompt.getRelType());
+            paramMap.put("tailEntityType", prompt.getEndEntityType());
+            paramMap.put("question", question);
+            paramMap.put("answer", answer);
             Prompt ask = new Prompt(new UserMessage(StrUtil.format(prompt.getPrompt(), paramMap)));
-            log.info("开始分析:");
             ChatResponse call = chatClient.call(ask);
             stopWatch.stop();
-            log.info("耗时:{}", stopWatch.getTotalTimeSeconds());
             String content = call.getResult().getOutput().getContent();
-            log.info("分析的结果是:{}", content);
+            log.info("耗时:{},分析的结果是:{}", stopWatch.getTotalTimeSeconds(), content);
             // 获取从提示词中提取到的三元组信息
-            JSONObject jsonObject = new JSONObject(content);
-            // 修改,经测试,一次提取多个三元组效果较差,改成一次只提取一个三元组
-            //JSONArray threeInfo = jsonObject.getJSONArray("result");
-            //for (int i = 0; i < threeInfo.length(); i++) {
-            //JSONObject object = threeInfo.getJSONObject(i);
-            String entity = jsonObject.getString("主体");
-            String relation = jsonObject.getString("关系");
-            String value = jsonObject.getString("客体");
-            // 类型信息从notePrompt对象中获取
-            // String startNodeType = object.getString("startNodeType");
-            // String endNodeType = object.getString("endNodeType");
-            // 去空,如果存在任何的空值,则忽略
-//                if (StrUtil.hasEmpty(startNodeType, entity, endNodeType, property, value)) {
-//                    continue;
-//                }
-            if (StrUtil.hasEmpty(entity, relation, value)) {
-                log.info("提取三元组信息出现空值,忽略,主体:{},关系:{},客体:{}", entity, relation, value);
+            TripleExtractResult extractResult = JSONUtil.toBean(content, TripleExtractResult.class);
+            if (ObjectUtil.isEmpty(extractResult) || extractResult.result.isEmpty()) {
+                log.info("提取三元组信息为空,忽略");
                 return null;
             }
-            // 构建三元组信息
-            return new TripleInfo(entity, relation, value, caseId, recordId, recordSplitId, LocalDateTime.now(), prompt.getStartEntityType(), prompt.getEndEntityType());
-            //}
+            for (TripleExtractNode tripleExtractNode : extractResult.getResult()) {
+                TripleEntity headEntity = tripleExtractNode.getHeadEntity();
+                TripleEntity tailEntity = tripleExtractNode.getTailEntity();
+                String relation = tripleExtractNode.getRelation();
+                if (StrUtil.hasEmpty(headEntity.getName(), relation, tailEntity.getName())) {
+                    log.info("提取三元组信息出现空值,忽略,主体:{},关系:{},客体:{}", headEntity.getName(), relation, tailEntity.getName());
+                    return null;
+                }
+                // 构建三元组信息
+                return new TripleInfo(headEntity.getName(), tailEntity.getName(), relation, caseId, recordId, recordSplitId, LocalDateTime.now(), prompt.getStartEntityType(), prompt.getEndEntityType());
+            }
         } catch (Exception e) {
             log.error("提取三元组出现错误", e);
         }
         return null;
     }
 
+    @Data
+    public static class TripleExtractResult {
+        private List<TripleExtractNode> result;
+
+    }
+
+    @Data
+    public static class TripleExtractNode {
+        private TripleEntity headEntity;
+        private String relation;
+        private TripleEntity tailEntity;
 
 
+    }
+
+    @Data
+    public static class TripleEntity {
+        private String name;
+        private String type;
+    }
+
 
 }
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 353f40a..49a0fa1 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -4,11 +4,13 @@ spring:
   ai:
     # 文档地址 https://docs.spring.io/spring-ai/reference/1.0-SNAPSHOT/api/chat/ollama-chat.html
     ollama:
+#      base-url: http://192.168.10.70:12434
       base-url: http://192.168.10.70:11434
 #      base-url: http://124.220.94.55:8060
       chat:
         enabled: true
         options:
+          #model: qwen2:7b
           model: llama3-chinese:8b
 #          model: qwen2:72b
           # 控制模型在请求后加载到内存中的时间(稍微长一点的时间,避免重复加载浪费性能,加快处理速度)