基于医疗知识图谱的问答系统
一、项目来源由于之前用Rasa构建过对话系统因此一直想脱离Rasa这个开源框架从底层开始构建一个可以实现相似功能的对话系统毕竟框架用的再溜都不如自己做一遍。恰巧在Rasa群里看到了王乐前辈分享的一个项目基于知识图谱的医疗诊断知识问答系统先看了一遍视频然后把代码下载下来自己实现了一遍遇到不懂得地方就再看视频现在基本把这个项目搞明白了写个总结分享一下后期会在现有的基础上做一些横向拓展。由于前辈已经有了视频讲解(项目主页有视频链接)我的总结和分享尽量避开已有的讲解内容避免重复。因此建议本文和前辈的视频配合食用~二、项目架构[1]目前实现的是最小演示版本后期前辈可能会加上Redis、Elasticsearch、tf-serving等技术栈但是于我而言现在的版本已经足够了。本文的介绍也是基于目前的这个Demo进行的后期会不断更新。这个项目已实现的功能闲聊类的单论对话基于知识图谱的多轮问答先看一下对话流程或者也叫文本解析流程是根据代码逻辑整理出来的以用户输入“请问得了心脏病怎么办呢”为例NLU模块1先进入分类模型1判断是否是闲聊类的意图包括greet、goodbye、deny、isbot、accept、 diagnosis命中前四个意图那就进入Chitchat_bot从准备好的回复语料中随机抽取一条返回给用户对话结束命中acceptaccept意图是在进行问题澄清时发挥作用命中diagnosis进入2Medical_bot本例中命中的是diagnosis进入 2Medical_bot2在Medical_bot中先进入分类模型2进行意图二次识别这里包括13个医疗类的意图然后进入NER模型进行实体识别与提取意图识别的结果是{confidence: 0.8997645974159241, intent: 治疗方法}实体识别的结果是[{entities: [{type: disease, word: 心脏病}], string: 请问得了心脏病怎么办呢}, {entities: [{recog_label: dict, type: disease, word: 心 脏病}], string: 请问得了心脏病怎么办呢}]前面这两步相当于任务型对话机器人中的NLU模块DST模块3得到意图和实体之后先用实体填充槽位这里说一下NLU和DST的联系与区别NLU和DST的关系其实非常紧密它们都在槽位填充过程中发挥了作用但是在这个过程中扮演了不同的角色NLU模块是对用户的输入进行意图的分类同时对输入中的实体进行标注下面是上面实体识别结果的节选{entities: [{type: disease, word: 心脏病}], string: 请问得了心脏病怎么办呢}在此项目中是标出实体的类型(type)对应知识图谱中的节点同时标出对应的字段(word)但是还没有填充只是把实体找出来而已。DST模块则是基于对话历史为槽位列表中的每一个槽位找到一个槽位值治疗方法:{ slot_list : [Disease], slot_values:None, cql_template : [MATCH(p:疾病) WHERE p.name{Disease} RETURN p.cure_way, MATCH(p:疾病)-[r:recommand_drug]-(q) WHERE p.name{Disease} RETURN q.name, MATCH(p:疾病)-[r:recommand_recipes]-(q) WHERE p.name{Disease} RETURN q.name], reply_template : {Disease} 疾病的治疗方式、可用的药物、推荐菜肴有\n, ask_template : 您问的是疾病 {Disease} 的治疗方法吗, intent_strategy : , deny_response:没有理解您说的意思哦~ },这是治疗方法这个意图的下的信息(form)槽位列表中只有一个槽位Disease(下文会对这个form进行详细介绍)。在每一轮对话中DST模块都会查看截止目前的所有对话历史然后确定哪个文本可以填充为槽位列表中某个特定槽位的槽位值这个过程谓之追踪(DialogueStateTracking)。在这个项目中这一步是通过遍历槽位列表和实体识别的结果进行匹配完成的。PL模块4然后根据意图置信度确定回复策略这里分了三种简单的情况0.8根据识别到的意图去Neo4j(知识图谱)中查询答案返回给用户0.4~0.8反问用户进行问题澄清0.4返回兜底话术DST模块PL模块组成了任务型对话机器人中的对话管理(DM)模块在这个项目中界限并不是特别明显主要实现逻辑都在modules.py文件的semantic_parser函数中。学术和工业界也有好多人在研究这一部分一个热门的方向是用强化学习进行策略的选择有相关的论文感兴趣的可以去看看。实现上述过程需要完成以下几步工作1构建知识图谱作为底层数据支撑这里构建知识图谱采用的数据集是liuhuanyong在QABasedOnMedicaKnowledgeGraph 项目中使用的医疗数据集。一共8种实体药品、菜谱、食物、检查、科室、药企、疾病、症状共计4万余个11种实体关系疾病忌吃食物关系疾病宜吃食物关系疾病推荐吃食物关系疾病通用药品关系疾病热门药品关系疾病检查关系科室科室关系厂商药物关系疾病症状关系疾病并发关系疾病与科室之间的关系对于没有构建过知识图谱的同学来说在有结构化数据集的情况下不要把构建知识图谱想象成一件特别复杂特别困难的事情知识图谱的难点在于数据收集阶段从非结构化数据中提取出结构化的信息比如从网页文本中找出实体(NER)并提取出实体间的关系图谱设计阶段实体定义属性定义关系定义需要一定领域背景知识才能更好的进行图谱设计而在此项目中数据集是结构化的实体属性关系也都是定义好的所以不要把这一步想的很困难。在实际业务中构建知识图谱的难易取决于你具体的业务场景不能一概而论。2分类模型1分类模型1的任务是完成多意图分类判断用户意图是否是闲聊类的这是第一次意图分类(这个项目中一共进行了两层意图分类)这里采用的是LRGBDT多模型融合的方法。3分类模型2在Medical_bot中首先进入分类模型2识别出具体的医疗诊断意图定义、病因、治疗时间、预防、治疗方法等共计13个医疗诊断意图这里采用的是BertTextCNN进行多意图分类。4NER模型在Medical_bot中第二步是通过NER模型对医疗领域的实体进行识别及提取即从用户输入中就要求提取出知识图谱中包含的实体的名称前面提到过在本项目中一共8种.但是在大型项目中实体数量数以万计而普通的匹配方式由于每次匹配失败都需要回溯其耗时较久而AC自动机的时间复杂度理想状态下为O(n)n为用户输入字符串的长度。所以一种技术路线就是使用 AC自动机提取出包含知识库中实体的所有子串(或者最长子串) NER实体识别的方式对用户输入中的实体进行提取再综合两个结果召回评分最高的Top n实体进行后续的链接操作。本项目采用的就是AC自动机提取所有子串NER实体识别的方式。三、项目运行为了方便大家实践我把自己的代码上传到GitHub了地址是KBQA-study 与原代码相比对部分代码添加了注释方便调试阅读修改了部分参数和函数的名称原作者通过itchat链接到微信通过微信来进行交互我自己的微信账号连接不了因此用sanic这个轻量级的框架做了一个网页交互界面本来还想接入到Telegram但是实在没时间了这个计划暂时搁置其实用什么交互并不是最重要的重点是算法部分的工作。我的运行环境Win1016GB内存Pycharm要运行这个项目你需要做以下几项工作第一步下载需要的数据和模型数据是必须要用的模型后期可以训练你自己的下载连接在GitHub主页上下载好后把数据放到对应的文件夹下这里除了Bert预训练文件别的都有了Bert预训练文件太大了自行在网上下载吧第二步构建知识图谱1在自己电脑上安装Neo4j参考Win10下安装Neo4j图数据库Neo4j的安装与使用教程winLinux手把手教你快速入门知识图谱 - Neo4J教程2打开一个CMD输入neo4j.bat console启动服务3在Pycharm中运行build_kg文件夹下的build_kg_utils.py构建知识图谱这个过程比较慢我自己电脑需要2个小时左右如果你的内存比较小关掉一部分非必要应用把里面涉及到的路径和账号换成你自己的第三步启动服务1启动意图识别模型服务和NER模型服务启动命令在下面两个文件中run_intent_recog_service.batrun_ner_service.bat直接双击运行这两个文件打开后不要关闭如果是Linux系统将其改成 shell 脚本后运行奈何在我的电脑上双击后总是闪退如果你也遇到类似的情况可以试试以下方法Pycharm 中打开2个Terminal分别运行run_intent_recog_service.bat和run_ner_service.bat中的两条命令一般是报错了才会闪退可以用这种方法查看报错信息进行修改2启动知识图谱服务如果你构建好知识图谱后没有关闭服务这一步可以跳过要是关闭了就重新启动打开一个CMD输入neo4j.bat console启动服务3启动主程序我自己新建了一个local.py的文件在里面写了sanic的服务代码你可以先尝试使用微信版本Pycharm 中打开1个Terminal输入python itchat_app.py如果登陆不了可以试试输入python local.py然后浏览器打开http://你的IP:12348/swagger/#/default 就可以用我的这种方式和机器人进行交互了。四、项目总结就项目当前实现的程度而言主要涉及到以下知识点1知识图谱的构建从结构化数据集中提取所有的实体和关系然后构建三元组使用Neo4j 创建节点(node)和关系(edge)这一步需要你熟悉neo4j的一些常用语句2文本分类文本分类在本项目中主要体现在两次意图识别上第一次意图识别判断用户意图是否是闲聊类采用的是LRGBDT多模型融合的方法第二次意图识别识别出具体的医疗诊断意图采用的是BertTextCNN如果是抱着学习的态度就不能止步于项目中的内容毕竟文本分类既是NLP入门任务又是一大分支可以结合这个项目做些横向的拓展基于本项目的数据集试试其它的模型看看效果如何也可以试试其它数据集总之把文本分类这个任务掌握的牢固一点。3序列标注命名实体识别本项目的命名实体识别部分采用的是BiLSTMCRF模型后面还用了AC自动机做了补充修正。槽位填充槽位填充一般出现在任务型机器人中用来从用户那里收集信息先看意图中有什么槽位然后去用户输入中做实体识别以抽取该槽位的槽值槽位填充本质属于一个序列标注任务。之前看各种有关资料都是讲理论从来不说具体是怎么填充的通过这个项目算是基本明白了重点在config.py文件和modules.py文件的semantic_parser()函数里由于之前用过Rasa立刻就联想到Rasa中的domain文件 整个domain文件其实就是一个大字典存着各种槽位和意图信息。看一下这个项目是怎么实现多轮问答的以下内容节选自config.py文件semantic_slot { 定义:{ slot_list:[Disease], slot_values:None, cql_template: MATCH(p:疾病) WHERE p.name{Disease} RETURN p.desc, reply_template: {Disease}是这样的\n, ask_template: 您问的是 {Disease} 的定义吗, intent_strategy: , deny_response: 很抱歉没有理解你的意思呢~ }, 病因:{ slot_list : [Disease], slot_values:None, cql_template : MATCH(p:疾病) WHERE p.name{Disease} RETURN p.cause, reply_template : {Disease} 疾病的原因是\n, ask_template : 您问的是疾病 {Disease} 的原因吗, intent_strategy : , deny_response:您说的我有点不明白您可以换个问法问我哦~ }, 预防:{ slot_list : [Disease], slot_values:None, cql_template : MATCH(p:疾病) WHERE p.name{Disease} RETURN p.prevent, reply_template : 关于 {Disease} 疾病您可以这样预防\n, ask_template : 请问您问的是疾病 {Disease} 的预防措施吗, intent_strategy : , deny_response:额~似乎有点不理解你说的是啥呢~ }, }这里面的定义、病因、预防分别代表三个不同的医疗诊断意图每个意图后面跟着一个字典字典的key-value存着和意图相关的一些信息以定义这个意图为例槽位列表slot_list:[Disease]槽值被填充之后value是一个字典存着槽位列表中出现的槽位-槽位值slot_values:None图谱查询语句cql_template: MATCH(p:疾病) WHERE p.name{Disease} RETURN p.desc,回复模板reply_template: {Disease}是这样的\n,澄清话术意图置信度在0.4-.8之间是会用此模板进行问题澄清ask_template: 您问的是 {Disease} 的定义吗,回复策略intent_strategy: ,意图识别失败回复话术deny_response: 很抱歉没有理解你的意思呢~注意这里每一个意图下都有Disease这个槽位只要在最开始的时候将该槽位填充后后面就可以不断的就填充的槽值进行多轮对话因为槽位填充的逻辑里面有一个是获取上一步的槽值。4模型发布分类模型2和NER模型都是以接口的形式提供服务的通过这个又可以对模型发布有所了解。这个项目对于我最重要的是槽位填充那个环节结合之前使用Rasa的经历对于如何实现任务型对话机型人有了更深刻的理解同时也再次暗叹Rasa这个框架的厉害。本项目可扩展的地方在算法层面NLP领域的四大任务本项目已经涉及到两个序列标注和文本分类目前是采用知识图谱作为底层的数据库对答案进行存储可以考虑把文本生成的内容加进去在适当的时候直接用NLG模型生成答案返给用户至于在什么时候调用NLG模型完全看自己发挥了。然后是句子匹配也叫句子关系判断关键是找一个合适的场景以及数据集然后集成进去具体方法可以参考这篇21个经典深度学习句间关系模型代码技巧这样一来一个问答项目就涵盖了知识图谱NLP四大任务对于学习NLP的同学来说应该是一个挺不错的项目了比市面上某些培训班的项目还要丰富。暂时写到这里希望能帮助到有需要的人如果文中有什么错误欢迎指出来~谢谢~参考^https://arxiv.org/abs/2105.04387基于医疗知识图谱的问答系统 - 知乎GitHub - DeqianBai/KBQA-study: 基于医疗知识图谱的问答系统GitHub - z814081807/DeepNER: 天池中药说明书实体识别挑战冠军方案中文命名实体识别NER; BERT-CRF BERT-SPAN BERT-MRCPytorch【分享吧】Ahocorasick算法实现敏感词过滤

相关新闻

自指实在论的Coq形式化本体论构建与机器可验证性实施方案

自指实在论的Coq形式化本体论构建与机器可验证性实施方案

自指实在论的Coq形式化本体论构建与机器可验证性实施方案 作者:方见华 单位:世毫九实验室 摘要 本方案将自指实在论(核心公理:实在是全域自指映射的动态不动点\mathcal{U}\mathcal{F}(\mathcal{U}))的哲学本体论&#…

2026/10/2 13:48:57 阅读更多 →
世毫九实验室自指宇宙学中拓扑不变量Φ的导出及其CMB相位锁定振荡效应研究报告

世毫九实验室自指宇宙学中拓扑不变量Φ的导出及其CMB相位锁定振荡效应研究报告

世毫九实验室自指宇宙学中拓扑不变量Φ的导出及其CMB相位锁定振荡效应研究报告 作者:方见华 单位:世毫九实验室 摘要 本报告基于世毫九实验室公开的自指宇宙学(Self-Referential Cosmology, SRC)原创理论体系,系统拆解…

2026/9/29 0:14:11 阅读更多 →
VB、C#等PC高级语言PLC通讯组件例程的下载地址收集整理

VB、C#等PC高级语言PLC通讯组件例程的下载地址收集整理

PLC通讯组件是通过PC高级语言在Windows系统下编程,实现电脑、工控机等设备与PLC通讯数据交互的功能,以下是收集整理的下载地址: 1.西门子(SIEMENS)PLC: S7-300/S7-400 S7-1200/S7-1500 S7-1200/S7-1500标签方式通讯 S7-200 Smart S7-200 CP…

2026/10/8 22:35:19 阅读更多 →

最新新闻

COMSOL仿真极化无关BIC超表面:特征模式、Q值追踪与多极子分解全解析

COMSOL仿真极化无关BIC超表面:特征模式、Q值追踪与多极子分解全解析

超表面里的连续束缚态(Bound States in the Continuum,BIC)这两年是真的火,尤其在光子晶体超表面方向,高Q值、超窄线宽这些特性,直接把传感、激光、非线性谐波转换一系列应用的性能天花板抬了一大截。我前阵…

2026/10/13 19:16:34 阅读更多 →
配电网韧性提升:移动储能预布局与动态调度策略解析

配电网韧性提升:移动储能预布局与动态调度策略解析

配电网韧性、移动储能、预布局、动态调度,这几个词放在一起,基本就是当前配电系统防灾减灾领域最热的方向之一。我之前在好几个项目里都碰到过类似的课题,这次完整跑通并复现了IEEE33节点下的移动储能预布局与动态调度策略,整个过…

2026/10/13 19:16:34 阅读更多 →
STM32 GPS导航实战:从NMEA解析到地图绘制完整指南

STM32 GPS导航实战:从NMEA解析到地图绘制完整指南

简介:基于STM32与UC/GUI的GPS导航完整工程包,面向嵌入式开发者、电子竞赛参赛者及GUI入门学习者,定位在资源受限MCU上实现GPS定位信息采集与图形化交互界面的场景。压缩包约20.23MB,共548个文件,其中h头文件124个、c源…

2026/10/13 19:16:34 阅读更多 →
用Playwright MCP让AI真正操作浏览器:配置与实战

用Playwright MCP让AI真正操作浏览器:配置与实战

很多同学应该都遇到过这样一种场景:让 AI 写代码,它几分钟就能交付一个像模像样的脚本;但要是让它“去浏览器里把某个网页的信息提取出来再填个表单”,它立马就懵了。原因很简单,大多数 AI 应用没有“手”,…

2026/10/13 19:16:34 阅读更多 →
知识工作插件集合实战:从捕获到输出的完整工作流搭建指南

知识工作插件集合实战:从捕获到输出的完整工作流搭建指南

1. 这个插件仓库到底解决了什么问题第一次看到knowledge-work-plugins这个标题,我脑子里蹦出来的第一个念头是:又是一个“大而全”的知识管理插件集合?市面上这类东西太多了,Obsidian 插件市场一搜一大把,Notion 模板站…

2026/10/13 19:16:34 阅读更多 →
矩阵论期末复习:Jordan标准形、QR分解与广义逆手算全攻略

矩阵论期末复习:Jordan标准形、QR分解与广义逆手算全攻略

简介:矩阵论期末考试参考答案是一份针对矩阵论课程期末考试的完整解题资料,面向正在复习矩阵论、线性代数的本科生及考研备考生,也适用于需要快速回顾核心计算方法的工程类学生。资源包内共1个PDF文件,大小约284KB,文件…

2026/10/13 19:15:31 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →