基于RAG与知识图谱的AI智能医疗问诊平台构建实践
大模型方向做毕业设计或课程设计最容易出现的问题不是模型选型而是项目停留在“单接口问答 Demo”的程度页面写死几条对话、后端只调一次模型、没有数据沉淀也没有可展示的知识链路。AI智能医疗问诊平台这个题目之所以适合 Python AI 大模型方向是因为它能把 RAG、LangChain、Neo4j 知识图谱、FastAPI、Vue3 串成一条完整的工程链路用户输入症状系统先检索医疗知识库再从知识图谱中抽取疾病、症状、药物、科室之间的关系最后交给大模型生成带依据的回答。这个项目既能体现你对大模型应用的理解也能体现后端接口设计、前端交互和数据库建模的基本功。下面按“项目定位 - 环境搭建 - 知识图谱建模 - RAG 服务实现 - 前端联调 - 验证 - 排错 - 扩展”这条主线展开。文中代码用于说明实现思路落地时请结合你自己的项目结构、依赖版本和模型服务地址调整。1. 项目定位与整体架构设计1.1 医疗问诊场景为什么需要 RAG 和知识图谱先想清楚业务场景用户输入“我最近头晕、心悸可能是什么问题”如果只把这个问题直接抛给大模型模型会凭训练数据里的知识生成一段回答。这种做法有两个问题第一回答可能过时、不具体甚至出现幻觉第二模型没有引用任何可追溯的医学资料用户无法判断回答是否可信。RAG 的做法是先检索再回答。系统先从内置的医学文档、指南、科普材料中检索与“头晕、心悸”相关的段落再把检索结果作为上下文交给大模型。这样回答就有据可依还能在页面上展示来源。知识图谱则解决另一类问题症状和疾病之间、疾病和药物之间、疾病和科室之间存在结构化关系这类关系用文本检索很难精确表达。例如“头晕可能关联高血压”“高血压应该在心血管内科就诊”这种一跳、两跳的图关系适合用 Cypher 查询表达。RAG 负责非结构化知识知识图谱负责结构化关系。两者结合正好构成医疗问诊平台的知识底座。1.2 核心技术栈的分工这个项目涉及五个核心组件分工可以这样理解组件角色要解决的问题RAG检索增强生成机制从医疗文档中检索证据约束大模型回答LangChainRAG 链编排框架把加载、切分、向量化、提示词、模型调用串成管线Neo4j图数据库存储疾病、症状、药物、科室等实体及关系FastAPI后端 API 框架暴露问诊、知识图谱、历史会话等接口Vue3前端框架实现对话界面、知识图谱可视化和交互逻辑如果使用 GitHub 上的现成开源项目要重点确认它的模型接入方式。很多项目默认接入 OpenAI 兼容接口实际使用时会配置到本地推理服务或国内大模型 API。模型供应商、Embedding 模型、向量库类型都可能影响最终效果。1.3 一次问诊请求的完整执行链路整个系统一次典型请求的执行链路如下用户在 Vue3 页面输入症状描述点击发送。前端将问题通过 HTTP 请求发送到 FastAPI 后端/api/chat接口。后端调用 RAG 检索模块从向量库中检索相关文档片段。后端同时调用 Neo4j 查询模块用 Cypher 语句检索疾病、症状、药物等图谱关系。后端把文档片段和图谱结果组装成上下文放入 LangChain 构造的提示词中。大模型根据上下文生成回答。后端将回答、来源引用、图谱证据封装为统一格式返回前端。前端渲染回答并在知识图谱面板中展示与问题相关的实体关系。这条链路的每一步都有独立的验证点这也是毕业设计答辩时最能体现工程能力的地方。2. 环境准备与依赖安装2.1 Python 虚拟环境与后端依赖建议使用 Python 3.10 到 3.12 之间的版本。过旧的 Python 对 LangChain 新版本支持不好过新的版本可能遇到依赖编译问题。创建虚拟环境并安装依赖mkdir ai-medical-question cd ai-medical-question mkdir backend frontend data cd backend python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate后端核心依赖可以放在requirements.txt中fastapi0.115.* uvicorn[standard]0.30.* langchain0.3.* langchain-community0.3.* langchain-huggingface0.1.* neo4j5.* faiss-cpu1.8.* sentence-transformers3.* pydantic2.* pydantic-settings2.* python-dotenv1.*安装命令pip install -r requirements.txt这里有一个容易被忽略的细节langchain、langchain-community、langchain-huggingface这三个包版本必须互相兼容。直接把langchain升到最新版而langchain-community还停留在旧版导入时经常报ImportError。推荐的做法是先确定主版本再用同样的主版本号安装其他包。2.2 Neo4j 安装与 DBeaver 连接配置Neo4j 是这个项目的数据核心建议直接使用 Docker 安装 Community 版方便清理和重来docker run -d --name neo4j-medical \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTHneo4j/你的密码 \ -v neo4j_med_data:/data \ neo4j:5.26-community启动后访问http://localhost:7474使用neo4j和刚才设置的密码登录。7474 是浏览器管理界面端口7687 是 Bolt 驱动连接端口后端代码连接时要使用 7687。如果需要用 DBeaver 查看图数据可以新建 Neo4j 连接主机填localhost端口填7687数据库默认neo4j。DBeaver 中执行 Cypher 脚本时经常遇到Content is not allowed in prolog这类 XML 解析错误这通常不是 Neo4j 本身的问题而是 DBeaver 在导入.cypher文件时按 XML 格式校验了文件头。解决办法是不要在 DBeaver 里以“导入文件”方式执行 Cypher而是打开 SQL 编辑器把 Cypher 语句直接粘贴进去执行或者使用 Neo4j 自带的 Browser 执行。2.3 Vue3 前端脚手架与 UI 依赖前端使用 Vite 创建 Vue3 项目cd frontend npm create vitelatest . -- --template vue npm install建议补充安装 Element Plus 和 ECharts。Element Plus 用于对话框、表单、按钮等组件ECharts 用于知识图谱可视化。npm install element-plus echarts axios在main.js中注册 Element Plusimport { createApp } from vue import ElementPlus from element-plus import element-plus/dist/index.css import App from ./App.vue const app createApp(App) app.use(ElementPlus) app.mount(#app)对于课程设计来说前端不需要过度复杂。核心页面至少包含三个部分问诊对话区、来源引用区、知识图谱可视化区。3. 医疗知识图谱建模与数据导入3.1 实体、关系和属性的最小模型医疗知识图谱的数据模型不用一开始就做得很庞大建议从最小闭环开始。实体类型先定义四类疾病 Disease症状 Symptom药物 Medicine科室 Department关系类型定义四类(Disease)-[:HAS_SYMPTOM]-(Symptom)疾病表现出哪些症状(Disease)-[:TREAT]-(Medicine)疾病用哪些药物治疗(Disease)-[:REFER_TO]-(Department)疾病应挂哪个科室(Medicine)-[:TARGETS]-(Disease)药物治疗哪些疾病每种实体至少包含一个name属性有条件的再补充description、code等字段。属性越多后期展示越丰富但数据整理成本也越高。3.2 Cypher 导入数据与检索语句用 Cypher 创建一组示例数据CREATE (d1:Disease {code: D001, name: 高血压, description: 以体循环动脉血压升高为主要表现的慢性疾病}), (d2:Disease {code: D002, name: 心律失常, description: 心脏冲动的频率、节律或传导异常}), (s1:Symptom {name: 头晕}), (s2:Symptom {name: 心悸}), (s3:Symptom {name: 胸闷}), (m1:Medicine {name: 氨氯地平, usage: 口服每日一次}), (dep1:Department {name: 心血管内科}); CREATE (d1)-[:HAS_SYMPTOM]-(s1), (d1)-[:HAS_SYMPTOM]-(s2), (d2)-[:HAS_SYMPTOM]-(s2), (d2)-[:HAS_SYMPTOM]-(s3), (d1)-[:TREAT]-(m1), (d1)-[:REFER_TO]-(dep1), (d2)-[:REFER_TO]-(dep1);查询“哪些疾病有头晕症状”MATCH (d:Disease)-[:HAS_SYMPTOM]-(s:Symptom) WHERE s.name CONTAINS $keyword RETURN d.name AS disease, collect(s.name) AS symptoms LIMIT 20;这里要注意CONTAINS对中文按精确字符匹配不会做模糊语义匹配。用户输入“头有点晕”时匹配不到“头晕”。可以通过两段处理解决第一段在 Python 层做关键词归一化比如把“头有点晕”归一到“头晕”第二段使用全文索引或向量检索。Neo4j 5.x 支持全文索引可以执行CREATE FULLTEXT INDEX symptomNameIndex FOR (s:Symptom) ON EACH [s.name];查询时使用db.index.fulltext.queryNodesCALL db.index.fulltext.queryNodes(symptomNameIndex, 头晕) YIELD node RETURN node.name;3.3 Python 连接 Neo4j 并封装查询后端使用neo4j官方驱动。连接信息统一放在.env文件中NEO4J_URIbolt://localhost:7687 NEO4J_USERneo4j NEO4J_PASSWORD你的密码封装一个GraphServicefrom neo4j import GraphDatabase from typing import List, Dict class GraphService: def __init__(self, uri: str, user: str, password: str): self.driver GraphDatabase.driver(uri, auth(user, password)) def close(self): self.driver.close() def query_diseases_by_symptom(self, keyword: str) - List[Dict]: cypher MATCH (d:Disease)-[:HAS_SYMPTOM]-(s:Symptom) WHERE s.name CONTAINS $keyword RETURN d.name AS disease, collect(s.name) AS symptoms LIMIT 10 with self.driver.session() as session: result session.run(cypher, keywordkeyword) return [{disease: row[disease], symptoms: row[symptoms]} for row in result]这个服务类在 FastAPI 启动时初始化一次不要在每个请求里创建新的 Driver 连接。GraphDatabase.driver内部自带连接池重复创建会造成资源浪费。4. FastAPI 服务与 RAG 链路实现4.1 后端项目目录结构后端代码建议按功能分层backend/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── config.py # 读取环境变量 │ ├── api/ │ │ └── routes.py # 路由定义 │ ├── core/ │ │ ├── llm.py # 大模型初始化 │ │ ├── rag.py # RAG 检索链 │ │ └── graph.py # Neo4j 查询封装 │ └── schemas/ │ └── chat.py # Pydantic 请求响应模型 ├── data/ │ ├── documents/ # 医疗文档 │ └── vector_store/ # 向量库持久化目录 ├── requirements.txt └── .envconfig.py使用 pydantic-settings 读取配置from pydantic_settings import BaseSettings class Settings(BaseSettings): app_name: str AI智能医疗问诊平台 neo4j_uri: str bolt://localhost:7687 neo4j_user: str neo4j neo4j_password: str 12345678 llm_base_url: str http://localhost:8001/v1 llm_api_key: str EMPTY llm_model: str qwen2-7b embedding_model: str BAAI/bge-m3 vector_store_path: str data/vector_store class Config: env_file .env settings Settings()这里的llm_base_url指向兼容 OpenAI 协议的推理服务。实际项目中可能换成本地部署的 llama.cpp 服务也可能换成云端大模型 API取决于你使用的模型服务。4.2 文档加载、切分与向量化医疗知识库可以包含 txt、md、pdf 文件。先把文档切分为适合检索的片段再做向量化。from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS def build_vector_store(doc_dir: str, save_path: str): loader DirectoryLoader(doc_dir, glob**/*.txt, loader_clsTextLoader) docs loader.load() splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ] ) chunks splitter.split_documents(docs) embeddings HuggingFaceEmbeddings( model_namesettings.embedding_model ) vector_store FAISS.from_documents(chunks, embeddings) vector_store.save_local(save_path) return vector_storechunk_size和chunk_overlap是 RAG 效果的关键参数。chunk_size500表示每段约 500 个字符chunk_overlap50表示相邻片段重叠 50 个字符避免信息被截断。医疗文档经常出现“如果出现……应立即就诊”这类关联内容分段太小容易丢失上下文。HuggingFaceEmbeddings会从 Hugging Face Hub 下载模型首次运行需要网络。如果网络受限可以改用本地 Embedding 模型或 API 方式。这里还要注意bge-m3这类模型对内存有一定要求课程设计机器建议先使用小模型如paraphrase-multilingual-MiniLM-L12-v2验证流程。4.3 知识图谱增强的检索生成链RAG 链路核心思路是“双路检索”一路查向量库一路查知识图谱最后合并结果。from langchain.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from langchain_openai import ChatOpenAI def retrieve_context(question: str): vector_docs vector_store.similarity_search(question, k3) graph_data graph_service.query_diseases_by_symptom(question) return { question: question, docs: vector_docs, graph_data: graph_data } prompt ChatPromptTemplate.from_messages([ (system, 你是医疗问诊平台的智能助手。请依据检索到的医学文档和知识图谱信息回答用户问题。回答需要给出判断依据如果信息不足请明确说明无法判断。本系统仅用于健康科普和预问诊辅助不构成医学诊断。), (human, 用户问题{question} 检索到的文档片段 {docs} 知识图谱结构化证据 {graph_data} 请组织答案并列出参考来源。) ]) llm ChatOpenAI( base_urlsettings.llm_base_url, api_keysettings.llm_api_key, modelsettings.llm_model, temperature0.2 ) def build_rag_chain(): chain ( RunnablePassthrough.assign(contextretrieve_context) | prompt | llm | StrOutputParser() ) return chaintemperature0.2是医疗问答场景的常用设置。温度越低模型生成内容越保守越倾向于依照检索上下文作答。如果设置到 0.7 以上回答会更发散这在医疗场景中不是好事。检索时k3表示取最相似的 3 个片段作为证据。片段太少会导致证据不足片段太多会超过模型上下文窗口也会引入无关内容。实际调优时可以在 3 到 8 之间测试。4.4 接口定义与统一响应格式毕业设计里接口返回格式统一是很容易加分的点。定义如下格式{ code: 0, message: success, data: { answer: 回答内容, sources: [ {type: document, title: 高血压科普.txt, score: 0.82}, {type: graph, disease: 高血压, relation: HAS_SYMPTOM} ] } }Pydantic 模型from pydantic import BaseModel, Field from typing import Optional, List class ChatRequest(BaseModel): question: str Field(..., min_length1, max_length500) session_id: Optional[str] None class SourceItem(BaseModel): type: str title: Optional[str] None disease: Optional[str] None relation: Optional[str] None class ChatData(BaseModel): answer: str sources: List[SourceItem] class ApiResponse(BaseModel): code: int 0 message: str success data: Optional[ChatData] NoneFastAPI 路由from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.core.rag import build_rag_chain, vector_store from app.core.graph import GraphService from app.schemas.chat import ChatRequest, ApiResponse, ChatData, SourceItem from app.config import settings app FastAPI(titlesettings.app_name) app.add_middleware( CORSMiddleware, allow_origins[http://localhost:5173], allow_credentialsTrue, allow_methods[*], allow_headers[*], ) graph_service GraphService( settings.neo4j_uri, settings.neo4j_user, settings.neo4j_password ) rag_chain build_rag_chain() app.post(/api/chat, response_modelApiResponse) async def chat(req: ChatRequest): answer rag_chain.invoke(req.question) sources [ SourceItem(typedocument, title医疗知识库), SourceItem(typegraph, disease高血压, relationHAS_SYMPTOM) ] return ApiResponse(dataChatData(answeranswer, sourcessources))跨域配置要特别注意allow_origins的值。前端 Vite 开发服务器默认端口是 5173如果你把端口改成 5174这里也要同步修改。生产环境还应考虑允许的来源域名范围不能直接写*。5. Vue3 前端问诊界面与联调5.1 页面结构、路由和状态管理前端页面推荐拆成三个视图ChatView.vue主问诊界面。GraphView.vue知识图谱浏览界面。HistoryView.vue历史问诊记录。在router/index.js中定义路由import { createRouter, createWebHistory } from vue-router import ChatView from ../views/ChatView.vue import GraphView from ../views/GraphView.vue const router createRouter({ history: createWebHistory(), routes: [ { path: /, component: ChatView }, { path: /graph, component: GraphView } ] }) export default router课程设计阶段会话状态可以放在前端的Piniastore 中也可以先用一个ref数组维护。不要过早引入复杂的状态管理先把主流程跑通。5.2 问诊对话组件对话组件是整个前端的核心。用户发送问题后先追加一条用户消息再调用后端接口拿到结果后追加一条助手消息。template div classchat-container div classchat-messages div v-formsg in messages :keymsg.id :class[message, msg.role] div classbubble{{ msg.content }}/div div v-ifmsg.sources msg.sources.length classsources 参考来源 span v-for(s, i) in msg.sources :keyi {{ s.type document ? s.title : s.disease }} /span /div /div /div div classchat-input el-input v-modelquestion placeholder请输入你的症状描述例如最近头晕心悸 keyup.entersendMessage / el-button typeprimary :loadingloading clicksendMessage 发送 /el-button /div /div /template script setup import { ref } from vue import { chatApi } from ../api/chat const messages ref([]) const question ref() const loading ref(false) async function sendMessage() { const text question.value.trim() if (!text || loading.value) return messages.value.push({ id: Date.now(), role: user, content: text }) question.value loading.value true try { const res await chatApi(text) messages.value.push({ id: Date.now(), role: assistant, content: res.data.answer, sources: res.data.sources }) } catch (e) { messages.value.push({ id: Date.now(), role: assistant, content: 服务暂时不可用请稍后重试。 }) } finally { loading.value false } } /script这里有个需要注意的地方chatApi返回的字段要和后端接口对应。如果后端把结果包在data.data.answer前端拿res.data.answer就会是undefined。联调前要先确认后端返回的 JSON 层级。5.3 知识图谱可视化知识图谱可视化推荐用 ECharts 的 graph 系列。使用/api/graph/search接口返回节点和关系import * as echarts from echarts function renderGraph(data) { const chart echarts.init(document.getElementById(graphChart)) const option { tooltip: {}, series: [{ type: graph, layout: force, data: data.nodes.map(node ({ name: node.name, category: node.category })), links: data.links.map(link ({ source: link.source, target: link.target })), categories: [ { name: 疾病 }, { name: 症状 }, { name: 药物 }, { name: 科室 } ], force: { repulsion: 200 } }] } chart.setOption(option) }图可视化这种功能在课程设计答辩中非常抢眼。但它依赖后端返回良好的结构化数据所以后端要先把 Cypher 查询结果转换成nodes和links两个数组前端不能直接渲染 Cypher 原始结果。6. 启动顺序、验证清单与答辩演示6.1 启动顺序与验证清单项目启动顺序很重要顺序错了会出现“前端打不开”“后端连不上 Neo4j”等连锁问题。推荐启动顺序# 1. 启动 Neo4j docker start neo4j-medical # 2. 启动模型推理服务或确保远端 API 可用 # 3. 启动后端 cd backend source venv/bin/activate uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 # 4. 启动前端 cd frontend npm run dev启动后按以下清单逐项验证验证项检查方式预期结果Neo4j 管理界面浏览器访问 7474能登录并在 Browser 中执行 Cypher后端健康检查访问/api/health或 Swagger 文档/docs返回正常 JSONSwagger 能列出接口问诊接口POST/api/chat发送测试问题返回code0且包含回答和来源知识图谱接口GET/api/graph/search?keyword头晕返回节点和关系数组前端页面访问 5173 端口页面正常渲染能发送问题并显示回答来源引用查看回答下方的来源区域展示文档标题或图谱疾病名6.2 后端接口测试的预期结果使用 curl 测试问诊接口curl -X POST http://localhost:8000/api/chat \ -H Content-Type: application/json \ -d {question: 我最近头晕心悸可能是什么问题}正常响应示例{ code: 0, message: success, data: { answer: 根据你描述的“头晕、心悸”症状可能涉及高血压、心律失常等疾病。建议先到心血管内科就诊同时注意血压监测。以上内容来自健康科普知识库不能替代专业诊断。, sources: [ {type: document, title: 高血压健康科普.txt, score: 0.82}, {type: graph, disease: 高血压, relation: HAS_SYMPTOM} ] } }如果响应不是这个结构先检查后端服务日志再检查retrieve_context函数是否正常返回了图谱数据。6.3 毕业设计演示脚本演示环节建议准备一条 5 分钟的主线脚本展示系统架构图说明哪些模块是本次独立完成。进入前端页面输入“头晕心悸”展示回答。展开来源引用说明回答不是凭空生成而是来自知识库和图谱证据。切换到知识图谱页面搜索“头晕”展示疾病、症状、科室之间的图关系。讲解 RAG 链路中 LangChain 如何编排检索和生成。讲解遇到的一个真实问题以及如何排查这比一帆风顺更有说服力。演示时最怕出现网络波动或模型服务未启动所以要准备一套“降级方案”如果模型服务不可用后端可以临时返回一条预设回答保证页面流程完整。这个逃生通道在答辩现场非常有用。7. 常见问题排查与解决方案7.1 Neo4j 连接与数据导入问题问题现象常见原因检查方式处理建议后端连接 Neo4j 超时Neo4j 容器未启动或端口映射错误docker ps查看容器状态确认容器运行检查 7687 端口映射DBeaver 执行 Cypher 报 PROLOG 错误以文件导入方式执行非 XML 内容查看错误弹窗中的文件路径改用编辑器粘贴执行浏览器管理界面打不开Neo4j 服务未启动访问 7474 端口重建容器确认日志无异常中文乱码数据文件不是 UTF-8 编码查看文件编码转存为 UTF-8 后重新导入7.2 依赖版本不匹配问题LangChain 0.3 系列中很多组件被拆分到langchain-community。只安装langchain却不安装langchain-community导入TextLoader时会报错。解决办法是统一版本号pip install langchain0.3.* langchain-community0.3.* langchain-huggingface0.1.*另外ChatOpenAI的base_url参数在不同版本中可能叫openai_api_base。如果你的代码报got an unexpected keyword argument检查当前 LangChain 版本的类签名。这种情况不要死记参数名直接看安装包里的源码或 IDE 提示。7.3 RAG 检索效果不理想检索效果不好的表现通常有三种回答完全无关retrieve_context可能没有把文档内容拼进提示词或提示词位置不对。先打印最终发送给模型的完整提示词确认上下文是否真正进入。检索到无关片段chunk_size过大导致片段语义混杂或文档本身包含过多噪声。尝试缩小到 300-500增加重叠。图谱证据没有参与回答先单独调用GraphService.query_diseases_by_symptom确认返回结果非空如果为空检查关键字归一化逻辑。调优顺序建议是先看检索结果再调参数最后改提示词。不要一上来就换大模型否则问题定位会非常困难。7.4 前端跨域、构建和打包问题开发阶段最常见的三个问题后端未配置 CORS。浏览器控制台报Access-Control-Allow-Origin错误。解决方法是 FastAPI 中加CORSMiddleware允许前端来源。Vite 端口变化后未同步后端配置。改了vite.config.js端口但后端allow_origins还是旧地址。打包后页面空白。检查vite.config.js中base是否设置为./否则部署到子目录时资源路径错误。// vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], base: ./, server: { port: 5173, proxy: { /api: { target: http://localhost:8000, changeOrigin: true } } } })配置代理后前端请求路径写/api/chat即可不需要写完整的http://localhost:8000/api/chat。这样打包部署时也不需要修改前端代码中的接口地址。8. 从课程设计到生产环境的扩展建议8.1 可复用清单系统上线前逐项检查这套结构不止能用在医疗问诊换成法律问答、产品客服、论文解读都能复用。上线前重点检查以下清单环境变量是否外置是否包含明文密钥。Neo4j 连接是否使用连接池是否在应用关闭时释放。向量库文件是否随项目正确配置启动时是重新构建还是加载已有文件。大模型接口是否设置超时、重试和异常兜底。检索结果是否限制数量避免一次请求把大量 token 塞进上下文。回答是否带来源引用是否有“无法判断”的兜底逻辑。前端是否处理接口异常页面是否有加载状态。日志是否覆盖模型调用、检索耗时、图谱查询耗时等关键环节。8.2 生产环境要补齐的能力课程设计能跑通主流程就够了但如果项目要放到生产环境需要补齐以下能力认证与权限当前接口是匿名访问生产环境要加入用户登录、会话管理和基于角色的权限控制。数据安全医疗数据属于敏感数据历史问诊记录要加密存储接口要限流和脱敏。日志与监控记录每次问诊的检索内容、模型响应、耗时用于效果分析和问题定位。测试为 RAG 链补充单元测试至少覆盖文档加载、图谱查询、接口返回格式三个部分。部署使用 Docker Compose 统一编排 Neo4j、后端、前端减少环境差异。模型管理把模型服务独立部署后端通过 API 调用避免 LangChain 直接依赖本地模型进程。8.3 后续扩展方向这个项目有三条清晰的扩展路线从单轮问答升级为多轮对话引入 LangChain 的对话记忆模块让系统能根据前文追问症状细节。从知识图谱浏览升级为智能诊断路径推荐在图谱中增加距离计算和路径搜索回答“这个疾病应该去哪个科室”时给出一条可解释的路径。从文本问答升级为多模态输入允许用户上传检查报告图片先用 OCR 抽取文本再进入 RAG 链路。对课程设计而言第一条路线投入产出比最高。多轮对话能让应用体验更真实也能在答辩时展示你对 LangChain 记忆机制的理解。建议在基础链路跑通后优先补充对话历史和追问引导功能。