尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于RAG与知识图谱的AI医疗问诊平台:从架构到毕业设计实现

基于RAG与知识图谱的AI医疗问诊平台:从架构到毕业设计实现 每年到毕业设计选题季总有一批计算机专业的同学卡在同一个问题上选一个什么样的题目既能用到最新的大模型技术又不会因为难度太高而做不完还能让答辩老师觉得“有点东西”。纯网页管理系统太旧纯算法研究太难单写前端没深度单训练模型又跑不起。而AI医疗问诊平台这类选题恰好站在一个非常舒服的位置上它有大模型、有知识图谱、有RAG检索增强生成也有完整的前后端工程技术栈几乎覆盖了当前企业招聘JD里最常出现的几个关键词。这篇文章要聊的就是一套基于RAG LangChain Neo4j知识图谱 FastAPI Vue3的AI智能医疗问诊平台系统从项目架构、环境搭建、核心代码到答辩亮点和常见坑位一次性拆清楚。先说一个非常重要的前提医疗AI是严肃场景本文只讨论技术教学与演示不构成任何医疗诊断建议。做毕业设计时一定要在系统里加入免责声明和“仅供参考”的提示这既是技术人的职业道德也是答辩时容易被追问的点。1. 这个项目值得选择的三个理由如果只看表面你可能觉得它只是一个“加了ChatGPT接口的医疗问答系统”。但实际上这类项目的真正价值在于它用一套完整的技术链路把大模型的生成能力、知识图谱的结构化推理能力和Web工程的交付能力串在了一起。第一技术栈完整简历上非常能打。从后端API到前端交互从图数据库到向量检索从Prompt工程到流式输出几乎每个模块都能单独拿出来写一段项目亮点。第二天然适合做成“展示型系统”。毕业设计答辩时老师最怕听到的是“我封装好了接口但界面没做完”。医疗问诊平台有明确的用户角色——患者提问、系统回答、按科室分类、展示关联知识前端可以做得很丰富后端也有明确的业务逻辑整场演示流程非常顺。第三区分度足够高。如果班里一半人做“图书管理系统”或“网上商城”你拿出一套“基于知识图谱的医疗问答系统”从选题上就已经赢了。再加上RAG和LangChain这些当前热度非常高的技术词答辩时能讲的东西太多了。当然这个项目的难度也不低。它不是简单的CRUD需要同时理解图数据库建模、向量检索、大模型调用和异步任务处理。但如果按本文的拆解一步步来完全可以在两周到三周内完成一个能演示的核心版本后续再逐步加分。2. 系统架构与核心概念拆解2.1 整体架构一句话版用户在前端Vue3页面输入症状描述请求通过FastAPI后端进入LangChain编排层LangChain先从Neo4j知识图谱中检索相关的疾病、症状、科室关系再从向量数据库中召回医学知识片段最后把这两部分结果一起塞进大模型Prompt生成结构化问诊回答。这个链路里有四个关键角色对应四层架构。层级技术选型核心职责前端展示层Vue3 Element Plus问诊对话界面、知识图谱可视化、科室导航后端服务层FastAPI统一API入口、权限校验、业务逻辑编排智能编排层LangChainPrompt管理、LLM调用、RAG检索链组装数据存储层Neo4j 向量库医疗知识图谱存储、医学文本向量化检索2.2 知识图谱在这里解决什么问题医疗问诊有一个天然适合用知识图谱建模的特点实体多、关系密。“头痛”可能指向“高血压”也可能指向“偏头痛”还可能关联“神经内科”。如果用传统关系型数据库存这种多跳关系查询会变得非常痛苦要写大量JOIN。知识图谱把“疾病-症状-科室-药物”建模成节点和关系(症状:头痛)-[可能指向]-(疾病:偏头痛) (疾病:偏头痛)-[建议就诊]-(科室:神经内科) (疾病:偏头痛)-[可服用]-(药物:布洛芬)当用户输入“我最近经常头痛还伴有恶心”系统可以先用实体识别抽取出“头痛”和“恶心”然后在图谱中进行多跳查询找到潜在的疾病和对应科室。这种能力是纯关键词搜索或纯大模型生成很难做到的。2.3 RAG和LangChain在这里扮演的角色RAG全称Retrieval-Augmented Generation检索增强生成。它解决的是大模型的“幻觉”问题和“知识陈旧”问题。医疗场景里如果让大模型凭记忆回答“头痛该吃什么药”它可能会给出看似合理但并不可靠的建议。RAG的思路是不直接让模型凭空回答而是先从知识库中检索出真实资料再让模型基于这些资料做总结和推理。LangChain就是这个过程的“胶水层”。它把Prompt模板、LLM调用、向量检索、知识图谱查询串成一整条链。比如LangChain里可以定义一个create_retrieval_chain把Neo4j的查询结果作为上下文注入Prompt再用ChatOpenAI或国内大模型API完成最终生成。很多初学者会对LangChain和LangGraph的关系感到困惑。简单理解LangChain是处理“链”的框架一条链通常是一个固定流程LangGraph是处理“图”的框架支持分支、循环、条件跳转。做毕业设计版本的医疗问诊系统用LangChain的标准链就够了如果你想在问诊中加入多轮对话决策比如根据用户回答决定是否追问症状细节再考虑升级到LangGraph。3. 环境准备与前置条件开始写代码之前先把环境理顺。这里按“本体开发机 数据服务 模型服务”三个部分来准备。3.1 基础环境Python 3.10 或 3.11建议用conda创建独立虚拟环境避免和系统Python冲突Node.js 18用于运行Vue3前端工程Neo4j Community Edition如果用Docker安装会更快一个可用的LLM API。可以是OpenAI兼容接口也可以是国内云厂商的大模型API更省事的方案是本地部署Ollama 开源模型需要说明的是不同版本的依赖之间兼容性差异很大本文代码以最常见组合为例版本号请以实际安装为准重点演示通用思路。3.2 安装Python依赖创建虚拟环境并安装核心依赖conda create -n medibot python3.11 -y conda activate medibot pip install fastapi uvicorn neo4j langchain langchain-community langchain-openai chromadb pydantic python-dotenv3.3 安装Neo4jDocker方式是最省心的一条命令启动docker run -d \ --name neo4j-medical \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTHneo4j/yourpassword \ -e NEO4J_PLUGINS[apoc] \ neo4j:5.26启动后用浏览器打开http://localhost:7474使用账号neo4j和设置的密码登录能在浏览器里执行Cypher查询就算安装成功。如果本机没有Docker也可以下载Neo4j Desktop或Community压缩包。桌面版自带图形管理界面适合新手观察图谱关系。社区版压缩包需要自己配JAVA_HOME如果忘记配置环境变量启动时会出现“Unable to find java”之类的报错。3.4 创建Vue3工程npm create vitelatest medibot-frontend -- --template vue cd medibot-frontend npm install npm install axios element-plus npm run dev访问http://localhost:5173能看到Vite默认页面说明前端环境已经就绪。4. 知识图谱建模与数据准备4.1 医疗知识图谱的实体与关系设计在Neo4j中建模之前先确定四类核心实体和四类核心关系这决定了系统能回答什么问题。实体Disease疾病属性包括名称、简介、注意事项Symptom症状属性包括名称、描述Department科室属性包括名称、位置Medicine药物属性包括名称、功效、用法关系(Disease)-[HAS_SYMPTOM]-(Symptom)疾病包含的症状(Symptom)-[MAY_INDICATE]-(Disease)症状可能指向的疾病(Disease)-[TREAT_IN]-(Department)疾病建议就诊科室(Disease)-[USE_MEDICINE]-(Medicine)疾病可用药物之所以保留双向关系是为了支持两类查询从症状找疾病患者提问场景从疾病查细节医生/信息展示场景。4.2 用Cypher批量导入数据Neo4j支持从CSV文件批量导入数据。假设数据文件放在Neo4j的import目录下。疾病节点导入LOAD CSV WITH HEADERS FROM file:///diseases.csv AS row CREATE (d:Disease { id: row.id, name: row.name, desc: row.desc, notice: row.notice });关系导入LOAD CSV WITH HEADERS FROM file:///disease_symptom.csv AS row MATCH (d:Disease {id: row.disease_id}) MATCH (s:Symptom {id: row.symptom_id}) MERGE (d)-[:HAS_SYMPTOM]-(s);如果是演示用的少量数据也可以直接用MERGE语句手写。这里比较推荐的办法是先准备一个init_data.cypher文件里面写好所有节点的创建语句然后在Neo4j Browser里执行。设计课程的演示数据量不需要很大20个疾病、50个症状、10个科室、30种药物就足够跑通全流程了。5. RAG向量检索模块实现5.1 为什么在知识图谱之外还要向量库知识图谱擅长精确关系查询但它有一个弱点它需要查询词和图谱里的实体名称匹配上。如果用户说“脑袋昏昏沉沉”而图谱里存的是“头晕”普通Cypher查询就匹配不上。向量检索解决的是这个问题。把医学文本片段转成向量存在向量库里用户提问时同样转成向量通过余弦相似度找到语义接近的文本即使措辞不一样也能召回。所以在完整版本的系统中知识图谱负责“结构化推理”向量库负责“语义召回”两者互补。5.2 构建医学知识向量库用LangChain的TextLoader加载医学知识文档按固定大小切分然后用Embedding模型转向量存入ChromaDB。from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma # 加载医学知识文档 loader TextLoader(medical_knowledge.txt) documents loader.load() # 文本切分 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50 ) chunks splitter.split_documents(documents) # 向量化并存储 embeddings HuggingFaceEmbeddings( model_nameshibing624/text2vec-base-chinese ) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db )这里用的是text2vec-base-chinese它是开源的中文文本向量模型对中文医学文本效果尚可且不需要联网获取Embedding服务。如果你想用更好的效果可以替换为BGE-large-zh或云厂商的Embedding API但要注意模型体积和推理耗时对毕设演示的影响。5.3 LangChain检索链from langchain_community.vectorstores import Chroma from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.chat_models import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain embeddings HuggingFaceEmbeddings( model_nameshibing624/text2vec-base-chinese ) vectorstore Chroma( persist_directory./chroma_db, embedding_functionembeddings ) retriever vectorstore.as_retriever(search_kwargs{k: 5}) llm ChatOpenAI( base_urlhttps://your-llm-api.com/v1, # 可以替换为兼容OpenAI的API地址 api_keyyour_api_key, modelgpt-3.5-turbo, temperature0.3 ) prompt ChatPromptTemplate.from_template( 你是一名专业的医疗问诊助手。请严格基于以下医学知识片段回答用户问题。 如果知识片段中没有相关信息请明确说“知识库中暂未收录相关信息建议前往医院就诊”不要编造答案。 知识片段 {context} 用户问题 {input} 请依次回答 1. 初步判断 2. 建议就诊科室 3. 注意事项与免责声明 ) document_chain create_stuff_documents_chain(llm, prompt) rag_chain create_retrieval_chain(retriever, document_chain) result rag_chain.invoke({input: 我最近经常头痛还伴有恶心可能是什么问题}) print(result[answer])这段代码里最关键的部分是Prompt。医疗场景的核心安全边界就是“有据可依、无据可拒”。如果没有限制大模型容易顺着用户的描述生成一个看起来很严重或者很不严重的回答加了“基于知识片段回答”的系统约束后输出质量会稳定很多。6. 基于Neo4j知识图谱的查询服务6.1 封装Neo4j驱动FastAPI后端中使用Neo4j官方Python驱动操作图数据库。建议单独封装一个服务类避免在路由函数里到处写查询逻辑。# 文件路径app/services/graph_service.py from neo4j import GraphDatabase class GraphService: def __init__(self, uri, user, password): self.driver GraphDatabase.driver(uri, auth(user, password)) def close(self): self.driver.close() def search_by_symptom(self, symptom_name: str): 根据症状查询可能的疾病和就诊科室 query MATCH (s:Symptom)-[r:MAY_INDICATE]-(d:Disease) WHERE s.name CONTAINS $symptom OPTIONAL MATCH (d)-[:TREAT_IN]-(dep:Department) RETURN d.name AS disease, d.desc AS disease_desc, dep.name AS department LIMIT 5 with self.driver.session() as session: result session.run(query, symptomsymptom_name) return [record.data() for record in result]CONTAINS不是最精确的匹配方式但对于演示场景足够。生产环境一般会用全文索引或分词组件。6.2 在FastAPI中整合FastAPI是整个后端的路由层。我们需要把三个能力汇聚到一个接口里调用GraphService查询知识图谱拿到疾病候选和科室关系调用LangChain RAG链路得到基于知识片段的生成回答把两部分拼接成结构化响应返回给前端# 文件路径app/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from app.services.graph_service import GraphService from app.services.rag_service import answer_question app FastAPI(titleAI智能医疗问诊平台) graph_service GraphService( uribolt://localhost:7687, userneo4j, passwordyourpassword ) class QueryRequest(BaseModel): question: str class QueryResponse(BaseModel): rag_answer: str graph_entities: list disclaimer: str app.post(/api/consult, response_modelQueryResponse) async def consult(req: QueryRequest): if not req.question.strip(): raise HTTPException(status_code400, detail问题内容不能为空) # 1. 知识图谱查询 graph_entities graph_service.search_by_symptom(req.question) # 2. RAG生成回答 rag_answer answer_question(req.question) return QueryResponse( rag_answerrag_answer, graph_entitiesgraph_entities, disclaimer以上内容由AI生成仅供参考不构成医疗诊断建议。如有不适请及时就医。 ) app.on_event(shutdown) def shutdown(): graph_service.close()启动后端uvicorn app.main:app --reload --port 8000启动后在浏览器打开http://localhost:8000/docs就能看到FastAPI自动生成的Swagger接口文档可以直接在页面上测试接口非常方便答辩演示。7. 基于Vue3的前端问诊界面7.1 前端页面结构前端界面至少要包含三个核心区域问诊对话区用户输入症状展示AI回复知识图谱区以图谱形式展示疾病与症状的关系科室导航区显示推荐就诊科室对话区是重点推荐使用类似聊天软件的布局用户消息靠右、AI消息靠左。调用后端接口时用axios发POST请求。7.2 前端核心代码!-- 文件路径src/components/ChatPanel.vue -- template div classchat-panel div classmessage-list div v-for(msg, index) in messages :keyindex :class[message, msg.role] div classbubble{{ msg.content }}/div /div /div div classinput-area el-input v-modelinputText placeholder请输入你的症状例如头痛、发热、咳嗽... keyup.entersendMessage / el-button typeprimary clicksendMessage发送/el-button /div /div /template script setup import { ref } from vue import axios from axios const messages ref([]) const inputText ref() async function sendMessage() { const question inputText.value.trim() if (!question) return messages.value.push({ role: user, content: question }) inputText.value try { const res await axios.post(http://localhost:8000/api/consult, { question }) const answer res.data.rag_answer \n\n res.data.disclaimer messages.value.push({ role: assistant, content: answer }) } catch (error) { messages.value.push({ role: assistant, content: 服务暂时不可用请检查后端是否启动。错误信息 error.message }) } } /script如果项目做到进阶版可以再加两个功能一是流式输出把FastAPI接口改成StreamingResponse前端用EventSource或fetch流式读取让AI回答像打字机一样逐字出现体验会明显提升二是知识图谱可视化用ECharts或D3.js把graph_entities渲染成节点关系图答辩时展示效果非常好。7.3 前后端联调注意点开发环境前后端端口不同会遇到跨域问题。FastAPI需要开启CORS中间件from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins[http://localhost:5173], allow_credentialsTrue, allow_methods[*], allow_headers[*], )如果不加这个配置浏览器控制台会报CORS policy错误前端拿不到任何数据。8. 完整运行流程与效果验证所有模块都写完后按下面的顺序启动服务。第一步确认Neo4j已启动浏览器能打开Neo4j Browser并能执行MATCH (n) RETURN n LIMIT 25;如果返回了图谱数据说明图数据库正常。第二步启动FastAPI后端cd backend uvicorn app.main:app --reload --port 8000打开http://localhost:8000/docs在Swagger页面调用/api/consult接口输入头痛观察返回结果。正常的响应应该包含rag_answer、graph_entities和disclaimer三个字段。第三步启动Vue3前端cd frontend npm run dev在页面输入症状观察对话是否正常返回。同时打开浏览器开发者工具查看Network面板中/api/consult请求的状态码200表示成功4xx或5xx需要回到后端日志排查。如果全部跑通系统演示流程可以这样设计先问一个图谱中明确存在的症状展示AI的结构化回答再问一个图谱中没有的模糊描述看RAG能否召回到相关答案最后展示图谱可视化页面说明知识图谱的推理路径。这套流程走下来答辩时间基本能撑满。9. 常见问题与排查思路问题现象可能原因排查方式解决方案Neo4j启动失败提示java相关错误未安装JDK或JAVA_HOME未配置执行java -version检查JDK安装JDK 17并配置JAVA_HOME环境变量Neo4j Browser打不开Docker容器未运行或端口冲突docker ps查看容器状态确认7474端口未被占用重启容器LangChain报OpenAIException: Invalid API keyAPI Key配置错误检查环境变量和代码中的API Key确认Key未过期确认API地址正确中文回答质量差或出现幻觉Embedding模型效果一般或知识库内容不足打印检索到的上下文片段看是否相关换用更强的Embedding模型增加知识库文本量前端请求后端报CORS错误后端未开启CORS中间件查看浏览器控制台错误信息在FastAPI中添加CORSMiddleware并允许前端地址知识图谱查询返回空结果数据未导入或症状名称不匹配在Neo4j Browser执行MATCH (n:Symptom) RETURN n检查CSV导入语句尝试用CONTAINS模糊匹配向量库加载失败Chroma持久化目录损坏或版本不兼容查看启动日志中向量库相关错误删除./chroma_db目录重新执行向量化脚本FastAPI启动报ModuleNotFoundError依赖未安装完整查看报错模块名称pip install对应的缺失依赖包确认虚拟环境已激活这里特别提醒一个容易被忽略的坑ChromaDB在不同版本之间存在兼容性问题如果之前用旧版本创建的持久化目录升级LangChain后可能无法加载。稳妥做法是固定版本或者在代码中加入“目录不存在时自动重建”的逻辑。10. 最佳实践与工程建议10.1 医疗场景的安全合规这是整个项目最需要强调的部分。作为毕业设计或课程设计系统里的AI回答不能给出明确的用药剂量和诊断结论必须在每次回答末尾附带免责声明。在设计Prompt时可以加入系统级约束例如“只提供科普信息不提供处方建议”。答辩时如果能主动提到这一点会显得你考虑问题更全面。10.2 项目目录结构规划一个大而全的项目最怕代码全堆在一个文件里。建议一开始就按模块划分medical-chatbot/ ├── backend/ │ ├── app/ │ │ ├── main.py # FastAPI入口 │ │ ├── services/ │ │ │ ├── graph_service.py # Neo4j操作 │ │ │ ├── rag_service.py # RAG链路 │ │ │ └── llm_service.py # LLM调用封装 │ │ └── models/ │ │ └── schemas.py # Pydantic模型 │ ├── data/ │ │ ├── diseases.csv │ │ └── medical_knowledge.txt │ └── requirements.txt ├── frontend/ │ ├── src/ │ │ ├── components/ │ │ │ ├── ChatPanel.vue │ │ │ └── GraphView.vue │ │ ├── api/ │ │ │ └── consult.js │ │ └── App.vue │ └── package.json └── README.md把services层独立出来的好处是后续不管是替换大模型API、换Embedding模型还是改图数据库查询逻辑都只需要改对应模块不会牵连其他文件。10.3 大模型API配置管理永远不要把API Key硬编码在代码里。使用.env文件管理敏感配置并在.gitignore中排除它from dotenv import load_dotenv import os load_dotenv() OPENAI_API_KEY os.getenv(OPENAI_API_KEY) NEO4J_PASSWORD os.getenv(NEO4J_PASSWORD)这样在答辩演示时不会出现Key泄露的尴尬也符合工程上线的基本规范。10.4 如果没申请到大模型API怎么办很多学校的学生可能没有可用的OpenAI API Key或者觉得海外支付麻烦。两条替代方案方案一使用国内云厂商的大模型API只要是OpenAI兼容的接口LangChain的ChatOpenAI类可以直接替换base_url参数。方案二使用本地部署的Ollama安装qwen2-7b或类似的开源模型再用LangChain的ChatOllama调用。缺点是需要一定的显存资源但好处是断网也能演示且完全不涉及API费用。10.5 答辩时怎么讲这个项目讲项目时不要只念功能清单。建议按“为什么要做→技术难点怎么解决→效果如何→改进方向”这个逻辑讲。重点可以讲为什么用知识图谱而不是关系型数据库画一张多跳关系查询的对比图为什么用RAG而不是直接调大模型讲清楚“幻觉问题”的危害知识图谱和向量检索是如何配合的覆盖了哪些查询场景回答中的免责声明和Prompt约束是怎么设计的11. 总结与后续扩展方向到这里基于RAG LangChain Neo4j FastAPI Vue3的AI智能医疗问诊平台系统的核心链路已经完整梳理了一遍。它从医疗知识图谱的建模开始完成了Neo4j数据导入、LangChain RAG检索链搭建、FastAPI后端接口封装以及Vue3前端问诊界面的开发最后通过一条完整的演示流程把整个系统串了起来。这个项目有意思的地方在于它不是一个停留在“调用大模型接口”层面的简单应用而是把大模型生成和信息检索、图数据库推理结合在了一起每一步都有技术决策可以展开讲。如果基础版本已经跑通后续往这几个方向扩展会更有竞争力第一增加多轮问诊对话。当前版本是单轮问答用户每次提问都是独立上下文。可以引入LangGraph或对话记忆机制让AI根据用户的追问动态调整问题比如先问“头痛持续多久了”再根据回答进一步判断。第二增加图谱可视化交互。在Vue3中接入ECharts关系图把疾病、症状、药物、科室渲染成动态网络图点击节点可以展开关联节点这会成为答辩的视觉亮点。第三增加用户登录与问诊记录。在FastAPI中加入JWT认证用MySQL或MongoDB保存用户的问诊历史。完整系统加上用户体系后才更接近一个“平台”的定义。第四扩充医学知识库。可以从开源医学知识库中获取更多疾病和药品数据但需要注意数据脱敏和版权确认。不建议直接爬取医院官网信息用于论文。最后再强调一次医疗AI技术很有价值但演示系统必须守住边界不能把自己包装成真正的在线问诊工具。在这个前提下放心去写代码、放心去构造你的知识图谱这套技术栈能给你的毕业设计带来非常扎实的加分项。如果按照本文思路动手实践遇到问题可以按照第9节的排查表逐项定位祝顺利。
返回列表