ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于知识图谱的医疗问答系统:Django+MySQL+NLP实现智能导诊

基于知识图谱的医疗问答系统:Django+MySQL+NLP实现智能导诊 简介本资源是一套完整的基于知识图谱的医疗问答系统毕业设计源码面向计算机、软件工程及医学信息工程等专业的本科生与课程设计学习者解决传统医疗咨询响应慢、专业性弱、知识关联浅等问题。系统采用Django构建前后端MySQL 5.7存储用户账号等结构化数据Neo4j图形数据库承载疾病、症状、药品、科室等实体及其语义关系实现精准语义检索与推理问答。压缩包共1207个文件含33个核心Python后端模块、225个JS交互脚本、176个PNG界面资源、101个CSS样式文件、41个HTML模板页以及Neo4j原生存储文件如neostore.*、counts.db、propertystore.db.arrays等完整复现知识图谱导入、图查询接口、用户认证与问答前端流程包体大小为186.79MB。已有108人下载学习配套说明文档详述环境配置Python 3.6.8 PyCharm Navicat11、数据库初始化、Neo4j图谱加载步骤及LW论文框架可直接用于毕设答辩与二次开发。1. 项目概述一个能“听懂”医学问题的智能助手最近几年无论是毕业设计还是实际项目开发基于知识图谱的智能问答系统都是一个非常热门的方向。特别是结合医疗这个垂直领域它既有明确的应用价值又有足够的技术深度来支撑一个完整的毕业设计。我手头这个项目就是一个典型的、可以直接拿来参考甚至复现的“基于知识图谱的医疗问答系统”它用 Python 的 Django 框架搭建了完整的前后端后端用 MySQL 存储结构化数据并整合了知识图谱的核心思想来实现问答逻辑。简单来说这个系统就像一个初步具备医学知识的“智能导诊员”。用户不用去记忆复杂的医学名词分类或者科室划分他可以直接用自然语言提问比如“我最近老是头晕、乏力可能是什么原因”或者“糖尿病的早期症状有哪些”。系统会尝试理解这个问题然后从它背后的“知识库”——也就是我们构建的医疗知识图谱——中找到最相关、最准确的答案片段并以清晰、结构化的方式呈现给用户。这背后涉及的核心技术就是如何把散乱的医疗知识疾病、症状、药品、检查等组织成一张相互关联的“网”知识图谱以及如何让计算机理解用户模糊的自然语言问题并在这张网上进行精准的“导航”和“检索”。这个项目非常适合计算机、软件工程、人工智能相关专业的同学作为毕业设计选题。它技术栈完整PythonDjangoMySQL前端涵盖了 Web 开发、数据库设计、自然语言处理NLP基础应用等多个知识点而且最终的成果是一个有界面、能交互的完整系统答辩时演示效果会非常好。对于有经验的开发者来说这个项目的架构和实现思路也为构建其他垂直领域的问答系统如法律、金融、教育提供了很好的模板。2. 核心架构与设计思路拆解要理解这个系统是怎么工作的我们不能只看代码得先理清它的“大脑”是如何思考的。一个基于知识图谱的问答系统其核心设计思路可以概括为“知识结构化”和“问题理解与匹配”两大阶段。2.1 为什么选择“知识图谱关系型数据库”的混合模式纯粹的知识图谱引擎如 Neo4j擅长处理复杂的、网状的关系查询但对于一个毕业设计或中小型项目来说引入 Neo4j 会增加环境部署、数据迁移和学习成本。而这个项目采用了一种非常务实且高效的方案用 MySQL 关系型数据库来“模拟”和存储知识图谱的三元组结构。什么是三元组它就是知识图谱的基本单位通常表示为实体1关系实体2。例如糖尿病常见症状多饮、阿司匹林用于治疗头痛。在 MySQL 中我们可以设计这样几张核心表实体表 (entity)存储所有实体如疾病、症状、药品、检查项目等。表字段可能包括实体ID、实体名称、实体类型用于区分是疾病还是症状、描述等。关系表 (relation)存储所有定义好的关系类型如“症状”、“病因”、“治疗方法”、“禁忌”等。表字段包括关系ID、关系名称。三元组表 (triple)这是最核心的表用于记录具体的知识。表字段包括三元组ID、头实体ID对应 entity 表、关系ID对应 relation 表、尾实体ID对应 entity 表。通过外键关联我们就用关系数据库的表结构清晰地记录下了“糖尿病-常见症状-多饮”这条知识。注意这种设计的好处是结构清晰、查询灵活通过 SQL 的 JOIN 操作可以实现多跳查询并且与 Django 的 ORM对象关系映射模型结合得天衣无缝开发效率很高。它本质上构建了一个“属性图”。对于医疗领域初期相对规范的关系疾病-症状药品-适应症来说完全够用。2.2 系统核心工作流程解析当用户在前端页面输入一个问题后后端 Django 应用会按以下流程处理问题接收与预处理Django 的视图View接收到前端 Ajax 提交的问题文本。关键信息抽取NLP 核心这是问答系统的“理解”环节。系统需要对用户问题进行分词、词性标注和命名实体识别NER。例如对于问题“糖尿病应该吃什么药”需要识别出“糖尿病”是疾病实体“药”是目标实体类型。在毕业设计层面这里通常不会用复杂的深度学习模型而是采用基于词典和规则的方法。我们预先构建一个医疗实体词典从医学百科、公开数据集中抽取然后通过字符串匹配或简单的算法如 AC 自动机来快速识别问题中的疾病、症状等关键词。意图识别与查询构建识别出实体后还需要判断用户的意图。是问症状问病因还是问药品这可以通过分析问题中的关键词“有什么症状”、“是什么原因”、“怎么治疗”、“吃什么药”结合规则来判断。例如问题中有“症状”意图就是“查询疾病症状”。然后系统根据识别出的实体和意图动态拼接出对应的 SQL 查询语句。比如意图是“查询疾病症状”实体是“糖尿病”那么生成的 SQL 就是去triple表中查找头实体“糖尿病” 且 关系“常见症状”的所有尾实体。知识检索与答案生成执行构建好的 SQL 查询从 MySQL 中检索出相关的实体即答案。例如查出“多饮、多尿、体重下降”等。然后将这些零散的答案片段组织成一句或一段通顺的自然语言回复。例如“糖尿病的常见症状包括多饮、多尿、体重下降等。”结果返回与前端展示Django 将组织好的答案以 JSON 格式返回给前端前端 JavaScript 再将其渲染到页面的答案区域。整个流程就是一个将“非结构化自然语言问题”转化为“结构化数据库查询”再将“结构化查询结果”转化为“自然语言答案”的过程。3. 关键技术细节与实现要点理解了宏观流程我们深入到几个关键的技术实现细节这些地方往往是决定项目成败和深度的关键。3.1 医疗知识图谱的数据构建与处理一个问答系统知识库的质量决定了它的天花板。对于毕业设计我们通常无法获得高质量的标注数据因此需要采用“半自动化构建人工校验”的方式。数据来源公开结构化数据如“疾病百科”类网站的数据通常包含疾病名称、别名、症状、病因、治疗方法等字段相对规整易于解析入库。非结构化文本爬取从权威医学网站如 Mayo Clinic、国内正规医学平台爬取疾病介绍文章。但这部分数据是纯文本需要进一步的信息抽取。现有知识库可以尝试使用像“CN-DBpedia”、“Zhishi.me”等开放的中文通用知识图谱中与医疗相关的子集但需要清洗和领域化。信息抽取与知识融合 对于从非结构化文本中抽取知识在毕业设计场景下可以采用基于依存句法分析的规则方法。例如从句子“糖尿病的主要症状是多饮和多尿”中我们可以分析出“糖尿病”是主语“症状”是谓语“多饮和多尿”是宾语。通过预设的规则模板如“疾病的[主要|常见]症状是症状列表”就可以抽取出糖尿病症状多饮和糖尿病症状多尿两个三元组。 抽取出知识后会遇到“一词多义”和“多词一义”问题如“高血压”和“高血压病”指同一疾病。这里需要建立一个同义词表在存入数据库前进行实体链接将表述不同的同一实体归一化到标准实体名上。3.2 基于规则与词典的简易 NLP 模块实现如前所述复杂的深度学习 NER 模型部署成本高。在 Django 项目中我们可以实现一个轻量级的nlp_processor.py模块。# nlp_processor.py 示例 import jieba import jieba.posseg as pseg import re class MedicalNLP: def __init__(self): # 加载自定义医疗词典 jieba.load_userdict(data/medical_entities.dict) self.disease_dict self.load_dict(data/disease.txt) # 疾病词典 self.symptom_dict self.load_dict(data/symptom.txt) # 症状词典 self.drug_dict self.load_dict(data/drug.txt) # 药品词典 # 意图关键词映射 self.intent_keywords { symptom: [症状, 表现, 征兆, 有什么感觉], cause: [原因, 病因, 为什么, 怎么会], treatment: [治疗, 怎么治, 怎么办, 疗法], drug: [药, 药品, 吃什么药, 用药], prevention: [预防, 怎么防止, 避免] } def load_dict(self, filepath): with open(filepath, r, encodingutf-8) as f: return set([line.strip() for line in f]) def extract_entities(self, question): 抽取问题中的医疗实体 words pseg.cut(question) entities {disease: [], symptom: [], drug: []} for word, flag in words: if word in self.disease_dict: entities[disease].append(word) elif word in self.symptom_dict: entities[symptom].append(word) elif word in self.drug_dict: entities[drug].append(word) return entities def recognize_intent(self, question): 识别用户意图 for intent, keywords in self.intent_keywords.items(): for kw in keywords: if kw in question: return intent return other # 默认意图 def parse_question(self, question): 解析问题返回实体和意图 entities self.extract_entities(question) intent self.recognize_intent(question) return { entities: entities, intent: intent, original_question: question }这个类提供了最基础的功能利用 Jieba 加载医疗词典进行分词和实体识别通过关键词匹配判断意图。在实际使用时需要在medical_entities.dict和各个.txt文件中预先整理好医疗实体词库。3.3 Django 模型层与问答逻辑的核心设计Django 的模型Model是与数据库交互的桥梁。以下是核心数据模型的一种设计方式# models.py from django.db import models class Entity(models.Model): 实体表如疾病、症状、药品等 ENTITY_TYPES ( (disease, 疾病), (symptom, 症状), (drug, 药品), (check, 检查), (department, 科室), ) name models.CharField(max_length100, uniqueTrue, verbose_name实体名称) entity_type models.CharField(max_length20, choicesENTITY_TYPES, verbose_name实体类型) desc models.TextField(blankTrue, verbose_name描述) # 可以添加更多字段如别名、图片链接等 def __str__(self): return self.name class Relation(models.Model): 关系类型表 name models.CharField(max_length50, uniqueTrue, verbose_name关系名称) desc models.CharField(max_length200, blankTrue, verbose_name关系描述) # 例如has_symptom有症状, common_drug常用药, belongs_to属于科室 def __str__(self): return self.name class Triple(models.Model): 三元组表存储具体知识 head models.ForeignKey(Entity, on_deletemodels.CASCADE, related_nameas_head) relation models.ForeignKey(Relation, on_deletemodels.CASCADE) tail models.ForeignKey(Entity, on_deletemodels.CASCADE, related_nameas_tail) # 可添加置信度、来源等字段 created_time models.DateTimeField(auto_now_addTrue) class Meta: unique_together (head, relation, tail) # 防止重复知识 def __str__(self): return f{self.head.name} - {self.relation.name} - {self.tail.name}基于这个模型问答逻辑视图层的核心函数可能如下# views.py (部分) from django.http import JsonResponse from .models import Entity, Triple, Relation from .nlp_processor import MedicalNLP nlp_processor MedicalNLP() def answer_question(request): if request.method POST: question request.POST.get(question, ).strip() if not question: return JsonResponse({code: 400, msg: 问题不能为空}) # 1. NLP解析 parsed_result nlp_processor.parse_question(question) entities parsed_result[entities] intent parsed_result[intent] # 2. 根据意图和实体构建查询 answer_entities [] if intent symptom and entities.get(disease): disease_name entities[disease][0] try: disease_entity Entity.objects.get(namedisease_name, entity_typedisease) # 查找该疾病的所有症状关系三元组 symptom_relation Relation.objects.get(namehas_symptom) # 假设存在此关系 triples Triple.objects.filter(headdisease_entity, relationsymptom_relation) answer_entities [triple.tail.name for triple in triples] except (Entity.DoesNotExist, Relation.DoesNotExist): pass # 3. 生成答案文本 if answer_entities: if intent symptom: answer_text f{disease_name}的常见症状包括{、.join(answer_entities)}。 # ... 其他意图的答案模板 else: answer_text 抱歉我暂时没有找到这个问题的答案。 return JsonResponse({ code: 200, data: { question: question, answer: answer_text, entities: answer_entities, intent: intent } }) return JsonResponse({code: 405, msg: 方法不允许})4. 完整前后端实现与部署要点一个毕业设计项目除了核心逻辑完整的前后端交互和部署也是评分重点。4.1 前端界面设计与交互实现前端不需要太复杂一个简洁的问答界面即可。可以使用 Bootstrap 快速搭建。核心是一个输入框、一个提问按钮和一个答案展示区域。!-- question.html 核心部分 -- div classcontainer mt-5 h2 classtext-center mb-4医疗知识智能问答系统/h2 div classrow justify-content-center div classcol-md-8 div classinput-group mb-3 input typetext classform-control idquestionInput placeholder请输入您的医疗问题例如糖尿病的症状有哪些 button classbtn btn-primary typebutton idaskBtn提问/button /div div idanswerArea classmt-4 !-- 答案将动态加载到这里 -- /div /div /div /div script $(document).ready(function(){ $(#askBtn).click(function(){ var question $(#questionInput).val(); if(!question) { alert(请输入问题); return; } // 显示加载中 $(#answerArea).html(div classtext-centerdiv classspinner-border rolestatus/div 思考中.../div); $.ajax({ url: /api/answer/, // Django后端API地址 type: POST, data: { question: question, csrfmiddlewaretoken: {{ csrf_token }} }, success: function(response){ if(response.code 200){ var data response.data; var html div classcard div classcard-headerstrongQ:/strong ${data.question}/div div classcard-body p classcard-textstrongA:/strong ${data.answer}/p small classtext-muted识别意图${data.intent}/small /div /div; $(#answerArea).html(html); } else { $(#answerArea).html(div classalert alert-danger${response.msg}/div); } }, error: function(){ $(#answerArea).html(div classalert alert-danger网络请求失败请稍后重试。/div); } }); }); // 支持回车键提问 $(#questionInput).keypress(function(e){ if(e.which 13){ $(#askBtn).click(); } }); }); /script4.2 数据库初始化与数据导入流程项目拿到手后数据库很可能是空的。你需要一个数据初始化脚本。创建数据库和迁移python manage.py makemigrations python manage.py migrate编写数据导入脚本(import_data.py) 这个脚本负责从你准备好的数据文件如medical_data.json或medical_data.csv中读取知识并调用 Django 的 ORM 创建Entity和Triple记录。import os, django os.environ.setdefault(DJANGO_SETTINGS_MODULE, your_project.settings) django.setup() from kg_medical.models import Entity, Relation, Triple import json def import_from_json(filepath): with open(filepath, r, encodingutf-8) as f: data json.load(f) for item in data: # 假设数据格式{head: 糖尿病, relation: has_symptom, tail: 多饮} head_entity, _ Entity.objects.get_or_create(nameitem[head], defaults{entity_type: disease}) tail_entity, _ Entity.objects.get_or_create(nameitem[tail], defaults{entity_type: symptom}) relation_obj, _ Relation.objects.get_or_create(nameitem[relation]) Triple.objects.get_or_create(headhead_entity, relationrelation_obj, tailtail_entity) print(数据导入完成)运行python import_data.py即可将知识灌入数据库。4.3 项目部署与运行指南对于毕业设计演示本地运行即可。但了解部署流程是加分项。环境准备确保安装 Python 3.7使用pip install -r requirements.txt安装依赖Django, mysqlclient, jieba 等。数据库配置在settings.py中正确配置 MySQL 数据库连接信息。DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: medical_kg, # 数据库名 USER: your_username, PASSWORD: your_password, HOST: localhost, PORT: 3306, } }运行开发服务器python manage.py runserver 0.0.0.0:8000然后在浏览器访问http://localhost:8000即可。生产环境部署可选可以使用 Nginx Gunicorn 来部署 Django 应用并使用 Supervisor 管理进程。但这对于毕业设计答辩通常不是必须的。5. 常见问题排查与项目深度优化方向在实际运行和开发这个项目的过程中你肯定会遇到一些坑。这里我总结几个常见问题和对应的解决思路。5.1 开发与运行中的典型问题速查表问题现象可能原因排查与解决思路运行python manage.py runserver报错ModuleNotFoundError: No module named MySQLdb未安装 MySQL 的 Python 连接驱动。安装mysqlclient包pip install mysqlclient。在 Windows 上如果安装失败可以到 这里 下载对应版本的.whl文件离线安装。访问页面出现DisallowedHost错误Django 的ALLOWED_HOSTS配置限制了可访问的主机。在settings.py中将ALLOWED_HOSTS []修改为ALLOWED_HOSTS [*]仅限开发环境或添加具体的域名/IP。前端 Ajax 请求返回 403 Forbidden 错误缺少 CSRF跨站请求伪造令牌。确保 POST 请求中包含了 CSRF token。如上文前端代码所示通过模板变量{{ csrf_token }}获取并随数据提交。或者在视图上使用csrf_exempt装饰器不推荐用于生产环境。问答系统识别不出实体或意图1. 用户问题中的词汇不在自定义词典里。2. 意图关键词匹配规则不完善。1.扩充词典持续收集医疗实体加入disease.txt,symptom.txt等文件并确保jieba.load_userdict加载了最新词典。2.优化规则分析未匹配的问题案例补充新的意图关键词或采用更灵活的匹配方式如正则表达式。数据库查询速度慢页面响应迟缓1. 数据量增大后缺乏索引。2. 问答逻辑中存在循环查询或低效查询。1.添加数据库索引为Entity表的name字段Triple表的head,relation,tail外键字段添加索引可以极大提升 JOIN 查询速度。2.优化查询使用 Django ORM 的select_related或prefetch_related来减少数据库查询次数。避免在循环内进行数据库查询。5.2 从毕业设计到更优系统的优化建议如果你想把这个项目做得更出彩或者为后续深入研究做准备可以考虑以下几个优化方向引入更先进的 NLP 模型实体识别升级将基于词典的 NER 替换为基于预训练模型如 BERT、RoBERTa的微调模型。你可以使用transformers库在少量标注的医疗文本上微调一个 NER 模型识别准确率会大幅提升。意图识别升级将关键词匹配升级为文本分类模型。把用户问题分类到更精细的意图类别如“查询疾病症状”、“查询药品副作用”、“查询检查项目”等。可以用 FastText 或简单的 BERT 分类模型来实现。知识图谱查询的复杂化 当前系统主要处理单跳查询如疾病-症状。可以扩展支持多跳推理查询例如“治疗糖尿病的药物有哪些副作用”。这需要系统能先找到“治疗糖尿病的药物”第一跳再找到这些药物的“副作用”第二跳。这需要对查询逻辑进行更复杂的设计可能涉及图数据库查询语言如 Cypher或更复杂的 SQL 联表查询。答案生成的友好性与多样性 目前的答案生成是基于简单模板的。可以引入更灵活的模板或者尝试使用文本生成技术让答案更自然。例如除了列出症状还可以补充一句“如果出现以上多种症状建议及时就医检查。”前端体验优化历史问答记录使用浏览器本地存储LocalStorage或后端会话保存用户的提问历史。相关问题推荐在返回答案的同时根据当前问题中的实体从知识图谱中推荐几个相关问题如“糖尿病如何预防”、“糖尿病饮食注意什么”提升交互性。可视化知识图谱使用 ECharts 或 D3.js 库将查询结果涉及的实体和关系以图谱形式可视化展示出来非常直观答辩时是亮点。引入检索增强生成RAG思想 这是当前结合大语言模型LLM的热门方向。你可以将系统改造为先用现有的知识图谱检索出最相关的若干条知识三元组然后将这些知识作为“参考依据”和用户问题一起提交给一个开源的、本地部署的小规模 LLM如 ChatGLM-6B、Qwen-7B让 LLM 来组织生成最终答案。这样既能保证答案的准确性来源于可靠知识库又能提升答案的自然度和完整性。这需要一定的本地 GPU 算力或使用云上 API。这个项目提供了一个坚实的起点。它的价值在于清晰地展示了从数据到知识、从知识到智能应用的完整链路。无论是为了通过毕业答辩还是作为进入 AI 或知识图谱领域的敲门砖亲手实现并深入理解其中的每一个环节都会让你受益匪浅。在实际操作中最大的挑战往往不是编写代码而是如何获取和清洗高质量的数据以及如何设计出覆盖大部分用户问法的规则。多测试、多分析 bad case回答错误或无法回答的案例是迭代优化系统的最佳途径。本文还有配套的精品资源点击获取
返回列表