简介:面向计算机专业毕业设计、课设与实战学习者,这份Python结合机器学习的知识图谱智能医疗推荐问答App项目,覆盖知识图谱构建、医疗数据整理、推荐问答算法与Android客户端实现,并提供配套论文。源码经本地编译调试可运行,评审得分98分,适合作为选题参考或二次开发基础。压缩包共1403个文件,包含820个Java文件承载Android端业务逻辑、216个XML用于界面布局与配置、77个Python脚本负责模型与推荐服务,并有JSON、CSV、H5、SQL等数据与模型文件,整体38.72MB。另有Git版本配置、Gradle构建文件及PDF论文等资料,结构清晰。目前已有77人学习下载,内容完整、难度适中,便于理解一个医疗问答系统从数据到算法再到App落地的全过程。 每年毕业设计选题,总有几个同学会拿着“Python 基于机器学习的知识图谱智能医疗推荐问答 App”这个题目来问我。这套组合的吸引力很直接:Python 做算法顺手、机器学习能体现建模能力、知识图谱显得有技术深度,再做成一款移动 App,工作量也拿得出手。但它也有容易翻车的地方——如果没有把模型和图谱真正串成闭环,答辩时老师一问“机器学习到底用在哪了”,很多人就会卡壳。这篇文章就围绕这个题目,把选题逻辑、图谱构建、模型设计、后端与 App 联调、论文写作和答辩准备完整拆开讲,正在做或想复现的同学可以直接参考。
1. 选题与整体设计:为什么这个组合能当毕业设计
1.1 一个题目覆盖四类考点
毕业设计答辩时,评委最关心三件事:工作量够不够、技术有没有深度、系统能不能跑通。纯算法类题目容易变成“调参报告”,纯 App 类题目又容易被说成“没有科研含量”,知识图谱加推荐问答这个组合恰好把缺失的部分补上了。
这个题目能同时吃到四个方向的考点:
- Python 与工程能力:用 Flask/FastAPI 写后端、训练脚本、数据处理脚本,体现代码组织能力。
- 机器学习建模能力:意图识别、疾病预测、推荐排序都涉及真实分类任务,可以画出完整的训练、评估、对比流程。
- 知识图谱与数据能力:从非结构化文本中抽实体关系,设计本体,导入图数据库,再通过图查询得到可解释答案。
- 移动端与产品能力:App 不是附赠品,而是整个系统的展示面,聊天提问、结果卡片、图谱可视化都能让答辩演示更有冲击力。
我见过不少同学把这个项目做成“一个 App 接一个搜索接口”,或者“一个图谱网站里的查病工具”,这两种都没把题目吃透。好的做法是让知识图谱成为数据底座,让机器学习完成意图判断和结果排序,让 App 成为前端入口,三者各司其职又互相咬合。
1.2 系统架构与技术选型
技术选型决定了后面五个月是顺是坑,建议按下面这层结构走:
| 层级 | 推荐方案 | 说明 |
|---|---|---|
| 前端 App | uni-app 或 Vue3 打包 H5 | 跨平台省事,一套代码同时出 Android 和 iOS |
| 知识图谱可视化 | Vue3 + AntV G6 / ECharts Graph | 图谱关系展示效果好,社区案例多 |
| 后端服务 | Python + FastAPI 或 Flask | 和算法代码同语言,模型推理不用额外起服务 |
| 图数据库 | Neo4j 4.x | 知识存储与 Cypher 查询,文档丰富 |
| 机器学习框架 | scikit-learn + PyTorch(可选) | 意图分类可以先用 sklearn,NER 再引入深度学习 |
| 关系数据 | SQLite / MySQL | 存用户、问答历史、反馈记录 |
选 Python 而不是 Java 做后端的理由很实际:模型训练和模型推理都要用 Python,如果再套一个 Spring Boot,就不得不用 HTTP 把两个语言串起来,徒增工作量不说,答辩时还要解释两套工程的维护逻辑。FastAPI 自带异步支持和接口文档,比较适合这种带模型服务的场景。
1.3 端到端数据流
把整条链路在脑子里过一遍,后面写代码才有方向。用户打开 App,输入“我最近头痛、发热,还一直流鼻涕”,这条文本会依次经过以下节点:
- 意图识别模型判断用户想问什么(问疾病、问科室、问用药,还是闲聊)。
- 实体抽取模块从文本中提取症状实体“头痛”“发热”“流鼻涕”。
- 后端带着实体去知识图谱查询候选疾病,按命中症状数量打分。
- 推荐模型结合用户画像和当前症状对候选结果重新排序。
- 答案组装模块生成一段带依据的回复,连同相关疾病卡片一起返回 App。
这条链路里,图谱负责事实,机器学习负责语义理解和排序,两者缺一不可。这也是论文里最有价值的系统流程图。
2. 知识图谱构建:整个项目的信息底座
2.1 数据来源与本体设计
知识图谱不是越“大”越好,毕业设计里一个垂直小领域的图谱反而更容易讲清楚。我当时选了常见呼吸道和消化系统疾病,实体规模控制在几千个,三元组几万条,覆盖四十多种常见病,已经足够撑起演示和实验。
数据来源建议优先考虑公开可用的医学术语表、药品说明书文本、医学百科条目,以及开源的中文医学数据集合。这里有一条必须守住的底线:不要使用真实患者病历或含有个人身份信息的医疗数据,一方面是隐私合规问题,另一方面论文里也无法交代数据来源。
本体设计是整个图谱最重要的一步。我先定义实体类型和关系类型,再动手写采集脚本。我的本体结构是:
- 实体:疾病、症状、药品、检查项目、科室、人群(比如“儿童”“老年人”)。
- 关系:疾病与症状之间是“表现为”,疾病与药品是“治疗用药”,疾病与检查是“需做检查”,疾病与科室是“就诊科室”,药品与症状是“禁忌”。
设计关系的原则是“跟着问答场景走”。比如用户会问“感冒有什么症状”“头痛挂什么科”“发烧吃什么药”,那么这几个关系就必须要存在,否则系统回答不了高频问题。
2.2 实体识别与关系抽取的落地路径
图谱数据从哪来?我的做法是分两步:先用规则快速搭底子,再用模型做补充。
第一步用词典和正则从语料里抽取。比如定义一个疾病名称词典和症状词典,用反向最大匹配在文本里找候选词。关系抽取则用句式模板,比如“XX的典型症状是YY”“XX表现为YY”“治疗XX常用药物为YY”,一条条把三元组摘出来。规则抽取的好处是准确率高、成本低,缺点是覆盖率有限。
第二步再引入机器学习模型。我在论文里设计了一个基于 BERT 的中文命名实体识别模块,标注工具用的是开源的 Label Studio,标注了大概两千条语料,模型负责从用户自由文本里抽症状和疾病。但说实话,毕业设计规模下,词典兜底往往比模型更可靠,所以最终线上服务是“模型抽取 + 词典修正”的组合:模型给出实体候选,词典负责纠错和补全同义词,比如“头疼”和“头痛”统一映射到同一个实体节点。
关系抽取没有做太复杂,句式模板 + 人工抽检就够了。重点不是研究新方法,而是把流程走通,并且能在论文里写出你对不同抽取方式的对比分析。
2.3 用 Neo4j 存图谱,Cypher 写检索
数据清洗完成后,我导出成两个 CSV:节点表包含实体名称和类型,关系表包含头节点、尾节点和关系类型。首次导入时用 Cypher 的 LOAD CSV 批量创建。为了方便查询,我还在实体名称上建了唯一约束,后续重复导入不会产生脏数据。
CREATE CONSTRAINT ON (d:Disease) ASSERT d.name IS UNIQUE;症状匹配是问答系统的核心查询。用户输入“头痛、发热、流鼻涕”后,后端生成这样的 Cypher:
MATCH (d:Disease)-[:HAS_SYMPTOM]->(s:Symptom) WHERE s.name IN ['头痛', '发热', '流鼻涕'] RETURN d.name, count(d) AS hit_num, collect(s.name) AS matched_symptoms ORDER BY hit_num DESC LIMIT 5;这个查询本质上是在做“基于图谱的证据打分”:哪个疾病命中的症状多,排序就靠前。即使不接任何复杂的推荐算法,图谱本身已经能给出一个合理的候选集,这是知识图谱带来的天然优势。
2.4 图谱质量校验
图谱建完直接上线一定会翻车。我踩过几个坑:一是实体重复,比如“上呼吸道感染”和“上感”建成了两个节点,需要做上下位词和别名的合并;二是关系方向不一致,统一成“疾病→症状”后查询逻辑才清晰;三是孤立节点,图谱里有几十个节点没有任何关系,明显是抽取阶段没过滤干净。
我的校验办法是写一个脚本统计节点度数、检测孤立节点,再导出部分三元组人工抽查。另外会用可视化工具把图谱渲染出来,直观检查“围绕一个疾病展开的关系是否合理”。知识图谱可视化页面中所用的 Vue3 组件,在后端接口返回节点时要注意数量限制,如果只返回 25 个标签是因为后端分页或参数配置问题,不要误当成前端渲染出 bug。
3. 机器学习模型与推荐问答核心逻辑
3.1 意图识别与实体抽取
问答系统的第一步是弄清楚用户想问什么。我给系统定义了五类意图:查询疾病症状、根据症状问疾病、问科室、问用药、其他闲聊。分类模型用的是 FastText,输入是经过分词和清洗的句子,输出是意图标签和置信度。
训练数据量不需要很大,每个类别标注两三百条就能跑出可用的基线。为了让模型更稳,我对句子做了同义词替换和随机扩展,相当于做了数据增强。意图分类置信度低于 0.6 时,默认走了兜底话术:“这个问题我还不太确定,你可以试试输入症状,比如‘头痛发热,还咳嗽’。”
实体抽取模块独立成一个服务函数。它对用户输入做实体识别后,返回标准化后的实体列表。这里的技巧是:图谱中的症状名称和用户口语之间往往有偏差,比如用户说“嗓子疼”,图谱里可能是“咽痛”,因此需要维护一份同义词映射表,把口语化表达统一成标准实体名。这一步做不好,图谱查询再快也匹配不上。
3.2 疾病风险预测与可解释推荐
知识图谱能回答“事实型问题”,但还缺一点“推荐感”。为了体现机器学习的作用,我设计了一个疾病风险预测模型:输入是症状集合的多热编码向量,输出是每个候选疾病的概率。
算法上我对比了逻辑回归、随机森林和 XGBoost 三个模型。逻辑回归作为基线,随机森林缓解过拟合,XGBoost 效果最好但训练慢一些。在小样本场景下,逻辑回归的表现其实并不差,而且可解释性最强,可以输出每个症状对结果的权重贡献。最终论文里的实验表格就是这三者的精确率、召回率和 F1 对比。
推荐结果为什么可信?这是答辩必问的问题。我的设计是“图谱命中 + 模型打分 + 规则过滤”三合一:图谱提供候选和依据,模型重新排序,规则过滤掉明显不合适的答案(比如儿童禁用的药品)。最终返回的推荐卡片里会展示“命中症状”和“置信度”,让用户看到系统不是瞎猜的,这个可解释性设计是加分项。
3.3 问答结果的组装与兜底策略
生成回复时我没有用生成式模型直接“编”答案,而是采用模板化组装。原因很简单:医疗领域容错率低,模型自由发挥很容易生成不准确的内容。我们可以把图谱里的事实查出来,再放到预定义模板里拼装。
比如用户问“头痛挂什么科”,系统从图谱中找到“神经内科”“普通内科”等科室实体,然后生成:“根据你的症状,建议前往 XX 科就诊,如果你还有发热症状,也可以考虑先去发热门诊排查。”这类句式虽然朴素,但准确性和可控性都很好,且每条答案都有图谱出处。
医疗回复的安全边界也要提前设计好。系统定位是“健康辅助参考”,不是临床诊断。App 端在结果页底部明确标注“本结果仅供参考,不能代替医生诊断”,接口层也统一加了相应提示。这不仅是对用户负责,也是论文里体现工程素养的地方。
4. 后端与 App 端的工程落地
4.1 后端接口与代码结构
后端工程如果只有单个 Python 文件,后期一定很难维护。我建议按功能拆成分层目录:
medical_app/ ├── app.py # 路由与启动入口 ├── config.py # 配置:数据库地址、模型路径 ├── services/ │ ├── nlu.py # 意图识别 + 实体抽取 │ ├── kg_query.py # Neo4j 查询封装 │ ├── recommender.py # 推荐排序 │ └── answer_builder.py # 答案组装 ├── models/ # 训练好的模型文件 ├── data/ # 图谱与数据集 └── requirements.txt核心接口就一个,前端调用起来非常简单:
POST /api/chat 请求体:{ "query": "我最近头痛发热,还流鼻涕,怎么办?" } 响应体: { "intent": "ask_disease", "diseases": [ { "name": "普通感冒", "confidence": 0.82, "matched_symptoms": ["头痛", "发热", "流鼻涕"] } ], "answer": "根据你提供的症状,可能相关的疾病有:普通感冒、流感。建议前往呼吸内科就诊。", "related_entities": ["头痛", "发热", "流鼻涕"] }实际开发中要注意统一返回结构、异常处理和日志记录。不能等前端同学(或你自己写的前端页面)来问“为什么报错”,而是后端主动返回错误码和可读信息。FastAPI 的全局异常处理器能省不少事。
4.2 App 端核心页面与交互
App 端我用的是 uni-app,原因是可以一套代码编译到 Android/iOS H5。核心页面有四个:聊天问答页、推荐结果卡片页、知识图谱可视化页、历史记录页。
聊天问答页是主入口,交互参考微信聊天窗口:用户输入框在底部,消息列表向上滚动展示问答对。工程上要注意键盘弹出时输入框被遮挡的问题,还有长答案在气泡里的排版。推荐结果卡片放在机器人回复下方,包含疾病名称、置信度、匹配症状和就诊科室,数据从接口的 diseases 字段渲染。
知识图谱可视化页是对“你查的疾病和哪些实体有关”的图形化呈现。这个页面我用 WebView 内嵌了一个 Vue3 + AntV G6 的页面。实际操作中要注意:图谱数据量别一次性全量返回,最多取两跳邻居,否则前端布局会很乱,节点标签也会重叠。页面加载时先显示 loading,数据到了再画图,避免白屏。
4.3 本地部署、打包与联调
联调最容易踩坑的是网络地址问题。模拟器里访问本机后端用 localhost 通常没问题,但真机调试时后端地址要换成电脑的局域网 IP,并且后端服务启动时要绑定 0.0.0.0。另外,App 请求后端的域名或 IP 需要加入网络安全配置,否则会被系统拦截。
模型加载和线程安全也要留意。BERT 这类模型初始化会占几百兆内存,如果在每次请求时重新加载,后端直接卡死。我的做法是在服务启动时把模型加载到全局变量,推理时只做前向计算。FastAPI 默认的同步接口在线程池里运行,多个用户同时问也能稳定返回。
5. 论文写作与时间安排
5.1 论文怎么写才不“空”
论文结构我建议按标准的七章走:绪论、相关技术、需求分析、系统设计、系统实现、系统测试与实验分析、总结与展望。这样既符合学院要求,也覆盖了所有硬指标。
最怕的是论文里堆了一堆原理和代码,却没有“你的设计”。解决办法是每个章节都用自己的系统截图、自己的实验数据说话。比如相关技术章介绍 BERT 时,结尾补一段“本文为何选择 BERT 而不是 LSTM”的理由;系统设计章放自己的本体设计表、接口定义和数据流图;实验章放模型对比表。图和表是论文的骨架,本科毕设有十张以上的图表,保底工作量就是充足的。
模型实验一定要做对比。我当时给出了意图识别的 FastText vs TextCNN vs BERT 对比表,以及疾病风险预测的三种模型对比。哪怕结论是“简单模型效果接近复杂模型”,这也是一个有价值的分析,顺便还能体现对算法原理的理解。
5.2 从定题到答辩的时间分配
这个项目完整做下来,我建议留 10 周左右。具体分配可以这样排:
- 第 1-2 周:搭 Python 环境、装依赖、跑通最小 Demo,同步收集医疗数据。
- 第 3-4 周:设计本体,完成知识图谱构建和 Neo4j 导入。
- 第 5-6 周:完成意图识别模型和疾病预测模型,跑对比实验。
- 第 7-8 周:后端接口开发,App 端页面联调。
- 第 9-10 周:论文写作、源码整理、答辩 PPT 和演示脚本。
这里有一个很重要的建议:不要等到系统全做完了再写论文。每完成一个模块,就顺手把对应章节的图、表和初稿写出来,否则最后两周会非常痛苦。源码整理也要专门留时间,写一份清晰的 README,说明 Python 版本、安装命令和启动步骤,答辩时老师很可能现场要求运行。
5.3 源码管理与演示准备
源码管理最忌讳“一个文件走天下”。从第一天起就用 git 管理,每个模块一个 commit。论文里的代码片段放核心逻辑,不要贴大段无关代码。
答辩演示准备一条主流程就够:用户提问 → 意图识别 → 图谱查询 → 推荐结果 → 图谱可视化。把这条链路完整走一遍,比展示一百个页面截图都管用。同时准备一个“如果系统抽风”的备用方案,比如输入一个明显不合理的句子,系统返回兜底提示,也可以展示成系统鲁棒性。
6. 常见问题与踩坑实录
6.1 数据与图谱相关
问:医疗数据从哪来,会不会涉及隐私?
答:用公开医学语料、药品说明书和百科数据,或者自己构造模拟数据。论文里注明数据来源和规模,绝不碰真实患者信息。
问:知识图谱数据太少怎么办?
答:选择一个垂直子领域做深做细。横向铺开五十个疾病但每个只有两条关系,不如围绕二十个疾病构建完整的症状、用药、检查关系。演示时老师更关心你能否围绕一个案例解释清楚。
问:实体抽取总是不准。
答:先上词典和规则,模型作为补充。保证“实体对齐”做扎实,把同义词映射表维护好,往往比提升模型精度见效更快。
6.2 模型与算法相关
问:模型准确率低是不是就完了?
答:毕业设计不要求 SOTA。实验里把几种模型都跑一遍,对比分析为什么低、怎么改进,这本身就是论文价值。最忌讳只放一个最终精度很高的模型,却讲不清楚数据来源和训练过程。
问:推荐结果被老师挑战“不合理”怎么办?
答:设计时就加入规则过滤和置信度展示。只要你能说出“候选集来自知识图谱、排序来自模型、禁忌规则来自药品说明”,这个解释就足够有说服力。
6.3 工程与演示相关
问:App 真机访问不了后端?
答:检查后端是否绑定 0.0.0.0,App 是否用了局域网 IP,以及防火墙是否放行端口。用电脑上的 curl 先测一遍后端接口,再排查前端,能省一大半时间。
问:Neo4j 导入数据时连接失败?
答:先检查 Neo4j 服务是否启动、用户名密码是否和配置文件一致,再检查导入文件路径。用官方浏览器版管理界面做数据预览,排查比命令行直观很多。
问:演示时系统突然报错怎么办?
答:提前准备一份 demo 脚本,列出 3 个查询问题和预期返回。只要有一条主链路能稳定复现,加上兜底提示话术,演示就不会翻车。
我自己的体会是,这类项目能不能拿优秀,关键在于你是否把“知识图谱、机器学习、App”三个模块讲成了一件连贯的事。答辩时间有限,与其钻研一个模型的微小提升,不如把整个闭环的稳定性和可解释性打磨到位。最后再分享一个小技巧:答辩前一周,把意图识别、图谱查询、推荐返回这条链路上最容易出问题的环节都压测一遍,特别是不含医疗实体的乱输入,确保系统能优雅降级而不是直接崩溃,这个细节比任何花哨的功能都更能让老师放心。
本文还有配套的精品资源,点击获取