diff --git a/backend/app/engine/engine.py b/backend/app/engine/engine.py index cea0cfe..daef56b 100644 --- a/backend/app/engine/engine.py +++ b/backend/app/engine/engine.py @@ -14,6 +14,7 @@ from app.engine.response.treeSummResponse import CustomTreeResponse from llama_index.core.settings import Settings from llama_index.core.indices.property_graph import LLMSynonymRetriever,VectorContextRetriever from llama_index.core import PropertyGraphIndex +from app.engine.retriever.graphKeyWordRetriever import GraphKeyWordRetriever ModelPlateCategory = '模型平台' @@ -122,8 +123,7 @@ def create_query_engine(index,top_k=3, use_reranker=False, filters=None, respons llm_query = os.getenv('LLM_QUERY_WAY','rag') if llm_query == 'graph': graphIndex:PropertyGraphIndex = index - synonym_retriver = LLMSynonymRetriever(graphIndex.property_graph_store, - llm=Settings.llm, + keyWord_retriver = GraphKeyWordRetriever(graphIndex.property_graph_store, include_text=False ) if graphIndex.property_graph_store.supports_vector_queries: @@ -137,7 +137,7 @@ def create_query_engine(index,top_k=3, use_reranker=False, filters=None, respons include_text=False ) - retriever = graphIndex.as_retriever(sub_retrievers=[synonym_retriver,vector_retriver]) + retriever = graphIndex.as_retriever(sub_retrievers=[keyWord_retriver,vector_retriver]) else: retriever = get_Retriever(index, diff --git a/backend/app/engine/graph/extractor.py b/backend/app/engine/graph/extractor.py index 2fbe41c..f723755 100644 --- a/backend/app/engine/graph/extractor.py +++ b/backend/app/engine/graph/extractor.py @@ -8,6 +8,73 @@ from app.engine.loaders.markdownReader import ChunkMarkdownReader from app.engine.graph.graphTypes import * import uuid +IdField = '_id' +nodeTypeField = 'nodeType' +parentIDField = 'parentId' + +class Record: + def __init__(self,id:str,tableName:str,property:dict) -> None: + self._childs = [] + self._id = id + self._property:dict = property + self._tableName = tableName + + def add(self,rcd:'Record'): + self._childs.append(rcd) + + @property + def Property(self): + return self._property + + @property + def Id(self): + return self._id + + @property + def Name(self): + for name,value in self._property.items(): + if '名称' in name: + return value + raise ValueError('记录名称为空') + + @property + def Label(self): + if '工程属性' in self._tableName: + label = '属性项' + else: + label = self.Property[nodeTypeField] if nodeTypeField in self.Property else self.Name + label = label + '项' + return label + + @property + def HasChild(self): + return len(self._childs) > 0 + + def childCount(self): + return len(self._childs) + + def child(self,index:int): + return self._childs[index] + +class RecordTreeMake: + def __init__(self,tableName:str,records:list) -> None: + self._records = records + self._tableName = tableName + + def make(self)->list[Record]: + rcdMaps:dict[str,Record] = {} + for record in self._records: + parid= '' + if parentIDField in record: + parid = record[parentIDField] + id = record[IdField] if IdField in record else str(uuid.uuid1()) + if parid in rcdMaps: + parRcd = rcdMaps[parid] + parRcd.add(Record(id,self._tableName,record)) + else: + rcdMaps[id] = Record(id,self._tableName,record) + return list(rcdMaps.values()) + class PrjGraphExtractor(TransformComponent): ProjectName:str _nodeMaps = {} @@ -37,24 +104,20 @@ class PrjGraphExtractor(TransformComponent): records:dict[str,list] = self._getRecordNode(llama_node) fInfos = fileName.split('_') if len(fInfos) == 1: - fileID = self._add_node(existing_nodes = existing_nodes,name=fInfos[0], label=fInfos[0]) + fileID = self._addTableNode(existing_nodes = existing_nodes,name=fInfos[0], label=fInfos[0]) elif len(fInfos) == 2: - fileID = self._add_node(existing_nodes = existing_nodes,name=fileName, label=fInfos[1]) + fileID = self._addTableNode(existing_nodes = existing_nodes,name=fInfos[1], label=fInfos[0]) else: - raise ValueError("文件名存在多个下划线") + raise ValueError("文件名存在多个下划线") - index = 0 - for record in records: - index = index + 1 - rcdName = self._getRecordName(fileName,record) - rcdid = self._add_node(existing_nodes = existing_nodes,name=rcdName, label=rcdName,properties = record) - existing_relations.append( - RagRelation( - label="包含", - source_id= fileID, - target_id= rcdid - ) - ) + rdMake = RecordTreeMake(fileName,records) + rcds:list[Record] = rdMake.make() + + for record in rcds: + self._make_RecordEdge(existing_nodes = existing_nodes, + existing_relations = existing_relations, + fileID = fileID, + rcd = record) existing_relations.append( RagRelation( @@ -73,13 +136,13 @@ class PrjGraphExtractor(TransformComponent): existing_nodes:list = llama_node.metadata.pop(KG_NODES_KEY, []) existing_relations:list = llama_node.metadata.pop(KG_RELATIONS_KEY, []) records:dict[str,list] = self._getRecordNode(llama_node) - fileID = self._add_node(existing_nodes = existing_nodes,name=fileName, label=fileName) + fileID = self._addTableNode(existing_nodes = existing_nodes,name=fileName, label=fileName) - index = 0 - for record in records: - index = index + 1 - attName = self._getRecordName(fileName,record) - attID = self._add_node(existing_nodes = existing_nodes,name=attName, label= attName,properties = record) + rdMake = RecordTreeMake(fileName,records) + rcds:list[Record] = rdMake.make() + + for record in rcds: + attID = self._add_RecorNode(existing_nodes = existing_nodes,rcd = record) existing_relations.append( RagRelation( label="聚合", @@ -113,32 +176,56 @@ class PrjGraphExtractor(TransformComponent): def _addPrjNode(self,llama_node:BaseNode): existing_nodes:list = llama_node.metadata.pop(KG_NODES_KEY, []) - self._prjID = self._add_node(existing_nodes = existing_nodes,name=self.ProjectName,label=self.ProjectName) + self._prjID = self._addTableNode(existing_nodes = existing_nodes,name=self.ProjectName,label=self.ProjectName) llama_node.metadata[KG_NODES_KEY] = existing_nodes - def _getRecordName(self,fileName:str,record:dict): - for name,value in record.items(): - if '名称' in name: - return value - raise ValueError('记录名称为空') + def _addTableNode(self,existing_nodes:list,name:str,label:str): + return self._add_Node(existing_nodes,name,label,str(uuid.uuid1())) + + def _add_RecorNode(self,existing_nodes:list,rcd:Record): + return self._add_Node(existing_nodes,rcd.Name,rcd.Label,rcd.Id,rcd.Property) - def _add_node(self,existing_nodes:list,name:str,label:str,properties:dict = {}): + def _add_Node(self,existing_nodes:list,name:str,label:str,defaultid:str,property:dict= {}): id:str = '' if name in self._nodeMaps: nodes:list[RagEntityNode] = self._nodeMaps[name] for node in nodes: - if node.properties == properties and node.name == name and node.label == label: + if node.properties == property and node.name == name and node.label == label: id = node.id break if id =='': - id = str(uuid.uuid1()) - newNode = RagEntityNode(name = name,label=label,properties = properties,uid = id) + id = defaultid + newNode = RagEntityNode(name = name,label=label,properties = property,uid = id) existing_nodes.append(newNode) if name in self._nodeMaps: nodes:list[RagEntityNode] = self._nodeMaps[name] nodes.append(newNode) else: self._nodeMaps[name] = [newNode] + return id - return id \ No newline at end of file + def _make_RecordEdge(self,existing_nodes:list,existing_relations:list,fileID:str,rcd:Record,parID:str = ''): + rcdID = self._add_RecorNode(existing_nodes = existing_nodes,rcd = rcd) + if fileID!='': + existing_relations.append( + RagRelation( + label="子级", + source_id= fileID, + target_id= rcdID + ) + ) + + if parID!='': + existing_relations.append( + RagRelation( + label="子级", + source_id= parID, + target_id= rcdID + ) + ) + + if rcd.HasChild: + for i in range(rcd.childCount()): + child = rcd.child(i) + self._make_RecordEdge(existing_nodes,existing_relations,'',child,rcdID) diff --git a/backend/app/engine/graph/graphStore.py b/backend/app/engine/graph/graphStore.py index 60ac9ba..7d143e2 100644 --- a/backend/app/engine/graph/graphStore.py +++ b/backend/app/engine/graph/graphStore.py @@ -39,4 +39,22 @@ class RAGPropertyGraphStore(SimplePropertyGraphStore): graph.nodes = kg_nodes graph.relations = kg_relations - return cls(graph) \ No newline at end of file + return cls(graph) + + def save_networkx_graph(self, name: str = "kg.html") -> None: + """Display the graph store, useful for debugging.""" + import networkx as nx + + G = nx.DiGraph() + for node in self.graph.nodes.values(): + if isinstance(node,EntityNode): + G.add_node(node.id, label=node.name) + for triplet in self.graph.triplets: + G.add_edge(triplet[0], triplet[2], label=triplet[1]) + + # save to html file + from pyvis.network import Network + + net = Network(notebook=False, directed=True) + net.from_nx(G) + net.write_html(name) \ No newline at end of file diff --git a/backend/app/engine/vectordb.py b/backend/app/engine/vectordb.py index e610baa..9fd71b8 100644 --- a/backend/app/engine/vectordb.py +++ b/backend/app/engine/vectordb.py @@ -3,7 +3,6 @@ from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.vector_stores.qdrant import QdrantVectorStore from qdrant_client import qdrant_client from llama_index.graph_stores.neo4j import Neo4jPropertyGraphStore - qclient = None def get_qdrant_vector_store(docType:str): @@ -74,6 +73,12 @@ def get_vector_store(docType:str): return store def get_Neo4j_Graph_Store(docType:str): + from neo4j import GraphDatabase + driver = GraphDatabase.driver(os.getenv('NEO4J_URL'), auth=(os.getenv('NEO4J_USERNAME'), os.getenv('NEO4J_PASSWORD'))) + with driver.session() as session: + session.run("MATCH (n) DETACH DELETE n") + driver.close() + neo4jStore = Neo4jPropertyGraphStore( username= os.getenv('NEO4J_USERNAME'), password= os.getenv('NEO4J_PASSWORD'), diff --git a/backend/unit_test/Quetions/projects_0ffaf7fb-8a61-46e2-97a2-8f924e9560a7.json b/backend/unit_test/Quetions/projects_0ffaf7fb-8a61-46e2-97a2-8f924e9560a7.json index 1e3fb4e..719bd33 100644 --- a/backend/unit_test/Quetions/projects_0ffaf7fb-8a61-46e2-97a2-8f924e9560a7.json +++ b/backend/unit_test/Quetions/projects_0ffaf7fb-8a61-46e2-97a2-8f924e9560a7.json @@ -1,124 +1,282 @@ { - "test:线路工程查询": [ + "test:工程属性_普通属性": [ { - "question": "基础工程项目划分合价", - "answer": "5099350万元 或者 49051649643元" + "question": "设置线材工地运输计算方式", + "answer": "设置线材工地运输计算方式是按实际用量计算。" }, { - "question": "此工程名称", - "answer": "架线南网" + "question": "材料调差系数", + "answer": "材料调差系数: -0.95" }, { - "question": "此工程电压等级", - "answer": "35kV" + "question": "拆除安装材料按系数调差", + "answer": "拆除安装材料按系数调差的值是1。" }, { - "question": "基础工程项目划分合价", - "answer": "合价为 49051649642.9667 元" + "question": "甲供材料损耗是否计入甲供材料费", + "answer": "甲供材料损耗是否计入甲供材料费的值为 -1。" }, { - "question": "基础工程项目划分合价,输出以万元为单位", - "answer": "合价总计为4905164.96429667万元" + "question": "计税方式", + "answer": "计税方式: 增值税" }, { - "question": "建设场地征用及清理费是多少", - "answer": "建设场地征用及清理费的金额为16831284.228711元" + "question": "地形调整及跳跃施工计算顺序", + "answer": "地形调整及跳跃施工计算顺序: 0" }, { - "question": "建设场地征用及清理费金额多少", - "answer": "建设场地征用及清理费的金额为16831284.228711元" + "question": "是否自动计算凿桩头总量", + "answer": "是" }, { - "question": "线路亘长", - "answer": "此工程的线路亘长为5.0公里。" + "question": "脚手架材料费系数", + "answer": "脚手架材料费系数的值是0.5。" }, { - "question": "工程运距", - "answer": "工程运距包括:人力运距20km,汽车运距30km,拖拉机运距40km,船舶运距40km,海缆船舶运距50km,索道运距7km。" + "question": "工程唯一标识码", + "answer": "工程唯一标识码: {2FD2000A-C003-4573-8605-88C7B94EFA0F}" }, { - "question": "基坑土石方单公里用量", - "answer": "81081630.354" - }, - { - "question": "基本预备费费率", - "answer": "基本预备费的费率为2%。" - }, - { - "question": "调差文件", - "answer": "调差文件指的是调差系数文件〔2020年14号文〕" - }, - { - "question": "工程税率", - "answer": "工程税率是9.0%" - }, - { - "question": "新建时间", - "answer": "2020/10/9" - }, - { - "question": "工程静态投资,以万元为单位", - "answer": "71503585.3336万元" - }, - { - "question": "耐张塔比例", - "answer": "耐张塔的比例为38.462%" - }, - { - "question": "耐张杆比例", - "answer": "耐张杆的比例是72.222%。" - }, - { - "question": "耐张杆的比例是如何计算出来的?", - "answer": "耐张杆的比例计算方式是将耐张杆基数除以耐张杆和直线杆的总基数,然后将结果转换为百分比。" - }, - { - "question": "勘察设计费", - "answer": "勘察设计费的总金额为16164210209.43,其中包含勘察费12122154260.0和设计费4042055949.43。" - }, - { - "question": "岩石比例", - "answer": "99" - }, - { - "question": "人工挖孔", - "answer": "148" - }, - { - "question": "余土运距", - "answer": "余土运距为187.0公里" - }, - { - "question": "高压线(含10kV)", - "answer": "3处" - }, - { - "question": "基坑普通土", - "answer": "313873965.334m³" - }, - { - "question": "尖峰及施工基面普通土", - "answer": "尖峰及施工基面普通土的量为6534.528 m³" - }, - { - "question": "节能评估费用", - "answer": "节能评估费用在电力工程造价中被标识为C1A,其费率设置为100.0%,但需要注意的是,在当前工程中此费用的金额为0.0。" - }, - { - "question": "工程监理费", - "answer": "工程监理费的代码为B3,其费率是100.0,金额为131009.92。" - }, - { - "question": "可行性研究文件评审费", - "answer": "可行性研究文件评审费的代码是C41,其金额为13340.0。" - }, - { - "question": "接地工程合价", - "answer": "合价为 121964.914965元" - }, - { - "question": "接地工程项目划分合价", - "answer": "合价为 121964.914965元" + "question": "计价方式", + "answer": "计价方式: 定额计价" } - ] + ], + "test:工程属性_单位换算": [ + { + "question": "工程总投资(万元),结果用元表示", + "answer": "根据提供的信息,工程总投资为81579073.299588 万元转换为元是815790732995.88元。" + }, + { + "question": "总价万元,结果用元表示", + "answer": "总价万元为77469835.590045万元,转换为元表示即为774698355900.45元。" + }, + { + "question": "工程总投资,结果用万元表示", + "answer": "工程总投资为71503585.3336元。因此,工程总投资为7150.35853336元万。" + }, + { + "question": "余土外运量,结果用立方分米表示", + "answer": "余土外运量为583624.490963立方米,因此,583624490.963立方分米。" + } + ], + "test:总算表_金额查询": [ + { + "question": "序号为“一”的金额是多少?", + "answer": "金额字段的值为55105688268.517624。" + }, + { + "question": "名称为“架空输电线路本体工程”的金额是多少?", + "answer": "名称为“架空输电线路本体工程”的记录中,其金额为55105688268.517624。" + }, + { + "question": "代码为“BTGC”的金额是多少?", + "answer": "代码为“BTGC”的记录中,对应的金额为55105688268.517624。" + }, + { + "question": "金额字段值为“55105688268.517624”的取费基数是多少?", + "answer": "金额字段值为“55105688268.517624”的记录对应的取费基数是100。" + }, + { + "question": "编码字段值为“2131243”的金额是多少?", + "answer": "编码字段值为“2131243”的金额55105688268.517624。" + }, + { + "question": "服务内容为“是”的金额是多少?", + "answer": "服务内容为“是”的金额是55105688268.517624。" + }, + { + "question": "费用归属字段值为“否”的金额是多少?", + "answer": "费用归属字段值为“否”的金额是55105688268.517624。" + }, + { + "question": "表一显示字段值为“否”的金额是多少?", + "answer": "表一显示字段值为“否”的金额为55105688268.517624。" + }, + { + "question": "建筑费字段值为“0”的金额是多少?", + "answer": "根据提供的表格数据,建筑费字段值为“0”的行对应的金额是55105688268.517624。这一数值出现在第一行的最后一列“合计费”中。" + } + ], + "test:总算表_金额查询": [ + { + "question": "架空输电线路本体工程的金额是多少?", + "answer": "根据提供的表格数据,架空输电线路本体工程的金额是55105688268.517624。" + }, + { + "question": "一般线路本体工程的金额是多少?", + "answer": "一般线路本体工程的金额是55105688268.517624。" + }, + { + "question": "名称为辅助设施工程的金额是多少?", + "answer": "名称为“辅助设施工程”的金额为403152254301.795654。" + }, + { + "question": "名称为小计的金额是多少?", + "answer": "名称为“小计”的金额是458257942570.313293。" + }, + { + "question": "名称为编制基准期价差的金额是多少?", + "answer": "名称为编制基准期价差的金额是29246752707.118019元。" + }, + { + "question": "名称为设备购置费的金额是多少?", + "answer": "根据提供的信息,名为“设备购置费”的项目的金额是2567934636.357451元。" + }, + { + "question": "名称为其他费用的金额是多少?", + "answer": "名为“其他费用”的金额是210942912572.869415元。" + }, + { + "question": "名称为建设场地征用及清理费的金额是多少?", + "answer": "名为“建设场地征用及清理费”的金额为16831284.228711元。" + }, + { + "question": "名称为工程建设检测费的金额是多少?", + "answer": "名称为工程建设检测费的金额是185575370.146398" + }, + { + "question": "其中:特种设备安全监测费的金额是多少?", + "answer": "其中:特种设备安全监测费的金额是0。" + } + ], + "test:其他费用_金额查询": [ + { + "question": "名称为建设场地征用及清理费的金额是多少?", + "answer": "名称为“建设场地征用及清理费”的记录显示其金额为16831284.228711。" + }, + { + "question": "名称为项目建设管理费的金额是多少?", + "answer": "名称为“项目建设管理费”的金额是1619697876.652205。" + }, + { + "question": "名称为项目法人管理费的金额是多少?", + "answer": "根据提供的表格数据,名称为“项目法人管理费”的记录显示其金额为986923559.414937。" + }, + { + "question": "名称为招标费的金额是多少?", + "answer": "名称为“招标费”的金额是236,186,834.73178。" + }, + { + "question": "序号为2.1的金额是多少?", + "answer": "序号为2.1的记录对应的金额是986923559.414937。" + }, + { + "question": "序号为2.2的金额是多少?", + "answer": "序号为2.2的记录对应的金额是236186834.73178。" + }, + { + "question": "编码为318G0000000的金额是多少?", + "answer": "编码为318G0000000的金额是16831284.228711。" + }, + { + "question": "编码为318A0000000的金额是多少?", + "answer": "根据提供的表格数据,编码为318A0000000的记录对应的金额是2567934636.357451。" + }, + { + "question": "编码为31870000000的金额是多少?", + "answer": "根据提供的表格数据,编码为31870000000的行中,对应的金额是61246155757.175179。" + }, + { + "question": "名称为工程监理费的金额是多少?", + "answer": "根据给定的上下文信息,名为“工程监理费”的项目的金额是131009.92。" + } + ], + "test:其他费用_单位换算": [ + { + "question": "建设场地征用及清理费(元),结果用万元表示。", + "answer": "根据提供的表格数据,建设场地征用及清理费的金额为16831284.228711元。结果用万元表示为1683.1284228711万元。" + }, + { + "question": "项目建设管理费(元),结果用万元表示。", + "answer": "根据提供的表格数据,项目建设管理费(元)为1619697876.652205元。将其转换为万元表示,结果为161969.7876652205万元,通常可以四舍五入为161969.79万元。" + }, + { + "question": "项目法人管理费(元),结果用万元表示。", + "answer": "根据提供的表格数据,项目法人管理费(B1)的金额为986923559.414937元。将其转换为万元表示,结果为98692.3559414937万元,通常可以四舍五入为98692.36万元。" + }, + { + "question": "招标费(元),结果用万元表示。", + "answer": "根据提供的表格数据,招标费(B2)的金额为236,186,834.73178元。将其转换为万元表示,结果为236,186.83473178万元,保留到万元单位,可以表示为236,186.83万元。" + } + ], + "test:项目划分_线路_普通属性": [ + { + "question": "名称为一般线路本体工程的费率是多少?", + "answer": "名称为“一般线路本体工程”的费率是0。" + }, + { + "question": "名称为一般线路本体工程的计算式是多少?", + "answer": "名称为“一般线路本体工程”的计算式为空" + }, + { + "question": "名称为一般线路本体工程的费用编码是多少?", + "answer": "名称为“一般线路本体工程”的费用编码为Y1820000000" + }, + { + "question": "名称为一般线路本体工程的路径是多少?", + "answer": "名称为“一般线路本体工程”的路径是一般线路本体工程" + }, + { + "question": "名称为基础工程的费率是多少?", + "answer": "名称为“基础工程”的费率是0。" + }, + { + "question": "名称为基础工程的计算式是多少?", + "answer": "名称为基础工程的计算式为3" + }, + { + "question": "名称为基础工程的费用编码是多少?", + "answer": "名称为基础工程的费用编码是Y1821000000" + }, + { + "question": "名称为基础工程的路径是多少?", + "answer": "名称为基础工程的路径是一般线路本体工程/基础工程。" + }, + { + "question": "名称为一般线路本体工程的nodeType是多少?", + "answer": "名称为一般线路本体工程的nodeType是项目划分。" + }, + { + "question": "名称为一般线路本体工程的parentId是多少?", + "answer": "名称为一般线路本体工程的parentId为空。" + } + ], + "test:项目划分_线路_重名项目划分": [ + { + "question": "专业类型为线路的线路本体工程的合价", + "answer": "根据提供的表格数据,专业类型为线路的线路本体工程的合价为55105688268.517624元。" + }, + { + "question": "专业类型为线路的线路本体工程的拆除人工调差系数", + "answer": "名称为一般线路本体工程的拆除人工调差系数为11.03。" + }, + { + "question": "专业类型为线路的线路本体工程的拆除机械调差系数", + "answer": "名称为“一般线路本体工程”的记录显示了拆除机械调差系数为-0.95。" + }, + { + "question": "专业类型为线路的线路本体工程的拆除材料调差系数", + "answer": "名称字段为“一般线路本体工程”,且“专业类型”字段为“线路”,该记录中的“拆除材料调差系数”字段值为9.89。" + }, + { + "question": "专业类型为线路的线路本体工程的机械调差系数", + "answer": "根据提供的表格数据,专业类型为线路的线路本体工程的机械调差系数为-0.95。" + }, + { + "question": "专业类型为线路的线路本体工程的材料调差系数", + "answer": "根据提供的信息,专业类型为线路的线路本体工程的材料调差系数为-0.95。" + }, + { + "question": "专业类型为线路的线路本体工程的编码", + "answer": "根据提供的表格数据,专业类型为线路的线路本体工程的编码为空。" + }, + { + "question": "专业类型为线路的线路本体工程的计算式", + "answer": "专业类型为线路的线路本体工程的计算式为空" + }, + { + "question": "专业类型为线路的线路本体工程的费率", + "answer": "根据提供的信息,专业类型为“线路”的线路本体工程的费率是0" + } + ] } \ No newline at end of file diff --git a/backend/unit_test/prompts.py b/backend/unit_test/prompts.py index 93d59eb..818318c 100644 --- a/backend/unit_test/prompts.py +++ b/backend/unit_test/prompts.py @@ -1,12 +1,12 @@ -Attribute_Prompt = ( - "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," - "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," - "现在需要你针对数据中属性一列进行提问和回答。" - "问题和回答的示例应该是这种类型的,示例:工程总投资(万元),工程总投资(万元)是77469835.590045万元;尖峰及施工基面土石方量,尖峰及施工基面土石方量是8377.6;截止阀的编码,截止阀的编码是F01010203。" - "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" - "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," - "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" -) +# Attribute_Prompt = ( +# "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," +# "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," +# "现在需要你针对数据中属性一列进行提问和回答。" +# "问题和回答的示例应该是这种类型的,示例:工程总投资(万元),工程总投资(万元)是77469835.590045万元;尖峰及施工基面土石方量,尖峰及施工基面土石方量是8377.6;截止阀的编码,截止阀的编码是F01010203。" +# "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" +# "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," +# "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" +# ) # Amount_Prompt = ( @@ -20,15 +20,6 @@ Attribute_Prompt = ( # ) -###MarkDown格式的提示词 -Amount_Prompt = """\ - 上下文信息是一张表格数据,请根据数据表中内容进行生成{num_questions_per_chunk}个和金额有关的问题。 - 生成规则推荐使用表中某行数据的某个值来查询“金额”字段值是多少钱的方式。 - 你生成的回答必须严格按照指定的格式生成,格式为:xxxx的金额是多少。其中xxxx表示的是某行的某个数据的值(金额字段的值除外)。 - 当文档中信息与金额无关时,请不要额外发散回答,只需要回答为' ' - 不要生成一些无关的问题,不要生成一些重复的问题 -""" - ###Json格式的提示词 # Amount_Prompt = """\ # 上下文信息是Json结构的数据,请根据数据表中内容进行生成{num_questions_per_chunk}个和金额有关的问题。 @@ -39,35 +30,82 @@ Amount_Prompt = """\ # """ -Units_Prompt = ( - "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," - "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," - "现在需要你针对上下文信息来进行单位转化问题提问和回答。" - "问题和回答的示例应该是这种类型的,示例:工程总投资(万元)结果用元表示,工程总投资(万元)是774698355900.45元;本体工程(元)结果用万元表示,本体工程(元)是5490494.261046万元。" - "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" - "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," - "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" -) +# Units_Prompt = ( +# "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," +# "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," +# "现在需要你针对上下文信息来进行单位转化问题提问和回答。" +# "问题和回答的示例应该是这种类型的,示例:工程总投资(万元)结果用元表示,工程总投资(万元)是774698355900.45元;本体工程(元)结果用万元表示,本体工程(元)是5490494.261046万元。" +# "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" +# "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," +# "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" +# ) -Name_Prompt = ( - "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," - "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," - "现在需要你针对上下文信息中的重名问题进行提问和回答。" - "问题和回答的示例应该是这种类型的,示例:专业类型为线路的杆塔工程项目划分的合价,专业类型为线路的杆塔工程项目划分的合价是220969744.905856;专业类型为线路清理的杆塔工程项目划分的合价,电缆工程的合价是0。" - "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" - "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," - "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" -) +# Name_Prompt = ( +# "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," +# "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," +# "现在需要你针对上下文信息中的重名问题进行提问和回答。" +# "问题和回答的示例应该是这种类型的,示例:专业类型为线路的杆塔工程项目划分的合价,专业类型为线路的杆塔工程项目划分的合价是220969744.905856;专业类型为线路清理的杆塔工程项目划分的合价,电缆工程的合价是0。" +# "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" +# "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," +# "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" +# ) -All_Amount_Prompt = ( - "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," - "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," - "现在需要你针对上下文信息中的总体金额进行提问和回答。" - "问题和回答的示例应该是这种类型的,示例:架空输电线路本体工程的总体金额,架空输电线路本体工程的总体金额是7.706703;工程静态投资的总体金额,工程静态投资的总体金额是100。" - "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" - "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," - "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" -) +# All_Amount_Prompt = ( +# "你是一个电力造价工程相关的项目经理,现在给你一些上下文信息," +# "你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题和对应的回答," +# "现在需要你针对上下文信息中的总体金额进行提问和回答。" +# "问题和回答的示例应该是这种类型的,示例:架空输电线路本体工程的总体金额,架空输电线路本体工程的总体金额是7.706703;工程静态投资的总体金额,工程静态投资的总体金额是100。" +# "你生成的回答必须严格按照示例中的格式:('问题, 回答')。不允许有丝毫的变动,问题和回答应该在一个单引号内。" +# "这种类似的问题和答案,生成的问题和答案必须一一对应,要符合文件里的内容,不要生成一些无关的问题,不要生成一些重复的问题," +# "不要生成一些过于简单的问题,不要生成一些过于复杂的问题。" +# ) +#----------------------------MarkDown格式的提示词------------------------------------- +Amount_Prompt = """\ + 上下文信息是一张表格数据,请根据数据表中内容进行生成{num_questions_per_chunk}个和金额有关的问题。 + 生成规则推荐使用表中某行数据的某个值来查询“金额”字段值是多少钱的方式。 + 你生成的问题必须严格按照指定的格式生成,格式为:名称为'aaaa'的金额是多少? + aaaa:表示的是名称的值 + 当文档中信息与金额无关时,请不要额外发散回答,只需要回答为' ' + 不要生成一些无关的问题,不要生成一些重复的问题 +""" + +All_Amount_Prompt = """\ + 上下文信息是一张表格数据,请根据数据表中内容进行生成{num_questions_per_chunk}个和总体金额有关的问题。 + 生成规则推荐使用表中某行数据的某个值来查询“总体金额”相关字段值是多少钱的方式。 + 你生成的问题必须严格按照指定的格式生成,格式为:编码为'aaaa'的总体金额是多少? + aaaa:表示的是编码的值 + 当文档中信息与总体金额无关时,请不要额外发散回答,只需要回答为' ' + 不要生成一些无关的问题,不要生成一些重复的问题 +""" + +Attribute_Prompt ="""\ + 上下文信息是一张表格数据,请根据数据表中内容进行生成{num_questions_per_chunk}个和字段有关的问题。 + 生成规则推荐使用表中某行数据的某个字段及值来查询另一个字段值是多少的方式。 + 你生成的问题必须严格按照指定的格式生成,格式为:名称为'aaaa'的'bbbb'是多少? + aaaa:表示的是名称的值 + bbbb:除名称外的其他字段名 + 当文档中信息与金额无关时,请不要额外发散回答,只需要回答为' ' + 不要生成一些无关的问题,不要生成一些重复的问题 +""" + +Units_Prompt = """\ + 你是一个电力造价工程相关的项目经理,现在给你一些上下文信息。 + 你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题。 + 现在需要你针对上下文信息来进行单位转化问题提问。 + 问题的示例应该是这种类型的,示例:工程总投资(万元),结果用元表示;本体工程(元),结果用万元表示。 + 你生成的回答必须严格按照示例中的格式:问题。 + 当文档中信息与单位无关时,请不要额外发散回答,只需要回答为' ' + 不要生成一些无关的问题,不要生成一些重复的问题。 +""" + +Name_Prompt = """\ + 你是一个电力造价工程相关的项目经理,现在给你一些上下文信息。 + 你需要根据现有的上下文信息,来生成{num_questions_per_chunk}个电力造价工程相关的问题。 + 现在需要你针对上下文信息中的重名问题进行提问。 + 问题的示例应该是这种类型的,示例:专业类型为线路的杆塔工程项目划分的合价?"。 + 你生成的问题必须严格按照示例中的格式,不允许有丝毫的变动。 + 不要生成一些无关的问题,不要生成一些重复的问题。 +""" \ No newline at end of file diff --git a/backend/unit_test/test_evaluate.py b/backend/unit_test/test_evaluate.py index 91f313c..93b1aec 100644 --- a/backend/unit_test/test_evaluate.py +++ b/backend/unit_test/test_evaluate.py @@ -46,13 +46,13 @@ DEFAULT_SYSTEM_TEMPLATE = """ """ DEFAULT_USER_TEMPLATE = """ -## User Query +## 用户问题 {query} -## Reference Answer +## 参考答案 {reference_answer} -## Generated Answer +## 生成的答案 {generated_answer} """ @@ -65,7 +65,7 @@ DEFAULT_EVAL_TEMPLATE = ChatPromptTemplate( # 初始化聊天引擎和评估器 -corr_evaluator_qwen = CorrectnessEvaluator() +corr_evaluator_qwen = CorrectnessEvaluator(eval_template = DEFAULT_EVAL_TEMPLATE) # 异步函数用于评估查询