Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slover 过程中 chunk_retriever 和 kg_retriever 都提取不到已有节点信息 #150

Closed
zzzcccxx opened this issue Dec 20, 2024 · 2 comments

Comments

@zzzcccxx
Copy link
Contributor

zzzcccxx commented Dec 20, 2024

我使用的默认schema,我的数据文档如下:

《三国演义》

第一回 宴桃园豪杰三结义 斩黄巾英雄首立功

话说天下大势,分久必合,合久必分。周末七国纷争,最终并入秦国。秦朝灭亡后,楚汉相争,最终归于汉朝。汉朝自高祖刘邦斩白蛇起义,统一天下,后来光武帝中兴,传至献帝,遂分为三国。推究其动乱的根源,大概始于桓、灵二帝。桓帝禁锢忠良,崇信宦官。桓帝死后,灵帝即位,大将军窦武、太傅陈蕃共同辅佐。当时宦官曹节等人弄权,窦武、陈蕃密谋诛杀他们,因机密泄露,反被所害,宦官从此更加横行。

建宁二年四月十五日,灵帝在温德殿上朝。刚升座,殿角突然狂风大作。只见一条大青蛇从梁上飞下,盘踞在椅子上。灵帝惊倒,左右急忙扶他入宫,百官纷纷奔逃。片刻后,蛇不见了。忽然雷雨大作,夹杂冰雹,直到半夜才停,毁坏了许多房屋。建宁四年二月,洛阳发生地震;海水泛滥,沿海居民被大浪卷入海中。光和元年,雌鸡化雄。六月初一,黑气十余丈飞入温德殿。七月,彩虹出现在玉堂;五原山崖崩裂。种种不祥之兆,不止一端。灵帝下诏询问群臣灾异的原因,议郎蔡邕上疏,认为这些异象是妇人和宦官干政所致,言辞颇为直切。灵帝看后叹息,起身更衣。曹节在后面偷看,将奏章内容告知左右,遂以其他罪名陷害蔡邕,将其放归田里。后来张让、赵忠、封谞、段珪、曹节、侯览、蹇硕、程旷、夏恽、郭胜十人结党为奸,号称“十常侍”。灵帝尊信张让,称他为“阿父”。朝政日益腐败,导致天下人心思乱,盗贼四起。

当时巨鹿郡有兄弟三人,一名张角,一名张宝,一名张梁。张角原本是个落第的秀才,因入山采药,遇到一位老人,碧眼童颜,手持藜杖,唤张角到一洞中,授予他三卷天书,说:“此书名为《太平要术》,你得到它,应当代天宣化,普救世人;若心生异念,必遭恶报。”张角拜问老人姓名,老人说:“我是南华老仙。”说完,化作一阵清风而去。张角得到此书,日夜研习,能呼风唤雨,自称“太平道人”。中平元年正月,疫病流行,张角散施符水为人治病,自称“大贤良师”。张角有徒弟五百余人,云游四方,都能书符念咒。后来徒众日益增多,张角设立三十六方,大方万余人,小方六七千人,各立渠帅,称为将军;并散布谣言:“苍天已死,黄天当立;岁在甲子,天下大吉。”让人在家门上用白土书写“甲子”二字。青、幽、徐、冀、荆、扬、兖、豫八州之人,家家供奉大贤良师张角的名字。张角派其党羽马元义,暗中携带金帛,结交宦官封谞,以为内应。张角与两个弟弟商议说:“最难得到的是民心。如今民心已顺,若不趁势夺取天下,实在可惜。”于是私下制造黄旗,约定日期举事;一面派弟子唐周,送信给封谞。唐周直接到省中告发。灵帝召大将军何进调兵捉拿马元义,斩首;随后逮捕封谞等人下狱。张角得知事情败露,连夜举兵,自称“天公将军”,张宝称“地公将军”,张梁称“人公将军”。向众人宣称:“如今汉朝气数已尽,大圣人将出。你们都应顺应天意,以享太平。”四方百姓,裹黄巾跟随张角反叛的有四五十万人。贼势浩大,官军望风而逃。何进奏请灵帝火速下诏,令各处备御,讨贼立功。一面派遣中郎将卢植、皇甫嵩、朱儁,各率精兵,分三路讨伐。

且说张角一军,前犯幽州界。幽州太守刘焉,乃江夏竟陵人氏,汉鲁恭王之后。当时听说贼兵将至,召校尉邹靖商议。邹靖说:“贼兵众多,我兵寡少,明公应尽快招募义兵应敌。”刘焉同意,随即出榜招募义兵。

榜文传到涿县,引出涿县中一位英雄。那人不甚好读书;性情宽和,寡言少语,喜怒不形于色;素有大志,专好结交天下豪杰;身高七尺五寸,两耳垂肩,双手过膝,目能自顾其耳,面如冠玉,唇若涂脂;中山靖王刘胜之后,汉景帝阁下玄孙,姓刘名备,字玄德。昔日刘胜之子刘贞,汉武帝时封涿鹿亭侯,后因酎金失侯,因此遗留这一支在涿县。玄德祖父刘雄,父亲刘弘。刘弘曾举孝廉,也曾为吏,早逝。玄德幼年丧父,事母至孝;家贫,以贩屦织席为业。家住本县楼桑村。他家东南方有一棵大桑树,高五丈余,远远望去,如车盖。相士说:“此家必出贵人。”玄德幼时,与乡中小儿在树下玩耍,说:“我为天子,当乘此车盖。”叔父刘元起觉得他言语不凡,说:“此儿非同寻常!”因见玄德家贫,常资助他。十五岁时,母亲让他游学,曾师从郑玄、卢植,与公孙瓒等为友。

等到刘焉发榜招募义兵时,玄德已二十八岁。当日见到榜文,慨然长叹。随后一人厉声说:“大丈夫不为国家出力,为何长叹?”玄德回头看那人,身高八尺,豹头环眼,燕颔虎须,声如巨雷,势如奔马。玄德见他相貌非凡,问其姓名。那人说:“我姓张名飞,字翼德。世居涿郡,颇有庄田,卖酒屠猪,专好结交天下豪杰。刚才见你看榜而叹,故此相问。”玄德说:“我是汉室宗亲,姓刘,名备。如今听说黄巾贼作乱,有心破贼安民,可惜力不从心,故此长叹。”张飞说:“我颇有资财,当招募乡勇,与你一同举事,如何?”玄德大喜,遂与张飞一同入村店饮酒。

正饮酒间,见一大汉推着一辆车子,到店门口歇下,进店坐下,便唤酒保:“快斟酒来,我赶着进城投军。”玄德看那人:身高九尺,髯长二尺;面如重枣,唇若涂脂;丹凤眼,卧蚕眉,相貌堂堂,威风凛凛。玄德邀请他同坐,问其姓名。那人说:“我姓关名羽,字长生,后改云长,河东解良人。因本处豪强倚势欺人,被我杀了,逃难江湖,已有五六年。今闻此处招军破贼,特来应募。”玄德遂将自己的志向告诉他,云长大喜。三人一同到张飞庄上,共议大事。张飞说:“我庄后有一桃园,花开正盛;明日我们可在园中祭告天地,结为兄弟,同心协力,然后方可图大事。”玄德、云长齐声应道:“如此甚好。”

次日,在桃园中备下乌牛白马等祭品,三人焚香再拜,立誓说:“念刘备、关羽、张飞,虽然异姓,既结为兄弟,则同心协力,救困扶危;上报国家,下安黎庶。不求同年同月同日生,只愿同年同月同日死。皇天后土,实鉴此心,背义忘恩,天人共戮!”誓毕,拜玄德为兄,关羽次之,张飞为弟。祭告天地后,宰牛设酒,聚集乡中勇士三百余人,在桃园中痛饮一醉。次日收拾军器,可惜无马匹可乘。正思虑间,有人报告有两个客人,带一伙伴,赶一群马,投庄上来。玄德说:“这是天助我也!”三人出庄迎接。原来二客是中山大商:一名张世平,一名苏双,每年往北贩马,近因贼乱而回。玄德请二人到庄,置酒款待,诉说欲讨贼安民之意。二人大喜,愿将良马五十匹相送;又赠金银五百两,镔铁一千斤,以资器用。

玄德谢别二客,命良匠打造双股剑。云长造青龙偃月刀,又名“冷艳锯”,重八十二斤。张飞造丈八点钢矛。各置全身铠甲。共聚乡勇五百余人,来见邹靖。邹靖引见太守刘焉。三人参见毕,各通姓名。玄德说起宗派,刘焉大喜,遂认玄德为侄。不数日,有人报告黄巾贼将程远志统兵五万来犯涿郡。刘焉令邹靖引玄德等三人,统兵五百,前去破敌。玄德等欣然领军前进,直至大兴山下,与贼相见。贼众皆披发,以黄巾抹额。当下两军相对,玄德出马,左有云长,右有翼德,扬鞭大骂:“反国逆贼,何不早降!”程远志大怒,派副将邓茂出战。张飞挺丈八蛇矛直出,手起处,刺中邓茂心窝,翻身落马。程远志见折了邓茂,拍马舞刀,直取张飞。云长舞动大刀,纵马飞迎。程远志见了,早吃一惊,措手不及,被云长刀起处,挥为两段。后人有诗赞二人:英雄露颖在今朝,一试矛兮一试刀。初出便将威力展,三分好把姓名标。

众贼见程远志被斩,皆倒戈而走。玄德挥军追赶,投降者不计其数,大胜而回。刘焉亲自迎接,赏劳军士。次日,接到青州太守龚景的牒文,说黄巾贼围城将陷,乞赐救援。刘焉与玄德商议。玄德说:“我愿前往救援。”刘焉令邹靖率兵五千,同玄德、关、张,投青州来。贼众见救军至,分兵混战。玄德兵寡不胜,退三十里下寨。

玄德对关羽、张飞说:“贼众我寡;必须出奇兵,方可取胜。”于是分关羽引一千军伏山左,张飞引一千军伏山右,鸣金为号,齐出接应。次日,玄德与邹靖引军鼓噪而进。贼众迎战,玄德引军便退。贼众乘势追赶,刚过山岭,玄德军中一齐鸣金,左右两军齐出,玄德挥军回身复杀。三路夹攻,贼众大溃。直追至青州城下,太守龚景也率民兵出城助战。贼势大败,斩杀极多,遂解青州之围。后人有诗赞玄德:运筹决算有神功,二虎还须逊一龙。初出便能垂伟绩,自应分鼎在孤穷。

龚景犒赏军士毕,邹靖欲回。玄德说:“近闻中郎将卢植与贼首张角战于广宗,我曾师从卢植,欲前往助战。”于是邹靖引军自回,玄德与关、张引本部五百人投广宗来。至卢植军中,入帐施礼,具道来意。卢植大喜,留在帐前听调。

当时张角贼众十五万,卢植兵五万,相拒于广宗,未见胜负。卢植对玄德说:“我今围贼在此,贼弟张梁、张宝在颍川,与皇甫嵩、朱儁对垒。你可引本部人马,我再助你一千官军,前去颍川打探消息,约期剿捕。”玄德领命,引军星夜投颍川来。

当时皇甫嵩、朱儁领军拒贼,贼战不利,退入长社,依草结营。嵩与儁计议说:“贼依草结营,当用火攻。”遂令军士每人束草一把,暗地埋伏。当夜大风忽起。二更以后,一齐纵火,嵩与儁各引兵攻击贼寨,火焰张天,贼众惊慌,马不及鞍,人不及甲,四散奔走。

杀到天明,张梁、张宝引败残军士,夺路而走。忽见一彪军马,尽打红旗,当头来到,截住去路。为首闪出一将,身高七尺,细眼长髯,官拜骑都尉,沛国谯郡人,姓曹名操字孟德。曹操父亲曹嵩,本姓夏侯氏,因是中常侍曹腾的养子,故冒姓曹。曹嵩生曹操,小字阿瞒,一名吉利。曹操幼时,好游猎,喜歌舞,有权谋,多机变。曹操有叔父,见他游荡无度,曾怒斥他,告诉曹嵩。曹嵩责备曹操。曹操心生一计,见叔父来,假装倒地,作中风状。叔父惊告曹嵩,曹嵩急忙来看。曹操故作无恙。曹嵩说:“叔父说你中风,现在好了吗?”曹操说:“我从未得此病;因叔父不喜欢我,故此诬陷。”曹嵩信以为真。后来叔父再言曹操过失,曹嵩不再听信。因此,曹操得以恣意放荡。当时有人桥玄,对曹操说:“天下将乱,非命世之才不能济。能安天下者,大概就是你吧?”南阳何顒见曹操,说:“汉室将亡,安天下者,必此人也。”汝南许劭,有知人之名。曹操去见他,问:“我是什么样的人?”许劭不答。再问,许劭说:“你是治世之能臣,乱世之奸雄。”曹操听后大喜。二十岁时,举孝廉,为郎,任洛阳北部尉。初到任,即设五色棒十余条于县之四门,有犯禁者,不论豪贵,皆责罚。中常侍蹇硕的叔父,提刀夜行,曹操巡夜拿住,用棒责罚。从此,内外无人敢犯,威名大震。后为顿丘令,因黄巾起,拜为骑都尉,引马步军五千,前来颍川助战。正值张梁、张宝败走,曹操拦住,大杀一阵,斩首万余级,夺得旗幡、金鼓、马匹极多。张梁、张宝死战得脱。曹操见过皇甫嵩、朱儁,随即引兵追袭张梁、张宝去了。

却说玄德引关、张来颍川,听得喊杀之声,又望见火光烛天,急引兵来时,贼已败散。玄德见皇甫嵩、朱儁,具道卢植之意。嵩说:“张梁、张宝势穷力乏,必投广宗去依张角。玄德可即星夜往助。”玄德领命,遂引兵复回。到得半路,只见一簇军马,护送一辆槛车,车中之囚,乃卢植也。玄德大惊,滚鞍下马,问其缘故。卢植说:“我围张角,将次可破;因张角用妖术,未能即胜。朝廷差黄门左丰前来体探,问我索取贿赂。我答曰:‘军粮尚缺,安有余钱奉承天使?’左丰挟恨,回奏朝廷,说我高垒不战,惰慢军心;因此朝廷震怒,遣中郎将董卓来代将我兵,取我回京问罪。”张飞听罢,大怒,要斩护送军人,以救卢植。玄德急忙制止说:“朝廷自有公论,你岂可轻举妄动?”军士簇拥卢植去了。关羽说:“卢中郎已被逮捕,别人领兵,我们无所依靠,不如暂回涿郡。”玄德听从,遂引军北行。行无二日,忽闻山后喊声大震。玄德引关、张纵马上高冈望之,见汉军大败,后面漫山遍野,黄巾军铺天盖地而来,旗上大书“天公将军”。玄德说:“这是张角!可速战!”三人飞马引军而出。张角正杀败董卓,乘势赶来,忽遇三人冲杀,张角军大乱,败走五十余里。

三人救了董卓回寨。董卓问三人现居何职。玄德说:“白身。”董卓甚轻之,不为礼。玄德出,张飞大怒说:“我们亲赴血战,救了这厮,他却如此无礼。若不杀他,难消我气!”便要提刀入帐来杀董卓。正是:人情势利古犹今,谁识英雄是白身?安得快人如翼德,尽诛世上负心人!董卓性命如何,且听下文分解。

在建立的过程都没有问题,我的indexer.py文件也采用了用户手册中的例子,代码如下:

# Copyright 2023 OpenSPG Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied.

import os

from kag.builder.component.reader import (
    DocxReader, PDFReader, 
    TXTReader, MarkDownReader, 
    CSVReader, JSONReader
)
from kag.builder.component.splitter import LengthSplitter, OutlineSplitter
from knext.builder.builder_chain_abc import BuilderChainABC
from kag.builder.component.extractor import KAGExtractor
from kag.builder.component.vectorizer.batch_vectorizer import BatchVectorizer
from kag.builder.component.writer import KGWriter
from kag.solver.logic.solver_pipeline import SolverPipeline
import logging
from kag.common.env import init_kag_config

file_path = os.path.dirname(__file__)

suffix_mapping = {
    "docx": DocxReader,
    "pdf": PDFReader,
    "txt": TXTReader,
    "md": MarkDownReader,
    "json": JSONReader,
    "csv": CSVReader,
}

class SanGuoDemoBuildChain(BuilderChainABC):
    def build(self, **kwargs):
        file_path = kwargs.get("file_path","a.docx")
        suffix = file_path.split(".")[-1]
        reader = suffix_mapping[suffix]()
        if reader is None:
            raise NotImplementedError
        project_id = int(os.getenv("KAG_PROJECT_ID"))
        splitter = LengthSplitter(split_length=1000, window_length=100)
        vectorizer = BatchVectorizer()
        extractor = KAGExtractor(project_id=project_id)
        writer = KGWriter()
        
        chain = reader >> splitter >> extractor >> vectorizer >> writer
        return chain
    
def buildKG(test_file,**kwargs):
    chain = SanGuoDemoBuildChain(file_path = test_file)
    chain.invoke(test_file, max_workers=1)
    

if __name__ == "__main__":
    test_txt = os.path.join(file_path,"./data/三国测试.txt")
    buildKG(test_txt)

抽取后的 neo4j 结果如下:
image

随后我使用手册中的实例提问代码进行提问:

import logging
import os

from kag.common.env import init_kag_config
from kag.solver.logic.solver_pipeline import SolverPipeline

logger = logging.getLogger(__name__)

class SanGuoDemo:

    def __init__(self):
        pass

    def qa(self, query):
        resp = SolverPipeline()
        answer, trace_log = resp.run(query)
        return answer,trace_log

if __name__ == "__main__":
    demo = SanGuoDemo()
    query = "关羽和张飞身高相差多少?"
    answer,trace_log = demo.qa(query)
    print(f"Question: {query}")
    print(f"Answer: {answer}")
    print(f"TraceLog: {trace_log}")

根据该问题我得到的sub_queryslogic_forms如下:
image

chunk_retriever:/KAG/kag/solver/logic/core_modules/lf_executor.py文件中的self.chunk_retriever进行召回的时候先对我的提问进行了ner任务,结果也没问题,得到如下结果:**
image

但在使用self.match_entities来召回片段的时候,也就是调用下面这个代码去文本块中召回的时候,却召回不到任何东西:

      typed_nodes = self.sc.search_vector(
          label=query_type,    # Person
          property_key="name",
          query_vector=self.vectorizer.vectorize(query),    # query='关羽'
          topk=top_k,    # 1
      )

nontyped_nodes也同样是召回不到任何东西。

kg_retriever: 由于第一个是 get_spo 操作所以进入的是下面的逻辑:

    if self.retrieval_executor.is_this_op(n):    # n -> get_spo(s=s1:Entity[关羽] ,p=p1:身高,o=o1:None ,sub_query= 查询关羽的身高)
        self.retrieval_executor.executor(n, self.req_id, self.params)    # self.params->{}
        cur_spo_set = self.kg_graph.get_entity_by_alias(n.p.alias_name)    # n.p.alias_name -> p1
        if cur_spo_set is not None and len(cur_spo_set) > 0:
            spo_set += [str(spo) for spo in cur_spo_set]

但上述cur_spo_set得到的结果也是None。所以得到的sub_answer为 "i don't know" ,随后去运行下面这句代码:

  sub_query_with_history_qa = self._generate_sub_query_with_history_qa(history, sub_query)    # history->[], sub_query->' 查询关羽的身高'
  docs_with_score = self.chunk_retriever.recall_docs(sub_query_with_history_qa, top_k=10, **params)    # sub_query_with_history_qa->' 查询关羽的身高'

但得到的docs_with_score仍为空。所以我第一次操作的结果为:
image

很奇怪就在于neo4j图谱中明明有关羽这个节点的呀,而且文本chunk召回为什么召回不到呢?

@zzzcccxx
Copy link
Contributor Author

zzzcccxx commented Dec 20, 2024

调试了下发现虽然建图使用的默认schema,但没使用knext schema commit 进行提交。提交后就可以正常提取文本了。但又有一个问题,就是虽然文档可以正常召回,但图结构的节点还是没有返回。
image

@thundax-lyp
Copy link
Contributor

默认schema里,人物是没有身高。

Person(人物): EntityType
     properties:
        desc(描述): Text
            index: TextAndVector
        semanticType(语义类型): Text
            index: Text

改成:

Person(人物): EntityType
     properties:
        desc(描述): Text
            index: TextAndVector
        semanticType(语义类型): Text
            index: Text
        height(身高): Text
            index: Text

在 KAGExtractor.named_entity_recognition 中将调用 kg_result = self.llm.invoke({"input": passage}, self.kg_prompt),kg_result里能看到数据

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants