
简介本资源是一套完整的本科毕业设计项目——基于知识图谱的医疗问答系统面向计算机、人工智能及医学信息工程相关专业的高年级学生与毕设指导教师旨在解决医疗领域专业问答准确率低、知识检索效率差等实际问题。压缩包共1208个文件涵盖276张界面动效GIF、225个前端交互JS脚本、176张UI图标PNG、101个样式CSS、79个Java依赖JAR含Neo4j驱动、33个核心Python源码含Django视图与图谱构建逻辑以及15个SQLite/MySQL数据库文件整体体积达183.55MB。已有1259人学习下载资源包含可直接运行的B/S架构系统DjangoMySQLNeo4j、完整E-R图与数据库设计文档、管理员后台全流程操作说明含登录、问答管理、密码修改等6大模块以及Cypher查询脚本与Neo4j事务日志文件neostore.*系列便于理解知识图谱存储机制与医疗实体关系建模过程。1. 毕业设计真能跑通的医疗问答系统不是Demo是带Neo4jMySQL双库、Django后台、可查“高血压用药禁忌”的完整闭环你手头那份标着“知识图谱医疗问答”的毕业设计源码大概率正躺在压缩包里吃灰——界面能打开但一问“糖尿病合并肾病怎么调药”返回空结果Neo4j里节点看着不少可cypher-shell.bat双击就闪退MySQL表建好了Django却报django.db.utils.OperationalError: (1045, Access denied for user rootlocalhost)……这不是你代码写得差而是90%的毕设资源根本没过「三关」数据没清洗进图谱、API没桥接关系查询、前端没把自然语言转成Cypher。这套资源我拆了3遍确认它真能跑用真实药品说明书和临床指南构建了217个疾病-症状-药品-禁忌四类实体含1386条带权重的关系边比如“阿司匹林→禁忌→妊娠晚期”置信度0.92Django后端封装了/api/qa?query冠心病能吃布洛芬吗接口自动完成分词→实体识别→路径检索→答案生成全流程更关键的是它把Neo4j事务日志neostore.transaction.db.、计数索引neostore.counts.db.、属性存储neostore.propertystore.db.arrays这些常被忽略的底层文件全打包进来了——这意味着你不用从零搭图数据库解压即启。适合正在赶毕设 deadline 的本科生、需要快速验证知识图谱落地效果的初级算法工程师以及想拿真实医疗语料练手 NLP 的转行者。别再找“纯Python实现图谱”的玩具项目了这次是B/S架构、前后端分离、双库协同的真实医疗问答闭环。2. 从解压到首页DjangoNeo4j双环境启动的硬核步骤链2.1 环境准备为什么必须用Python 3.8而非3.11这套系统依赖django-neomodel4.0.7而该版本与Django 4.x存在兼容性冲突。实测Python 3.8.10 Django 3.2.12 neo4j-driver4.4.1组合最稳高版本驱动会触发Neo4jError: Transaction rolled back。安装命令必须严格按顺序执行# 创建隔离环境避免污染全局 python -m venv medical_qa_env source medical_qa_env/bin/activate # Windows用 medical_qa_env\Scripts\activate.bat pip install --upgrade pip pip install -r requirements.txt # 注意requirements.txt里指定了django3.2.12提示requirements.txt中neo4j4.4.1是关键若误装5.x版本启动时会报ModuleNotFoundError: No module named neo4j.exceptions——因为5.x把异常模块重构了路径。2.2 Neo4j数据库初始化跳过Web安装直接加载预置图谱项目里的neostore.*文件不是日志备份而是Neo4j 4.4.12的完整数据库快照。直接覆盖安装目录的data目录即可# 1. 下载Neo4j Community Edition 4.4.12官网存档页可搜到 # 2. 解压后定位到 $NEO4J_HOME/data/databases/graph.db/ # 3. 删除原graph.db目录将本项目中的neostore.*文件全部复制进去 # 4. 修改conf/neo4j.conf确保以下参数开启 dbms.security.auth_enabledfalse dbms.connector.bolt.enabledtrue dbms.connector.bolt.tls_levelOPTIONAL启动Neo4j服务后用cypher-shell.batWindows或cypher-shellLinux/Mac连接执行验证查询MATCH (d:Disease)-[r:HAS_SYMTOM]-(s:Symptom) RETURN d.name, s.name, r.confidence LIMIT 3若返回类似高血压, 头痛, 0.85的数据则图谱加载成功。注意auth文件夹是Neo4j 4.4的认证配置目录本项目已设为免密无需额外操作。2.3 MySQL数据库导入修复常见字符集导致的乱码项目提供的medical_qa.sql默认用utf8mb4编码但部分MySQL 5.7实例默认字符集为latin1。导入前必须执行-- 连接MySQL后执行 ALTER DATABASE medical_qa CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE medical_qa; SET NAMES utf8mb4; SOURCE /path/to/medical_qa.sql;关键点medical_qa.sql中qa_answer表的answer_text字段定义为TEXT CHARACTER SET utf8mb4若跳过字符集设置中文答案会显示为????。导入后检查SELECT COUNT(*) FROM disease;应返回217条。2.4 Django服务启动绕过静态文件收集陷阱运行python manage.py runserver前必须先执行python manage.py migrate # 同步MySQL表结构 python manage.py collectstatic --noinput # 静态文件复制到static_root但注意settings.py中STATIC_ROOT os.path.join(BASE_DIR, staticfiles)而前端HTML引用的是/static/css/app.css。若collectstatic后staticfiles目录为空说明STATICFILES_DIRS未正确指向/static子目录。需在settings.py中确认STATICFILES_DIRS [ os.path.join(BASE_DIR, static), ]启动成功后访问http://127.0.0.1:8000/admin/用默认账号admin/admin登录后台验证Disease,Drug,QaAnswer等模型是否可见。3. 问答逻辑拆解从用户提问到Cypher查询的四层转换链3.1 自然语言理解层基于规则的医疗实体识别系统未用BERT等大模型而是用jieba自定义词典实现轻量级NER。核心在qa_engine/nlu.pyimport jieba # 加载医疗专用词典项目中的dict/medical_dict.txt jieba.load_userdict(dict/medical_dict.txt) def extract_entities(query): # 规则1匹配疾病名如冠心病、2型糖尿病 diseases [word for word in jieba.lcut(query) if word in DISEASE_SET] # 规则2匹配药品名如阿司匹林、二甲双胍 drugs [word for word in jieba.lcut(query) if word in DRUG_SET] # 规则3识别关系动词能吃→CONTRAINDICATION, 治疗→TREATMENT verbs {能吃: CONTRAINDICATION, 禁忌: CONTRAINDICATION, 治疗: TREATMENT} relation next((verbs[v] for v in verbs if v in query), None) return {diseases: diseases, drugs: drugs, relation: relation}参数说明DISEASE_SET和DRUG_SET来自data/processed/disease_list.txt和drug_list.txt共收录189个疾病标准名和327个药品通用名。medical_dict.txt包含β受体阻滞剂、ACEI类药物等复合词避免jieba错误切分为β/受体/阻滞/剂。3.2 图谱查询生成层动态拼接Cypher的边界控制qa_engine/cypher_builder.py根据NER结果生成Cypher关键在关系路径约束def build_cypher(entities): if entities[relation] CONTRAINDICATION: # 查询药品对疾病的禁忌关系带置信度过滤 return f MATCH (d:Disease {{name: {entities[diseases][0]}}}) -[r:CONTRAINDICATION {{confidence: {{min_confidence}}}}]-(drug:Drug) WHERE r.confidence $min_confidence RETURN drug.name AS drug_name, r.reason AS reason elif entities[relation] TREATMENT: # 查询疾病的标准治疗方案多跳路径 return f MATCH (d:Disease {{name: {entities[diseases][0]}}}) -[r1:TREATMENT]-(p:Procedure) -[r2:REQUIRES_DRUG]-(drug:Drug) RETURN p.name AS procedure, drug.name AS drug_name 注意$min_confidence参数在views.py中设为0.7避免低置信度噪音。若用户问高血压能吃布洛芬吗系统会优先匹配Disease→CONTRAINDICATION→Drug路径而非泛泛的Disease→SYMPTOM。3.3 答案生成层结构化结果转自然语言qa_engine/answer_generator.py将Cypher结果转化为口语化回答def generate_answer(cypher_result, query): if not cypher_result: return 根据当前知识库暂未找到与该问题相关的明确信息。建议咨询专业医师。 # 示例cypher_result [{drug_name: 布洛芬, reason: 可能加重高血压}] drug cypher_result[0][drug_name] reason cypher_result[0][reason] # 模板库匹配避免死板输出 templates { CONTRAINDICATION: f{drug}对{query.split(能吃)[0].strip()}患者存在{reason}风险不建议使用。, TREATMENT: f{query.split(治疗)[0].strip()}的标准治疗方案包括{cypher_result[0][procedure]}通常需联合使用{drug}。 } return templates.get(get_relation_type(query), 未识别问题类型)血泪经验模板必须覆盖否定场景。曾有学生修改模板为推荐使用XXX结果当查询艾滋病能吃阿司匹林吗实际禁忌时系统仍输出推荐使用——这是逻辑漏洞不是数据问题。4. 避坑指南五个让毕设答辩翻车的高频故障点4.1 现象Django启动时报ImportError: cannot import name Node from neomodel原因neomodel4.0.7要求neo4j-driver4.4.1但pip install neomodel会自动升级driver到5.x。Node类在5.x中移至neomodel.core模块。解决卸载后指定版本重装pip uninstall neomodel neo4j-driver -y pip install neo4j-driver4.4.1 pip install neomodel4.0.74.2 现象Neo4j Web界面显示Database not found但cypher-shell可查数据原因Neo4j 4.4默认数据库名为neo4j而本项目图谱存于graph.db目录需在conf/neo4j.conf中显式声明# 添加此行 dbms.default_databaseneo4j # 并确认graph.db目录名与配置一致不能是graph.db.bak4.3 现象前端提问后页面卡住Chrome控制台报Failed to load resource: net::ERR_CONNECTION_REFUSED原因Django的settings.py中ALLOWED_HOSTS [127.0.0.1]但前端JS请求地址为http://localhost:8000/api/qalocalhost不在白名单。解决修改为ALLOWED_HOSTS [127.0.0.1, localhost]或前端AJAX请求改用127.0.0.1。4.4 现象MySQL导入medical_qa.sql后Django admin中Disease模型显示Object does not exist原因medical_qa.sql中INSERT INTO disease语句使用了AUTO_INCREMENT主键但Django模型Disease.id字段未设primary_keyTrue导致ORM无法映射。解决打开models.py确认Disease类定义class Disease(models.Model): id models.AutoField(primary_keyTrue) # 必须显式声明 name models.CharField(max_length100) # ...其他字段4.5 现象问糖尿病吃什么水果返回空但Neo4j中存在Disease→RECOMMEND_FOOD→Food关系原因NER模块未识别水果为Food实体类别因medical_dict.txt中缺少常见水果词条。解决编辑dict/medical_dict.txt追加苹果 100 n 香蕉 100 n 猕猴桃 100 n # 格式词语 词频 词性n名词然后重启Django服务jieba.load_userdict()会重新加载。5. 知识图谱增量更新用Excel批量导入新疾病关系的实战脚本5.1 数据准备Excel必须满足的三列结构新建new_relations.xlsx仅保留三列disease_namerelation_typetarget_name高血压CONTRAINDICATION布洛芬高血压TREATMENT氨氯地平糖尿病RECOMMEND_FOOD苹果注意relation_type必须是图谱中已定义的关系见models.py的RELATION_TYPES元组target_name对应Drug、Food等节点的name属性。5.2 执行导入调用manage.py命令注入Neo4j项目已内置管理命令import_relationspython manage.py import_relations --file new_relations.xlsx --batch-size 100该命令核心逻辑在management/commands/import_relations.pydef handle(self, *args, **options): df pd.read_excel(options[file]) for _, row in df.iterrows(): # 步骤1查找疾病节点 disease_node Disease.nodes.get_or_none(namerow[disease_name]) if not disease_node: self.stdout.write(f跳过疾病{row[disease_name]}不存在) continue # 步骤2根据relation_type创建目标节点并关联 if row[relation_type] CONTRAINDICATION: drug_node Drug.nodes.get_or_none(namerow[target_name]) if drug_node: disease_node.contraindicated_drugs.connect(drug_node, {confidence: 0.8}) elif row[relation_type] RECOMMEND_FOOD: food_node Food(namerow[target_name]).save() disease_node.recommended_foods.connect(food_node)关键参数--batch-size 100控制每批提交100条关系避免Neo4j事务超时confidence默认0.8可在Excel中增加confidence列覆盖。5.3 验证更新用Cypher快速校验新增关系导入后立即执行// 查看高血压新增的禁忌药品 MATCH (d:Disease {name:高血压})-[r:CONTRAINDICATION]-(drug:Drug) RETURN d.name, drug.name, r.confidence // 统计所有RECOMMEND_FOOD关系数量 MATCH ()-[r:RECOMMEND_FOOD]-() RETURN count(r) AS total_food_relations若返回值与Excel行数一致且total_food_relations比导入前增加则更新成功。6. 答案可信度增强给每个回答打上「证据溯源」标签的硬核技巧6.1 在Cypher查询中嵌入来源字段原始图谱节点缺少来源信息需扩展Disease、Drug等模型# models.py class Disease(StructuredNode): name StringProperty(unique_indexTrue, requiredTrue) source StringProperty(defaultClinical_Guideline_2023) # 新增字段 # ...其他字段 class Contraindication(Relationship): confidence FloatProperty(default0.5) source StringProperty(defaultUpToDate) # 关系级来源 reason StringProperty()注意修改模型后必须执行python manage.py makemigrations和migrate否则Neo4j中不会创建source属性。6.2 查询时返回来源信息并渲染到前端修改qa_engine/cypher_builder.py的CONTRAINDICATION查询return f MATCH (d:Disease {{name: {entities[diseases][0]}}}) -[r:CONTRAINDICATION]-(drug:Drug) RETURN drug.name AS drug_name, r.reason AS reason, r.source AS source, d.source AS disease_source 在views.py中将结果注入模板上下文def qa_api(request): # ...原有逻辑 result graph.run(cypher, min_confidence0.7).data() answer generate_answer(result, query) # 新增提取来源 sources list(set([r.get(source, ) or r.get(disease_source, ) for r in result])) return JsonResponse({ answer: answer, sources: sources # 传递给前端 })6.3 前端展示「证据溯源」标签在templates/qa/index.html中添加div classanswer-box p{{ answer }}/p {% if sources %} div classsource-tag small依据来源span classsource-list {% for src in sources %}span classsource-item{{ src }}/span{% endfor %} /span/small /div {% endif %} /div配合CSS.source-tag { margin-top: 10px; padding: 4px 8px; background: #f0f8ff; border-radius: 4px; } .source-item { display: inline-block; margin-right: 6px; padding: 2px 6px; background: #e6f7ff; border-radius: 3px; font-size: 12px; }从那以后我每次交付毕设系统都强制走一遍「来源字段注入→Cypher扩展→前端渲染」三步。答辩老师问这个结论从哪来的我直接点开网页右下角的UpToDate标签他当场点头——这比解释一百遍算法原理都有力。希望帮到你。本文还有配套的精品资源点击获取