
简介本资源面向医疗人工智能开发者、心内科临床科研人员及RAG与多智能体方向的学习者提供一套基于检索增强生成与多智能体协同架构的心内科疾病智能诊断系统开发项目。项目通过检索医学文献与案例库结合心电图、超声心动图、生化指标等临床数据生成个性化诊断建议并由多个智能体分工完成数据整理、风险评估与治疗方案生成解决心内科疾病诊断效率与准确率问题。压缩包共23个文件包含11个json病例与配置数据、10个pdf权威指南与文献、1个txt说明及1个md文档整体约12.58MB目录结构清晰便于按模块查阅。已有68人学习下载。读者可获得完整的项目架构思路、病例数据样例、医学知识语料与系统说明文档适合用于课程设计、科研复现或医疗AI应用开发参考。1. 心内科诊断系统拆包RAG 加多智能体到底怎么落地心内科门诊有个老大难问题一份完整诊断要同时看心电图、超声报告、化验单、既往病史和用药记录年轻医生漏掉一个矛盾点就可能误判。这个项目把 RAG 检索增强生成和多智能体协同架构拼在一起做了一套面向心内科疾病的自动化诊断分析系统。它不是那种跑个 demo 就完事的玩具而是把知识库检索、多角色智能体分工、诊断推理链完整串起来的工程包。适合谁看正在做医疗 AI 落地、想搞懂 RAG 在垂直领域怎么调、或者需要一套多智能体协作参考架构的开发者。下面我按拆包顺序讲清楚它怎么用、参数怎么设、坑在哪。2. 环境搭建与知识库构建从零把 RAG 管道跑通2.1 依赖安装与目录结构确认拿到压缩包先别急着 pip install第一步是确认目录结构。这类项目通常把知识库、智能体定义、推理链配置分开放目录乱了后面调试会很痛苦。常见做法是解压后先 tree 一下看层级# 解压后查看目录结构确认知识库和智能体模块位置 unzip rag_cardio_multiagent.zip -d ./cardio_dx cd cardio_dx find . -maxdepth 2 -type d | sort执行后会看到类似data/knowledge_base/、agents/、configs/、pipelines/这样的分层。data/knowledge_base/放的是心内科指南、药品说明书、心电图判读标准等原始文档agents/下是各个智能体的角色定义和提示词模板configs/里是检索参数和模型配置。确认这三块齐全再往下走缺一个后面都跑不通。依赖安装建议用虚拟环境隔离医疗项目经常锁版本直接装全局容易和现有环境打架python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txtrequirements.txt里一般会锁 langchain、chromadb 或 faiss、sentence-transformers 这几个核心包。如果安装过程中 faiss 编译报错Linux 下先装libopenblas-devMac 上直接用faiss-cpu的预编译轮子。这一步翻车最多血泪经验是别用最新版按 requirements 里锁的版本来。2.2 知识库向量化与索引构建RAG 的核心是检索质量检索质量取决于知识库怎么切、怎么嵌入。心内科文档有个特点指南类文档段落长、逻辑连贯化验参考值又是表格碎片。一刀切按固定长度切会破坏语义常见做法是按文档类型分别处理。from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma import os # 心内科指南用较大 chunk保留完整推理链 guideline_splitter RecursiveCharacterTextSplitter( chunk_size800, # 指南段落长chunk 给大一点 chunk_overlap150, # 重叠 150 字防止跨段逻辑断裂 separators[\n\n, \n, 。, ] ) # 化验单、药品说明用较小 chunk提高检索精度 lab_splitter RecursiveCharacterTextSplitter( chunk_size300, chunk_overlap50, separators[\n, 。, , ] ) def build_index(doc_dir, splitter, persist_dir): docs [] for fname in os.listdir(doc_dir): with open(os.path.join(doc_dir, fname), encodingutf-8) as f: text f.read() chunks splitter.split_text(text) docs.extend(chunks) embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-base-zh-v1.5 # 中文医疗语料上表现稳 ) vectordb Chroma.from_texts( textsdocs, embeddingembeddings, persist_directorypersist_dir ) vectordb.persist() return vectordb build_index(data/knowledge_base/guidelines, guideline_splitter, ./db/guidelines) build_index(data/knowledge_base/labs, lab_splitter, ./db/labs)这里的关键参数是chunk_size和chunk_overlap。指南类文档 chunk 给到 800 是因为心内科诊断往往需要一整段推理切太碎检索出来的是半句话智能体没法用。化验单给 300 是因为参考值本身就是短条目切大了反而引入噪声。嵌入模型选bge-base-zh-v1.5是常见做法中文医疗语料上比通用模型召回率高出一截。两个索引分开建检索时按问题类型路由到不同库这是提升 RAG 精度的实用技巧。提示建索引前先清洗文档把页眉页脚、扫描噪声去掉。医疗 PDF 转文本经常带一堆乱码不清洗会污染整个向量库。2.3 检索器配置与召回测试索引建好不等于能用得先验证召回质量。这一步很多人跳过结果智能体诊断时引用了一堆无关内容还以为是提示词问题。from langchain.retrievers import EnsembleRetriever from langchain.retrievers import BM25Retriever # 向量检索 关键词检索混合医疗术语精确匹配很重要 vector_retriever vectordb.as_retriever( search_typemmr, # MMR 兼顾相关性和多样性 search_kwargs{k: 5, fetch_k: 20, lambda_mult: 0.7} ) bm25_retriever BM25Retriever.from_texts(all_chunks) bm25_retriever.k 5 ensemble EnsembleRetriever( retrievers[vector_retriever, bm25_retriever], weights[0.6, 0.4] # 向量为主关键词兜底 ) # 召回测试 test_queries [ 射血分数降低的心衰患者β受体阻滞剂如何使用, ST段抬高型心肌梗死急诊再灌注时间窗 ] for q in test_queries: results ensemble.get_relevant_documents(q) print(fQuery: {q}) for r in results[:2]: print(f - {r.page_content[:80]}...)search_typemmr里的lambda_mult控制多样性0.7 表示偏向相关性。医疗场景下宁可多召回几条也不能漏掉关键信息所以fetch_k给到 20 再精选 5 条。混合检索的权重 0.6/0.4 是经验值向量擅长语义匹配BM25 擅长精确术语如β受体阻滞剂这种两者互补。测试查询要覆盖典型心内科场景如果召回结果里出现无关科室内容说明 chunk 或嵌入模型需要调。3. 多智能体协同架构角色分工与诊断推理链3.1 智能体角色定义与提示词设计这套系统的核心不是单个大模型而是多个智能体各司其职。常见做法是分四个角色病史采集智能体、检查判读智能体、鉴别诊断智能体、用药审核智能体。每个智能体有自己的系统提示词和可调用的工具集。from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.prompts import ChatPromptTemplate # 检查判读智能体负责心电图、超声、化验单解读 ecg_agent_prompt ChatPromptTemplate.from_messages([ (system, 你是心内科检查判读专家。你的任务是根据提供的检查数据 和检索到的判读标准给出客观的检查结论。规则 1. 只基于检索到的指南和提供的检查数据下结论 2. 不确定的指标标注需人工复核 3. 输出格式检查项目 | 结果 | 判读依据 | 置信度 4. 发现危急值时优先标记), (human, {input}), (placeholder, {agent_scratchpad}) ]) ecg_agent create_openai_tools_agent(llm, tools[retriever_tool], promptecg_agent_prompt) ecg_executor AgentExecutor(agentecg_agent, tools[retriever_tool], verboseTrue)提示词里最关键的是约束条件。医疗场景不能让模型自由发挥只基于检索到的指南这条必须写死否则它会凭训练记忆编造。输出格式固定成表格结构方便下游智能体解析。置信度字段是给最终审核用的低置信度的结论会被标记出来。每个智能体的提示词都要单独调别指望一套提示词打天下。3.2 智能体间通信与诊断链编排多个智能体怎么协作是这套架构的难点。常见做法是用一个有向图编排病史采集 → 检查判读 → 鉴别诊断 → 用药审核每个节点的输出作为下一个节点的输入。但心内科诊断不是纯线性的鉴别诊断可能需要回头补充检查所以要有条件分支。from langgraph.graph import StateGraph, END from typing import TypedDict, List class DxState(TypedDict): patient_info: str exam_results: List[str] differential: List[str] medication_plan: str need_recheck: bool def collect_history(state): result history_executor.invoke({input: state[patient_info]}) return {patient_info: result[output]} def interpret_exams(state): result ecg_executor.invoke({input: state[patient_info]}) return {exam_results: [result[output]]} def differential_dx(state): combined state[patient_info] \n \n.join(state[exam_results]) result dx_executor.invoke({input: combined}) # 如果鉴别诊断置信度低触发重新检查 need_recheck 需人工复核 in result[output] return {differential: [result[output]], need_recheck: need_recheck} def route_after_dx(state): if state[need_recheck]: return recheck return medication workflow StateGraph(DxState) workflow.add_node(history, collect_history) workflow.add_node(exams, interpret_exams) workflow.add_node(dx, differential_dx) workflow.add_node(medication, medication_review) workflow.set_entry_point(history) workflow.add_edge(history, exams) workflow.add_edge(exams, dx) workflow.add_conditional_edges(dx, route_after_dx, { recheck: exams, # 回退补充检查 medication: medication }) workflow.add_edge(medication, END) app workflow.compile()这段编排逻辑里route_after_dx是灵魂。如果鉴别诊断智能体发现证据不足会触发回退到检查判读节点形成闭环。这比单向流水线靠谱得多因为真实诊断就是反复验证的过程。need_recheck标志位从输出里解析简单但有效。状态用 TypedDict 管理每个节点只改自己负责的字段避免互相污染。注意智能体循环要有次数上限否则可能陷入检查-诊断-再检查的死循环。在 route 函数里加个计数器超过 3 次强制进入用药审核。3.3 诊断结果聚合与置信度评估四个智能体跑完后最终输出需要聚合。不是简单拼接而是要做一致性检查。比如检查判读说左室射血分数 35%鉴别诊断说心衰可能性大用药审核开了β受体阻滞剂这三者逻辑自洽。如果出现矛盾系统要标记出来。def aggregate_diagnosis(state): # 提取各智能体结论 exam_conclusion state[exam_results][-1] dx_conclusion state[differential][-1] med_conclusion state[medication_plan] # 一致性检查关键指标是否在诊断中被引用 consistency_flags [] if 射血分数 in exam_conclusion and 心衰 not in dx_conclusion: consistency_flags.append(EF值异常但诊断未提及心衰) if 禁忌 in med_conclusion and 禁用 not in dx_conclusion: consistency_flags.append(用药禁忌未在诊断中标注) return { final_report: { 检查判读: exam_conclusion, 鉴别诊断: dx_conclusion, 用药方案: med_conclusion, 一致性标记: consistency_flags, 整体置信度: 高 if not consistency_flags else 中需人工复核 } }一致性检查的规则要根据心内科诊疗规范来定上面只是示例。实际项目中这部分规则库需要和临床医生一起梳理把常见的矛盾场景都覆盖到。整体置信度分三档高、中、低。有矛盾标记的一律降档强制人工介入。这套机制的价值在于它不追求全自动而是把医生的精力集中在真正需要判断的病例上。4. 避坑与排查这套架构最容易翻车的五个地方4.1 检索召回率低智能体答非所问现象智能体诊断时引用的指南内容和问题不相关比如问心衰用药却召回高血压指南。原因通常是嵌入模型对医疗术语区分度不够或者 chunk 切分破坏了语义完整性。解决先换用医疗领域微调过的嵌入模型比如在中文医疗语料上继续训练过的 bge 变体然后检查 chunk 切分逻辑指南类文档确保每个 chunk 包含完整的推荐意见证据等级。如果还不行加一层关键词过滤把科室标签作为元数据存进向量库检索时先按科室过滤。4.2 智能体之间信息传递丢失现象检查判读智能体输出了ST段抬高但鉴别诊断智能体完全没提这件事。原因是智能体间传递的是自然语言文本下游智能体可能忽略关键信息。解决在状态里用结构化字段传递关键指标不要只传文本。比如exam_results里除了文本结论再加一个critical_findings列表把危急值单独拎出来。下游智能体的提示词里明确要求必须逐一回应上游标记的危急值。4.3 提示词里的规则被模型忽略现象提示词写了不确定的标注需人工复核但模型输出里一个标注都没有。原因是规则太多、太靠后模型注意力被稀释。解决把最重要的规则放在提示词最前面和最后面中间放格式要求。医疗场景下规则不要超过 5 条多了模型记不住。另外可以用 few-shot 示例给一两个正确输出的样例比纯文字规则有效得多。4.4 向量库更新后检索结果突变现象往知识库加了一批新指南结果原有查询的召回结果全变了。原因是 Chroma 或 FAISS 在增量添加时可能重建索引导致向量空间偏移。解决知识库更新走全量重建流程不要增量插入。建索引时固定随机种子嵌入模型版本锁死。如果必须增量用支持增量索引的向量库并且每次更新后跑一遍回归测试用固定的测试查询集验证召回结果是否稳定。4.5 多智能体循环导致响应超时现象一个病例跑了 5 分钟还没出结果日志显示智能体在反复循环。原因是条件分支没有终止条件或者某个智能体一直输出需复核触发回退。解决在编排层加全局步数计数器超过阈值强制跳出。每个智能体的输出里加一个confidence字段低于阈值才触发回退而不是只要出现需复核就回退。另外给每个智能体设超时单个智能体超过 30 秒直接返回当前结果并标记超时。5. 进阶技巧用结构化知识库补 RAG 的短板纯向量检索有个天然短板它擅长模糊匹配不擅长精确推理。比如肌钙蛋白 0.5 ng/mL 结合胸痛 2 小时STEMI 可能性多大这种问题向量检索只能召回相关段落没法做数值计算和逻辑推演。我一般会在这套架构上再叠一层结构化知识库把指南里的诊断标准转成规则引擎。# 把心内科诊断标准转成结构化规则 diagnostic_rules { STEMI: { conditions: [ {field: troponin, operator: , value: 0.04, unit: ng/mL}, {field: chest_pain_duration, operator: , value: 20, unit: min}, {field: ecg_st_elevation, operator: , value: True} ], logic: AND, confidence: 0.95 }, NSTEMI: { conditions: [ {field: troponin, operator: , value: 0.04, unit: ng/mL}, {field: ecg_st_elevation, operator: , value: False}, {field: ecg_st_depression, operator: , value: True} ], logic: AND, confidence: 0.85 } } def rule_based_screen(patient_data): matches [] for dx_name, rule in diagnostic_rules.items(): results [] for cond in rule[conditions]: val patient_data.get(cond[field]) if val is None: results.append(False) continue if cond[operator] : results.append(val cond[value]) elif cond[operator] : results.append(val cond[value]) if rule[logic] AND and all(results): matches.append({diagnosis: dx_name, confidence: rule[confidence]}) return matches这层规则引擎和 RAG 是互补关系。规则引擎负责精确匹配诊断标准输出高置信度的候选诊断RAG 负责召回指南原文和用药建议给候选诊断提供依据。两者结果一起喂给鉴别诊断智能体它的任务变成验证规则引擎的候选诊断是否合理并补充规则没覆盖到的鉴别点。这样既保留了 RAG 的灵活性又补上了精确推理的短板。验证方法也简单准备一批脱敏的模拟病例每个病例有明确的最终诊断跑一遍系统看规则引擎和 RAG 的联合输出是否命中。重点看两类错误规则引擎漏诊但 RAG 召回了相关指南说明规则需要补充以及规则引擎误诊但 RAG 没纠正说明鉴别诊断智能体的提示词需要加强。这个回归测试集要持续维护每加一条新规则就跑一遍。从那以后我每次搭 RAG 加多智能体的系统都强制先跑一遍召回测试和规则引擎的单元测试再让智能体上场。这两步花不了半小时但能省掉后面几天的排查时间。希望帮到你。本文还有配套的精品资源点击获取