资讯动态

知识图谱驱动的《三国演义》问答系统设计与实现

发布时间:2026/10/21 11:03:25 来源:尧图企业网站定制
1. 项目全貌与毕设选题思路如果你正在为毕业设计选题发愁又恰好对知识图谱、问答系统、自然语言处理这些方向感兴趣那基于知识图谱的《三国演义》知识问答系统是一个非常值得做的题目。它既有文学文本的数据背景又有图谱构建、语义解析、深度学习排序这些硬核技术点做出来的东西还能直接演示、直接答辩老师一眼就能看懂你在干什么比纯做算法调参要好呈现得多。这个项目的核心是把《三国演义》原著中的实体人物、地点、事件、官职、势力和它们之间的关系父子、君臣、同盟、交战、谋略抽出来组织成一张结构化的图然后让用户用自然语言提问系统返回准确答案。比如问“诸葛亮的师父是谁”“赤壁之战发生在哪一年”“刘备和曹操是什么关系”系统都能基于图谱中的三元组回答。它适合谁做我身边不少同学是从三个方向上手的一是做传统Web开发的想往AI方向靠一靠二是学算法出身但不想只跑公开数据集想找一个有数据工程、有业务背景的题目三是真的喜欢三国想把兴趣变成毕业设计。无论哪一种这个项目都能满足。而且它天然是一个“大数据深度学习前端展示”三位一体的综合系统论文里不缺创新点答辩时不缺素材。对于毕设来说这个选题最大的优势是数据可控、规模适中。《三国演义》一共一百二十回人物上千关系复杂但不像通用互联网数据那样海量且嘈杂。你可以把整个EPUB或TXT原文作为原始语料再结合百科的半结构化数据做扩充既不用愁数据量太大跑不动也不用担心数据太少没法体现效果。整体难度处于“努力跳一跳能够得着”的水平。2. 知识图谱构建从原著文本到结构化三元组2.1 实体识别与关系抽取的工程化方案知识图谱构建是整个系统的地基。地基没打好后面问答再花哨也是空中楼阁。第一步是定义本体Schema。我先用纸笔列出了《三国演义》里最常见的六类实体人物、地点、事件、时间、官职、势力。比如“诸葛亮”是人物“赤壁之战”是事件“荆州”是地点。然后定义关系类型我实际用的关系有二十多种但真正高频、有效的大概是这些关系类型例子父子/母子刘备与刘禅孙坚与孙策兄弟孙策与孙权曹丕与曹植君臣刘备与诸葛亮隶属势力关羽属于蜀汉参与事件诸葛亮参与赤壁之战交战对手曹操与刘备交战担任官职诸葛亮的丞相出生地 / 活动地诸葛亮居于南阳时间事件发生时间赤壁之战发生于建安十三年谋士/盟友/敌人诸葛亮与司马懿互为对手关系定义太多会导致抽取困难太少又支撑不起问答。如果只做一个人物关系问答系统我建议优先做“人物-人物”关系和“人物-事件-时间”关系这两类是用户最常问的。抽取阶段最忌讳一上来就上深度学习因为标注数据不够。我自己是分三步走的第一步用正则和词典做第一轮粗抽。比如把“XX之妻”“XX弟”“XX对XX说”这类句式收集起来写正则模板直接套。第二步用百科半结构化数据做补充。很多公开的百科页面有现成的“人物关系”表格可以直接爬下来转成三元组。第三步用基于BERT微调的序列标注模型做兜底专门识别前面规则漏掉的实体和对齐关系。这里有一个非常容易被低估的点实体对齐。诸葛亮、孔明、卧龙、诸葛孔明这四个词在原著中指的是同一个人但在图谱中如果不做合并问“孔明的师父是谁”和“诸葛亮的师父是谁”就会得到两套答案。我的做法是建一个“别名表”每个实体选一个规范名其他别名统一映射过去。这个表不需要模型手工整理常见别名就够了。百科重定向可以帮忙但人工核对一遍最稳。2.2 图谱存储与可视化选型存储层我选的是Neo4j没有之一。原因很简单图数据库的Cypher查询语言对“找关系路径”这类操作几乎是零成本。比如用户问“刘备和曹操之间是什么关系”底层需要找到一条路径这在Neo4j里就是一条MATCH p(a)-[*1..3]-(b) RETURN p查询快、写起来也不复杂。如果用MySQL存三元组表要自己写递归查询效率低不说代码还难看。可视化方面Neo4j自带的Browser可以用于调试但做成毕设演示我建议用ECharts。我做的系统里前端展示的是固定范围的子图比如输入“诸葛亮”就展示与他直接相邻的所有实体和关系用ECharts的关系图graph类型渲染成节点和边。这样用户一眼就能看到自己问的问题在图谱中的位置所谓“知识图谱”的演示效果就出来了。数据导入这块有个小经验不要一行一行在Neo4j里创建节点效率太低。把三元组整理成CSV文件用Neo4j自带LOAD CSV或者Python的py2neo库批量导入。我最终导入了大约1200个实体、3200条关系。这个规模在Neo4j里就是小意思查询毫秒级返回。3. 问答系统核心从问题解析到答案检索3.1 问题分类与意图识别策略问答系统的难点不在答案检索而在把用户的自然语言问题解析成机器能理解的查询意图。中文口语用户会问“诸葛亮住在哪”也会问“卧龙先生隐居地”还可能会问“孔明在哪出山”句子表述差异极大要统一到同一个意图上。我的做法是把问题解析拆成两个子任务。第一个子任务是命名实体识别。从问句里抽取出目标实体。因为问句长度短、领域固定用词典匹配其实就够了不需要加载一个很大的BERT模型。我把人名表、地名表、势力表、事件表、官职表全部加载进来先用最长的词典条目优先匹配比如“赤壁之战”优先于“赤壁”免得拆错。再结合一个简单的CRF模型兜底处理那些词典外的新词。实测准确率已经能到九成以上。第二个子任务是问题类型判别。我把问题归为六大类人物关系、事件时间、事件参与人、人物其他信息字、号、籍贯、官职、地理位置、数量/统计。这里我用了BERT分类模型因为问题类型不像实体那样容易靠词典枚举句子的语义特征更明显。我收集并标注了大约5000条问题样本涵盖模板变化用小规模的bert-base-chinese微调了一个多分类模型。分类准确率在测试集上做到96%左右完全够用。这里有个容易被忽略的坑同义改写。比如“谁杀了关羽”“关羽被谁害死”“关羽的死因是什么”如果只做分类和实体识别这三种问法的处理路径完全不同。我的经验是在问题进入分类前先做一层归一化。把“被谁”“谁杀了”统一成“凶手”“死于”“死因”统一成“死亡事件”这样图谱查询模板就不用写太多。我建了一个“问题改写规则库”里面写了几十条正则表达式效果立竿见影。3.2 模板匹配与Cypher查询生成分类完成之后核心工作是把意图转换成Cypher查询语句。以“人物关系”类问题为例用户问“刘备和曹操是什么关系”系统抽取到实体“刘备”和“曹操”问题类型是“关系”。那我只需要生成一条CypherMATCH (a:人物 {name:刘备}), (b:人物 {name:曹操}) MATCH p (a)-[r]-(b) RETURN type(r) AS relation, properties(r) AS props如果存在直接关系直接把关系名返回。如果直接关系不存在就做多跳查询最多跳到三层把中间路径展示给用户比如“刘备—盟友—孙权—敌对—曹操”两个人物之间的关系就有了中间人这样的回答更丰富也更容易解释给答辩评委听。再举一个“事件时间”类问题“赤壁之战发生在哪一年”抽取到“赤壁之战”事件然后查它的time属性MATCH (e:事件 {name:赤壁之战}) RETURN e.time“谁参加了赤壁之战”则查事件和人物之间的参与关系。为了避免每次根据不同的问法写几十个if分支我构建了一个“模板映射表”。第3.1节归一化后的问题会落到预设模板中例如“谁动词实体”对应“事件参与人查询模板”“实体什么时候动词”对应“事件时间查询模板”。每个模板都带有一个Cypher生成器函数用最简单的方式完成“问题意图到图查询”的转换。这种基于规则的方式虽然看起来笨却是最稳定、最容易在论文里解释清楚的做法。4. 深度学习算法在问答系统中的应用4.1 基于向量检索的候选答案召回如果只用模板匹配系统只能回答预先设计好的那几类问题遇到开放式的、模板覆盖不到的问法就会哑火。为了让系统有“智能感”我把深度学习用在了答案召回和重排序两个环节。召回阶段用的是稠密向量检索。我先把知识图谱中的所有三元组编码成文本描述比如(刘备, 君臣, 诸葛亮)变成“刘备的臣子是诸葛亮”(诸葛亮, 参与, 赤壁之战)变成“诸葛亮参与了赤壁之战”然后统一用Sentence-BERT模型编码成向量存到向量数据库里。用户提问时同样把问题编码成向量通过余弦相似度召回Top-20相关的三元组描述。这个阶段不需要严谨的逻辑只需要把可能的答案范围扩大宁多勿缺。向量模型我用了中文预训练模型比如shibing624/text2vec-base-chinese这个模型轻量、效果稳定在普通CPU上也能跑不需要租GPU。如果毕设条件好一点可以换用更大规模的模型但实测下来对最终准确率的提升非常有限。原因是知识图谱里的三元组描述本身是模板化生成的结构相对简单小模型的语义表达能力已经足够。这里需要提一个重要细节召回和模板匹配不是两个独立系统而是并联关系。我在后端做了一个策略调度器优先尝试模板匹配如果模板匹配的置信度低比如问题分类器输出的置信度低于0.7就转入向量检索召回。这样既保证了高频问题的准确率又保留了长尾问题的一定覆盖率。4.2 基于预训练模型的答案重排序召回出来的Top-20候选答案中通常有一大半是噪声。这时需要做重排序把最可能回答用户问题的候选排到最前面。我的重排序方案是构建一个二分类模型输入“用户问题”和“候选答案描述”模型输出一个0到1的匹配分数。这个模型还是基于BERT做微调训练数据是人工构造的“问题-答案对”。正样本是从图谱中抽取的、真正能回答问题的三元组描述负样本则是随机挑选的、不相关的三元组描述。训练数据我生成了两万对比例大约1:2正样本少一点负样本多一点这是为了让模型学会区分“确实相关”和“看似相关但不对”。微调用的是transformers库的AutoModelForSequenceClassification标签就是0和1训练时间在两小时内能完成数据量小模型也收敛得很快。推理时把用户问题和20个候选描述分别拼接成[CLS]问题[SEP]候选[SEP]送入模型获取score然后排序取Top-1返回给用户同时把Top-3的候选作为“相关推荐”展示在界面上。做这一步的最直接好处是系统能处理类似“曹魏阵营中哪位将领最常与蜀汉交战”这种没有办法直接用模板匹配到的问题。虽然召回阶段可能返回一堆交战记录但重排序会根据问题语义把最相关的几条排到最上方再通过一个简单的聚合逻辑输出“赵云”“关羽”这样的答案。这正是“知识图谱深度学习”结合的创新所在论文的创新点之一就可以写这个。5. 毕设论文架构与代码工程实现要点5.1 论文目录与创新点写作思路很多同学拿到这种题目不知道论文怎么写。我当年的论文结构可以作为参考大致是这样的第一章绪论。写研究背景与意义比如传统浏览器搜索返回网页列表用户需要自己归纳而知识图谱问答系统能直接返回结构化答案。再写国内外研究现状提一下通用领域知识图谱如GeoNames、Freebase和开放域问答系统如IBM Watson的进展然后引出要做的事。第二章相关技术。这部分不要写成名词解释手册而要重点写“为什么选它”。比如Neo4j相比MySQL的优势、BERT的Attention机制如何适用于短文本匹配、Sentence-BERT在召回场景下如何解决向量相似度计算效率问题。老师最反感的就是大段抄教材定义要写成有自己理解的技术选型对比。第三章系统需求分析与总体设计。画功能模块图、用例图、系统架构图。注意架构图不要用Mermaid而是用绘图工具画好插图。模块划分要清晰数据层、图谱构建层、问答解析层、答案检索层、前端展示层。第四章知识图谱的构建。写实体定义、关系定义、抽取管道、数据清洗、实体对齐、Neo4j导入过程。附上几个可视化截图展示图谱规模。第五章问答系统的设计与实现。写问题分类、意图识别、模板映射、Cypher生成、向量召回、重排序。这是论文最核心的章节每个模块都要配上流程图用visio画和代码片段。第六章实验结果与分析。这一章在毕设中很关键很多人只写“系统能回答问题”就没了显得特别单薄。建议做三组实验第一组测试不同问题类型的正确率用标注好的500个问题评测给出精确率、召回率、F1值第二组消融实验比如“没有向量召回只有模板匹配”和“模板匹配向量召回重排序”的对比体现深度学习的贡献第三组对比实验可以换成开源的通用问答模型如基于检索式或基于生成式的Baseline展示你的系统在领域答案正确率上的优势。第七章总结与展望。写遇到的困难、解决过程、未来可以扩展的方向比如加入多轮对话、扩展到其他典籍。这里说一个答辩技巧一定要准备一个“创新点”总结哪怕只有一句话。我总结的三个创新点是针对文学作品设计了领域专用的本体结构和关系体系将模板匹配与深度学习向量检索结合兼顾准确率和覆盖率构建了中文古典文学作品的知识图谱问答流程有可迁移性。实际答辩时老师问得最多的就是“你这个系统和现有通用问答系统有什么不同”用这句话挡回去就对了。5.2 代码工程结构与环境配置代码仓库必须结构清晰答辩评阅老师可能会打开你的GitHub或压缩包看一遍。我建议按以下目录组织sanguo-qa/ ├── frontend/ # 前端工程Vue 3 ECharts ├── backend/ # 后端服务FastAPI │ ├── app/ │ │ ├── api/ # REST接口 │ │ ├── graph/ # 图谱查询逻辑 │ │ ├── nlu/ # 问题分类与命名实体识别 │ │ ├── retriever/ # 向量召回 │ │ └── reranker/ # 重排序模型 ├── data/ # 原始文本、标注数据、三元组CSV ├── notebooks/ # 数据清洗与模型训练脚本 ├── model/ # 训练好的模型权重 ├── docs/ # 论文、开题报告、答辩PPT └── requirements.txt后端我用FastAPI而不是Flask原因很简单自带OpenAPI文档前端联调时可以随时在浏览器里测试接口。前端只需要两页一个聊天窗口、一个图谱可视化页面不必做得太花哨。环境配置的坑要提前踩Neo4j的版本要和你用的py2neo版本匹配。我当初踩过一个坑Neo4j 5.x和py2neo 4.x不兼容连接一直报认证错误折腾了一晚上。后来换成neo4j官方Python驱动或者直接用Neo4j的HTTP接口就稳定多了。如果答辩现场担心网络问题建议把所有依赖打包成Docker镜像在答辩电脑上一键启动。这个细节很加分有一次答辩就是因为系统能离线演示被评委多夸了两句。6. 常见问题与排坑实录6.1 关系抽取准确率低、数据稀疏怎么办这是大家做知识图谱毕设时遇到最多的两个问题。关系抽取准确率低通常是因为规则模板写得太粗糙。比如“刘备对诸葛亮说”这种句子容易被规则误判成“下属关系”。我的经验是先统计高频关系模式用依存句法分析辅助比如拿到一句话的主谓宾再判断主语和宾语之间的语义角色。不要指望一个规则解决所有情况。更现实的方案是“人工抽检批量修正”随机抽200组三元组人工标出错误率如果超过15%就反向回查对应的规则把误报来源修掉。数据稀疏则集中在某些关系上。比如“贿赂”“联姻”这类关系在全书中出现次数很少三元组数量不够问答时很容易答不上来。我的应对是给每个关系类型设置了最低数量阈值低于5条的关系直接合并到“其他关系”类别中。用户询问时如果命中稀疏关系系统不会返回空而是返回相关实体的“概述”信息把图谱中没有直接答案的情况也给予友好提示。另外实体歧义问题也值得注意。《三国演义》中“荆州”既指州郡也可以指代城池同名人物可能出现演义和历史的混淆。我的处理是在导入图谱时给实体加domain属性标注其所属类别查询时优先匹配和问句上下文一致的类别。比如用户问“谁占据荆州”优先匹配地名而不是人物。6.2 系统演示与答辩环节的实战建议毕设答辩时系统的实际表现比任何理论讲解都重要。如果你现场演示时问了一个常见问题系统却返回错误或空白那印象分会打折扣。我建议你建立一个“演示用测试集”大概三十个问题覆盖六大类问法每个问题都提前测过确保万无一失。不要即兴输入免得遇到文本编码错误之类的意外。如果答辩时被问到“你这里用了深度学习和直接用规则有什么区别”不要回避直接说出实验中对比数据。我的实验中规则模板的准确率是82.7%加入向量召回和重排序后准确率提升到了91.3%覆盖率提升了18个百分点。这组数字是我花了整整一个星期测试出来的也是论文第六章最扎实的数据支撑。最后关于时间规划如果从现在开始做建议第一周完成数据准备和本体设计第二周到第四周做实体关系抽取和入库第五周到第七周做问答模块第八到第十周完成前端展示和模型微调最后三周写论文和调试。千万不要把代码放到最后一个月因为问答系统的联调需要大量时间。我见过太多同学前期慢悠悠后期通宵赶论文质量堪忧。我自己做完这个项目的体会是最难的不是算法而是把数据工程和算法模型串成一条线。你要是能把这条线走通无论毕业设计还是未来的简历都会多一份扎实的底气。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑