☰
基于RAG与知识图谱的微信小程序AI医疗问诊平台设计
2026/10/26 2:28:04 网站建设 项目流程

今年毕设季,我连续被好几个同学问同一个题目:基于 LLM 的微信小程序 AI 医疗问诊平台,技术栈还特别统一——RAG + Spring AI + Neo4j 知识图谱 + SpringBoot + Vue3。有人问我这题能不能做,有人问我 RAG 和知识图谱到底怎么配合,还有人直接卡在第一步:Spring AI 到底怎么调通。

先说结论:这个项目能做,但它的难点不在“接入大模型”,而在“让医疗问答变得可靠”。你给用户一个聊天框很容易,但用户问“头痛、发烧、咽喉痛是什么病”时,模型不能靠感觉答,它得能从知识库里找到依据,能给出科室建议,能规避“自己判断病情”的风险。能做到这一层,你才真正理解了 RAG 和知识图谱为什么要同时出现。

这篇文章我会按照自己设计这个项目时的思路,把整体架构、知识库构建、RAG 与 Neo4j 的协作机制、小程序端注意事项、常见坑点和答辩准备路径完整拆一遍。文章里的代码片段是通用实现结构,不是某个完整开源项目的搬运,落地时要结合你的 Spring Boot 和 Spring AI 版本调整。

1. 这个项目的核心难点不在 AI,而在医疗问答的可靠性

1.1 为什么普通聊天机器人方案不适合医疗场景

如果只是做一个“能聊天”的问诊助手,方案太简单了:把大模型 API 接进来,小程序端发消息,后端转发,返回流式文本。半天就能跑通。但这只能算 demo,不能算医疗问诊平台。

医疗场景有三层要求是普通聊天机器人扛不住的:

第一,回答必须有依据。用户问“高血压日常要注意什么”,模型如果凭训练数据答,可能抓到过时信息,甚至把养生偏方当医学建议。RAG 的逻辑是先从医学知识库里检索出相关内容,再让模型基于这些内容生成答案。模型不自由发挥,回答有出处,这是医疗平台的底线。

第二,实体关系必须清晰。医疗知识不是孤立的文档,而是大量实体之间的网络关系:疾病对应哪些症状,需要做哪些检查,常用药物是什么,应该挂哪个科室。这些关系用向量检索很吃力,用知识图谱却很自然。

第三,风险边界必须可控。问诊平台不是医生,不能给确定性诊断。系统必须能识别自己不适合回答的问题,并引导用户去医院就诊。这类“拒答”和“安全提示”策略,普通 chat 接口不会主动给你实现。

所以这个题目的真正价值,不是让模型学会看病,而是设计一套“先检索、再组织、最后生成”的知识处理流程。这也是答辩时最值得展开的地方。

1.2 这个项目里 RAG 和知识图谱分别扮演什么角色

很多人把 RAG 和知识图谱搞成二选一,其实在这个系统里它们负责的是两种完全不同的能力。

RAG 处理的是非结构化知识。比如你好不容易找到的医学教材、临床指南、疾病科普文档,这些是长篇文字,适合切块后做向量化,用语义相似度做召回。用户问“饭后血糖多少算正常”,RAG 能把相关段落找出来。

Neo4j 知识图谱处理的是结构化知识。症状、疾病、检查、药物、科室是节点,它们之间的“属于”“建议检查”“常用药物”“就诊科室”是关系。用户问“持续干咳伴胸痛应该挂什么科”,系统先在图谱里定位症状节点,沿着关系找到可能疾病,再映射到科室。这个过程是精确的、可解释的,不是语义模糊的向量匹配。

理想配合方式是:RAG 负责提供大段解释性知识,知识图谱负责提供精确的实体追溯和路径解释;两者结果一起交给 LLM 去组织成用户能读懂的答案。

一句话主判断:这个项目拼的不是模型聪明不聪明,而是知识组织得好不好、检索策略设计得对不对。

2. 总体架构:一条数据流把六个技术栈串起来

2.1 先看懂请求从微信小程序到模型的完整链路

整个系统可以看作一条生产线:

  1. 用户在微信小程序里输入问题。
  2. 小程序把问题通过 HTTP 请求发给 Spring Boot 后端。
  3. Spring Boot 使用 Spring AI 的 ChatClient 与 LLM 建立对话,但在此之前,先做增强检索。
  4. RAG 模块把用户问题转为向量,从向量数据库里检索相关医疗文档片段。
  5. Neo4j 查询模块把问题里的症状实体提取出来,在图谱中查询关联疾病、科室、检查项目。
  6. 把向量检索结果 + 图谱查询结果 + 用户问题拼装成 Prompt,发送给 LLM。
  7. LLM 生成答案,后端以流式方式返回给小程序,逐字展示。

这套链路里,Spring AI 的核心价值不是“调用模型”这一个动作,而是把模型调用、Prompt 模板、向量检索、结构化数据查询统一编排在一起。如果你只是在代码里硬编码 HTTP 调用大模型 API,那 Spring AI 就没有体现出意义。

2.2 Spring AI 在这套架构里到底负责什么

先别急着写代码,你要把 Spring AI 的角色理解成“AI 应用开发框架”,不是“大模型客户端”。

它主要负责三件事:

  • 统一的模型接入层:封装 OpenAI、通义千问、DeepSeek 等模型,通过一个 ChatModel 接口调用,切换模型时不用改业务代码。
  • Prompt 与上下文管理:支持模板化 Prompt、Message 组装、历史会话记录,不用自己拼字符串。
  • RAG 组件:提供向量存储抽象、文档读取器、切分器、检索增强链等基础能力。

你说的 Spring AI 2.0,需要确认一下具体版本状态。按当前公开情况,Spring AI 1.0 已经发布,2.0 处于迭代期。如果标题写的是 2.0,建议先查一下对应里程碑版本的 Maven 坐标和 API 差异,不要照抄 1.0 教程,避免版本不兼容。

2.3 三层架构的职责边界

可以按三层来拆:

层次技术组件主要职责
前端展示层微信小程序、Vue3 管理后台问诊对话、历史记录、健康档案展示、后台知识库管理
后端服务层Spring Boot、Spring AI用户接口、会话管理、RAG 编排、图谱查询、模型调用、权限控制
数据与知识层MySQL、Neo4j、向量数据库用户数据、对话记录、知识图谱、医疗文档向量

SpringBoot 4 和 Vue3 都代表了技术栈的“新”,但你要注意:SpringBoot 4 刚发布不久,生态适配还不算完全稳定,尤其是一些第三方 starter 可能还没有跟上。选型没有问题,但毕设演示阶段要有备选方案,至少保证 Spring AI 在目标 Spring Boot 版本上能正常初始化。这个问题放到第 5 部分细说。

3. 医疗知识库构建:这是项目质量的上限所在

3.1 数据从哪来,怎么清洗

这个项目避不开一个问题:医疗数据怎么获取。我用合法、稳妥的路径给你排序。

首选是公开的医疗指南和科普文档。比如国家卫健委发布的临床路径、诊疗指南,三甲医院官网的科普文章,权威医学媒体公开的疾病百科内容。这些内容可以人工整理成文本,数量不需要多,500 到 1000 条高质量条目就足够支撑毕设演示。

其次是结构化医学公开数据集。部分高校和科研机构开放了中文医学实体识别、关系抽取数据集,可以用来构建图谱。但使用前要确认授权协议,只用于学习研究。

不建议直接爬取商业问诊平台的内容,有版权和合规风险。毕设答辩也不会因为数据来源“全”而给你加分,反而会因为来源不透明被追问。

清洗时要注意:去除页眉页脚、广告、联系方式;统一医学术语表达;保留来源链接和更新时间;把专有名词(如“高血压”)统一成标准说法。数据质量直接决定后续向量检索的效果。

3.2 RAG 切块策略:不是切得越短越好

RAG 的效果,一大半取决于切块策略。医疗文档尤其讲究上下文完整性。

我一般建议这样处理:

  • 先按章节标题切大块,保证同一个主题的内容不被打散。
  • 再按段落切块,每一块控制在 300 到 800 个中文字符之间。
  • 切块时保留文档标题、来源、章节路径作为元数据。
  • 对包含症状列表、检查指标、药物用量的段落,单独切出来,不要混在长段落里。

为什么不建议切得太短?比如切成 100 字,检索时可能召回语义相近但上下文断裂的碎片,模型拼不出完整逻辑。为什么不建议切得太长?因为向量检索的相似度计算会被大量无关信息稀释,而且超出模型上下文窗口时还得做二次截断。

注意:切块没有一劳永逸的参数。切完之后用 20 个真实医疗问题做一轮召回测试,看检索结果里前 5 条是否包含正确答案,再决定调大还是调小。

3.3 Neo4j 知识图谱怎么设计实体和关系

知识图谱不是把文档塞进 Neo4j 就完了,你需要先设计本体(Ontology)。对于医疗问诊场景,我建议先从这五类实体和五类关系起步:

实体类型示例关系类型示例
疾病高血压、2型糖尿病疾病 -> 症状高血压 -> 头晕
症状头痛、心悸、多饮疾病 -> 检查高血压 -> 血压测量
检查血常规、糖化血红蛋白疾病 -> 药物2型糖尿病 -> 二甲双胍
药物硝苯地平、阿卡波糖疾病 -> 科室高血压 -> 心血管内科
科室心血管内科、内分泌科症状 -> 可能疾病心悸 -> 心律失常

先建这么多就够支撑问诊的常见路径。Neo4j 的 Cypher 查询核心是:

// 根据症状查可能疾病和对应科室 MATCH (s:Symptom {name: '干咳'})-[r:POSSIBLE_DISEASE]->(d:Disease) MATCH (d)-[:DEPARTMENT]->(dept:Department) RETURN d.name, dept.name, r.weight

关键在于,图谱里的关系必须有来源或权重。比如“干咳”可能是感冒症状,也可能是支气管炎症状。你在关系上设置一个 weight 字段,表示这种关联的常见程度或来源权威度,检索时要排序,不能让模型把所有可能性都当等概率输出。

3.4 文档型知识和结构化知识如何并存

最常见的错误是:把文档切块后向量化,又把这些块复制到 Neo4j 里,结果两边数据冗余,查询结果互相矛盾。

更合理的方式是:

  • 文档型知识进向量数据库,用于生成答案时的参考内容。
  • 结构化关系进 Neo4j,用于精确实体定位和路径解释。
  • 两者通过“疾病名称”或“标准实体名”产生交集。

举个例子,用户问“高血压不能吃哪些食物”。RAG 可能检索到一段“高血压饮食建议”的文档,含有低盐、低脂、多果蔬等具体描述;图谱查询则找到“高血压”这个疾病节点,顺着“推荐饮食”和“避免饮食”关系返回一些结构化条目。两条路径的结果都可以塞进 Prompt,让模型综合回答。一种是内容补充,一种是逻辑约束,缺一不可。

4. 从 Demo 到可演示项目:四个关键技术实现点

4.1 Spring AI 的调用链怎么搭

在 Spring Boot 项目里引入 Spring AI 之后,通常会有这样一条调用链:

  1. 用户消息进入 Controller。
  2. Service 层先调用 RAG API 做向量检索。
  3. Service 层再调用 Neo4jService 做图谱查询。
  4. 把检索结果组装成 Prompt。
  5. 调用 ChatModel 流式生成回答。
  6. 通过 SSE 或 WebSocket 推送给小程序。

代码结构可以参考:

@Service public class ConsultationService { private final ChatModel chatModel; private final VectorStore vectorStore; private final Neo4jKnowledgeService knowledgeService; public Flux<String> ask(String userId, String question) { List<Document> docs = vectorStore.similaritySearch(question); GraphQueryResult graphResult = knowledgeService.queryBySymptom(question); Prompt prompt = buildMedicalPrompt(question, docs, graphResult); return chatModel.stream(prompt.getContents()); } }

这只是显示调用顺序,具体 API 名称和参数在不同版本里有差异。引用方式以 Spring AI 官方文档和你引入的版本为准。

4.2 RAG 与图谱的检索策略:向量先召回,图谱再约束

这里有一个很值得写进论文的策略:不把所有知识一次性塞给模型,而是分阶段召回。

比如用户问题:“我最近经常头痛,有时候还感到恶心,应该挂什么科?”

第一阶段,从问题里抽取症状实体“头痛”“恶心”。可以用 LLM 做轻量实体抽取,也可以用规则匹配。毕设场景建议先用规则匹配 + 预置症状词表,简单可控;如果效果不够,再引入 LLM 抽取。

第二阶段,把症状实体带去 Neo4j 查询。找到关联疾病后,按 weight 排序,再映射到科室。

第三阶段,把疾病名和科室名作为查询词,去向量数据库检索相关科普文档,获得更完整的背景知识。

第四阶段,组合这三个结果,送入模型。

这个策略是“先精确定位,再补充扩展”。如果反过来,先做向量召回,模型可能被大段相似但不精确的文献带偏。

4.3 微信小程序端的技术选型和展示细节

项目标题里同时写“微信小程序”和“Vue3”,这里有一个常见混淆需要澄清:微信小程序原生开发用的是 WXML/WXSS/JS,不是 Vue3 语法。如果你写 Vue3,通常指的是用 uni-app 或 Taro 这类跨端框架来生成小程序,或者 Vue3 用于后台管理端。

我建议把定位拆清楚:

  • 用户问诊端用微信小程序,不管是用原生还是 uni-app,都要做聊天式界面。
  • 管理后台用 Vue3 + Element Plus,统一管理用户、对话日志、知识库文档、图谱数据。

小程序端最影响体验的不是 UI 动画,而是流式响应。你发一句话等 10 秒才看到完整回答,用户会觉得系统很慢。要优先实现字级或句级流式展示,让用户看到模型“正在生成”。这个功能后端用 SSE 或 WebSocket,小程序端用wx.request的 enableChunked 能力或 WebSocket 接收分片,逐段追加到消息气泡里。

建议用微信开发者工具的真机预览模式调试流式效果。开发工具模拟器和真机在网络行为上经常不一致,不要等到答辩前一天才发现。

4.4 会话上下文和用户意图识别按最小可用设计

第一次做这个项目,别急着把上下文管理做得很复杂。两个原则足够:

第一,只保留最近 5 到 8 轮对话。把历史摘要和当前问题一起拼到 Prompt 里。对话超过窗口就丢弃最早的消息,避免 Token 过长。

第二,区分问诊意图和非问诊意图。比如用户发“你好”“谢谢”“你是谁”,不需要走 RAG 和知识图谱,直接由模型回答即可。可以通过关键词或轻量分类识别。如果用户问“吃什么能治癌症”这类高风险问题,要触发安全回复模板,提示“不能替代医生诊断,请及时就医”。

这些边界规则看着不复杂,但它们是医疗问诊平台区别于普通聊天机器人的关键所在。

5. 最容易翻车的四个场景和排查路径

5.1 检索结果为空或相关性差

现象:用户问题很明确,但 RAG 返回的文档片段完全不相关,或者 Neo4j 查询结果为空。

排查顺序:

  1. 先检查文本是否进入向量库。常见问题是已经执行了切块和向量化,但没有调用 store 保存,或者向量数据库服务没启动。
  2. 检查问题与文档片段的语言一致性。用户用口语,文档用书面语,可能导致语义相似度偏低。
  3. 检查知识图谱里的实体名称和用户问题里的症状名是否一致。比如用户说“头晕”,图谱里只有“眩晕”,匹配不到。
  4. 检查 Neo4j 服务地址、账号密码、数据库名称是否对得上。开发环境最容易忽略 Neo4j 默认数据库是neo4j,如果你新建了medical.db又没切换,查不到任何数据。

对于匹配不到的问题,最实用的解决办法是维护一个“同义词表”或“别名表”,把口语化表达映射到标准术语。比如“脑袋疼”映射到“头痛”。

5.2 模型幻觉:回答与检索内容不一致

现象:检索结果明明说“高血压患者每日盐摄入量应低于 5 克”,模型生成时却写成“可以不限盐”。

排查路径:

  1. 检查 Prompt 是否明确约束了“只能基于给定知识库内容回答”。Spring AI 的 System Prompt 可以写成固定模板,去掉模型自由发挥的空间。
  2. 检查是不是检索到的内容太多了,模型抓不住重点。适当减少 Top-K 返回数量,比如从 10 条降到 5 条。
  3. 检查模型温度参数。医疗场景建议把 temperature 调低到 0.2 以下,或直接设置为 0。温度越高,回答随机性越强,不适合医疗场景。
  4. 检查是否有多个矛盾来源同时被召回。比如一篇文档说“高血压标准是 140/90”,另一篇说“新版标准是 130/80”,模型可能综合出错误结论。这需要在数据清洗时统一标准,或在 Prompt 里要求“如果存在矛盾,提示信息需要进一步确认”。

5.3 版本不兼容:Spring AI、Spring Boot、Neo4j 驱动互相打架

这个项目最容易卡住的地方不是业务逻辑,而是启动阶段报错。

排查顺序:

  1. 先确认 Spring Boot 版本和 Spring AI 版本的兼容关系。Spring AI 官方文档通常会在 Release Notes 里标明支持的 Spring Boot 版本范围。
  2. Neo4j 驱动版本要和 Neo4j 服务端版本匹配。比如 Neo4j 4.x 对应旧驱动,Neo4j 5.x 需要更新驱动,这个不能混。
  3. 向量数据库组件选型要提前确认。Spring AI 提供了多种向量存储适配器,本地开发建议先用轻量级实现,比如基于内存的 SimpleVectorStore,避免一开始就引入复杂中间件。
  4. 如果使用 Docker 安装 Neo4j,要确认容器内部端口和宿主机端口的映射关系,连接失败常常是端口没映射对。
# 常见 Docker 启动 Neo4j 的命令结构 docker run -d \ --name neo4j-medical \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTH=neo4j/yourpassword \ neo4j:5.26

不同 Neo4j 版本的镜像 tag 不一样,启动前用docker images和docker ps检查容器状态。

5.4 小程序端白屏、报错、无法访问接口

排查顺序:

  1. 先看微信开发者工具的 Network 面板,确认请求是否发出、响应码是多少。注意开发环境中关闭“不校验合法域名”前要确认你只是本地调试。
  2. 检查本地开发服务器是否监听在小程序可访问的地址上。不能只监听 127.0.0.1,真机调试时手机访问不到本机 localhost。
  3. 检查小程序端是不是用了未编译的 npm 包。小程序不支持直接 require 所有 Node.js 包,需要先构建 npm。
  4. 检查页面栈。微信小程序页面跳转层级过深时,用wx.navigateTo会失效,需要改用wx.redirectTo或wx.reLaunch,这是关键词里出现pageindex和“分包异步化”时最常关联的问题。问诊对话页要考虑分包加载,避免主包体积超限。

6. 从毕设题目到能演示的项目,还需要走完哪几段路

6.1 第一优先级:先把最小闭环跑通

不要一上来就想着做完整平台。推荐顺序是:

  1. 后端先写一个最简单接口,直接调用 ChatModel 返回一句话。
  2. 小程序端展示这句话,确认网络通路正常。
  3. 引入 Spring AI 的向量能力,手动放入 20 篇医疗文档,做一次检索测试。
  4. 在 Neo4j 里建 50 个疾病节点和 200 条关系,手工写 Cypher 查询,确认能查到科室。
  5. 把检索结果拼进 Prompt,让模型说出答案和参考来源。
  6. 最后再做流式、历史记录、后台管理。

每完成一步都保留一个可演示的截图或录屏,写论文和答辩 PPT 时都需要这些过程材料。

6.2 第二优先级:在“玩具”和“毕设系统”之间补齐差距

演示时,很多人一眼就能看出项目是纯 demo 还是完整系统。差距通常体现在:

  • 用户登录和会话隔离。至少要有 openId 绑定、会话表、历史记录表。
  • 知识库管理页面。允许管理员上传文档进行切割、向量化,并查看状态。
  • 对话日志。记录用户的每次提问、系统回答、检索命中的文档 ID。这个记录既是调试工具,也是论文里的测试数据来源。
  • 错误兜底。模型调用失败时,返回固定提示,而不是空白或报错。

6.3 答辩时最可能被追问的几个问题

提前准备好这几个问题的答案,比背稿更有用:

  1. 为什么用 RAG 而不是微调模型?答:医疗知识更新快,RAG 可以随时更新知识库而无需重新训练模型;且 RAG 能附来源,可解释性更强。
  2. 为什么还需要知识图谱?答:很多问诊问题本质上是实体关系查询,图谱路径清晰可解释,能纠正纯语义检索的模糊性。
  3. 如果用户问的问题在知识库里查不到怎么办?答:先触发拒答模板,告知无法提供确定性建议,引导前往正规医疗渠道。
  4. 如何评估回答质量?答:建立了测试集,包含 50 个常见医疗问题,分别评估检索召回率和回答正确率。虽然不够完整,但能证明系统具备效果验证能力。

6.4 对毕设项目使用 LLM 的几条实在建议

第一,模型选择没必要追求最大最强。用国内大模型 API 或开源模型部署都能完成项目,优先选文档完善、接入方便的。毕设评分看的是系统设计、工程完整度和对问题理解的深度,不是模型推理分数。

第二,本地部署大模型不是必选项。如果你的机器不支持,就老老实实走 API 方案。需要展示“本地化”能力时,可以说明模型层被 Spring AI 抽象,后续可无缝切换到本地部署模型。

第三,所有外部服务和数据集,都要在论文里注明来源。既体现学术规范,也避免答辩评审追问来源时语焉不详。

收尾:先解决知识组织,再谈模型强弱

这个题目很容易让人误以为“AI 医疗问诊 = 接入大模型 + 聊天气泡”,但真正把系统做完后你会发现,大模型只是最后一步的生成器,前面还有知识清洗、切块、向量化、图谱建模、检索策略、安全兜底、流式链路。项目质量的高下,不取决于模型多聪明,而取决于你让模型站在多少真实、可靠、有结构的医学知识之上。

再提醒一句:开工时别急着调参数、写炫酷界面。先把一条最简单的问题问答链路完整打通,再逐步叠加 RAG 和图谱。链路畅通了,后面所有优化才有意义。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询