1. 为什么医疗RAG项目的成败,八成都埋在前两段数据的坑里
做了几个医疗RAG相关的项目之后,我有一个很深的体会:大家聊起RAG,第一反应总是要选什么大模型、怎么调提示词、用哪个向量数据库,但真正让项目翻车的地方,几乎全在数据准备和预处理环节。医疗场景比通用领域更苛刻,因为知识库里的文件来源五花八门——有的是院内信息系统导出的结构化文本,有的是扫描版的纸质指南,有的是带复杂表格的药品说明书,还有的是医生手写病历的OCR结果。这些数据如果不经过严格清洗、切分、向量化处理,检索阶段的召回质量就直接崩盘,后续生成阶段再怎么调都无济于事。
这篇文章想讲的,是我在构建"智慧医疗RAG系统"时,前端数据准备与预处理这一整套流程里真正落地过的做法。内容会覆盖知识库的摸底与采集、文本清洗的难点、切分策略的设计、向量化与召回质量、质检方案,以及知识库的持续更新与治理。适合正在做医疗领域知识问答、辅助诊疗、临床文档检索等方向的工程师和产品同学参考,也适合医疗信息化从业者了解RAG系统的数据侧到底在解决什么问题。
先给一个总体的判断:在医疗RAG项目里,数据采集、清洗、切分、向量化、质检这几个环节加在一起,占掉了我大概八成的工作时间。并不是说模型不重要,而是说,如果数据侧没有做好,模型再强都只能"在错误的信息之上生成流畅的废话"。下面按我实际推进项目的顺序,把每一个环节的关键点和踩过的坑拆开讲。
1.1 医疗知识库不是"一堆文件",而是三类异构数据的混合
一个真实的医疗RAG知识库,通常由三类数据混合而成。
第一类是高度结构化的数据,比如检验检查结果、诊断编码、药品字典、手术记录字段。这类数据通常从院内系统导出,有明确的字段名和值,处理起来相对简单,主要问题是字段口径不统一、不同系统之间编码不一致。
第二类是半结构化的文档,比如药品说明书、临床指南、专家共识、操作规范。这类数据有章节结构,但具体格式差异很大——PDF、Word、扫描件都可能存在,表格和正文混排的情况非常普遍,是最考验预处理能力的一类。
第三类是完全非结构化的文本,比如医生书写的病历、出院小结、护理记录、会诊意见。这类文本风格高度个人化,口语化表达多,缩写多,错别字多,而且经常夹杂时间线、数值和科室信息,想在切分后保持语义完整非常难。
我见过不少团队在项目启动时,直接把所有PDF往解析工具里一丢,然后就开始接大模型。结果上线之后,用户问"高血压患者的用药禁忌",系统召回来的内容是指南的目录页,或者是一张被切碎的药物相互作用表格。问题的根源不在模型,而在数据准备阶段没有对这三类数据分别设计处理策略。
1.2 先想清楚检索是给谁用、答什么题,再做数据
医疗RAG的项目目标千差万别,数据准备的优先级也会完全不同。比如面向患者的知识问答,知识库以药品说明书、疾病科普、就医流程为主,对语言的通俗性要求高;面向临床医生的辅助决策,知识库以指南、共识、最新文献为主,对时效性和证据等级要求高;面向医务管理人员的制度问答,知识库以院内规章制度、操作流程为主,对版本和适用范围要求高。
我踩过的一个坑是:项目一开始没想明白使用场景,数据侧一上来就追求"多多益善",把院内各种资料全部灌进知识库。结果检索时不同来源的文档互相打架——2019版的指南和2024版的指南同时被召回,生成侧不知道该信谁。后来我们改成按使用场景拆分知识库,每个知识库独立预处理、独立索引、独立更新,检索时按场景路由,这个问题才解决。
所以我强烈建议,在动数据之前,先回答三个问题:这个系统的用户是谁?他们最常问的十类问题是什么?每个问题对应的权威知识来源在哪里?答案出来之后,再决定采集哪些数据、优先处理哪些数据、按什么标准做清洗。数据准备不是为了把文件"塞进"系统,而是为了支撑特定的回答质量目标。
2. 数据来源摸底:先搞清楚知识库里到底有什么
很多医疗数据资产散落在不同科室、不同系统、不同人手里。要想构建一个可靠的知识库,第一件要做的事不是清洗,而是摸底。
2.1 典型医疗知识资产的类型与更新节奏
我在实际项目中,把医疗知识库的常见来源整理成了一张表,供团队和院方沟通时使用:
| 知识类型 | 典型格式 | 更新节奏 | 处理难点 |
|---|---|---|---|
| 临床诊疗指南 / 专家共识 | PDF为主,偶尔有Word | 每2~5年更新 | 扫描版多,表格多,版本易混淆 |
| 药品说明书 | PDF、网页 | 随药品审批动态更新 | 项目符号多,【适应症】【用法用量】结构不一 |
| 检验检查报告模板与参考范围 | 系统导出的结构化文本 | 按设备/试剂变更 | 数值范围、单位和参考值容易不一致 |
| 病历文书(出院小结、会诊意见等) | 电子病历系统导出 | 持续产生 | 风格口语化,缩写多,隐私信息密集 |
| 医学教材、专著章节 | PDF / 扫描件 | 数年至数十年 | 体量大,重叠章节多 |
| 院内制度和操作流程 | Word / PDF | 不定期修订 | 版本管理混乱,旧版易混入 |
| 科研文献摘要 | XML / PDF | 持续更新 | 术语密度高,引用关系复杂 |
这张表的价值在于:它让我们在项目一开始就和院方确认了知识来源的边界和优先级,而不是等系统建好之后再返工。比如某医院的信息科同事一开始想接入所有历史病历,但我们评估后发现病历文书隐私风险高、文本质量参差不齐,短期对问答质量帮助有限,于是先把优先级放在了指南、药品说明书和制度文档上,病历类知识留到后期专门做脱敏和清洗后再接入。
2.2 从原始文件到可处理文本的解析路线
摸底之后,就是文件解析。这一步的技术含量不高,但决定了后续所有环节的上限。不同来源的文件,解析策略完全不同:
- 带文本层的PDF:直接抽取文本即可,但要注意页眉页脚、水印、页码混入正文的问题。我通常会对每一页做版面分析,先把页眉页脚区域剔除,再进入正文抽取。
- 扫描版PDF或图片:必须走OCR。医疗文档里的专业术语多,尤其涉及化学式、计量单位、上下标时,通用OCR模型的识别率不够。最好用专门训练过医疗文本的OCR模型,或者对识别结果做一轮术语纠错。我遇到过把"mg/dL"识别成"mgIdL"的情况,如果清洗环节不处理,检索时用户输入"mg/dL"就很难命中。
- 带复杂表格的文档:不要用纯文本抽取,那会把表格打散成一行行的碎片。正确做法是先做版面还原,恢复表格行列关系,再把每个单元格的内容按"表头+行标签+单元格值"的方式转成结构化文本。比如一张"药物相互作用表",要转成"{药物A}与{药物B}同用时可能出现{不良反应},建议{处理措施}"这样的描述文本,而不是一堆散落的单元格坐标。
- 导出的电子病历:这类数据通常在信息系统里本来就是结构化的,导出后反而丢失了结构。如果预算和时间允许,尽量从数据库直接读取,或者协调信息科提供结构化的中间表,省去后面大量清洗工作。
2.3 采集阶段就要定下的三个规范
很多团队在采集阶段只顾着"把文件搬过来",结果后续清洗时才发现文件命名混乱、版本不明、来源不清。我建议在采集阶段就顺手立下三个规范:
第一,文件层面统一命名。推荐格式是"《文档名》_版本号_发布时间_来源科室",例如"《高血压基层诊疗指南》_2024版_202401_心内科.pdf"。这样即使后面混入了旧版本文件,从文件名就能识别出来。
第二,元数据随文件走。每个文件在入库时就要记录来源类型(指南、说明书、病历等)、发布机构、发布时间、适用人群、整理责任人等字段。这些元数据后面会作为过滤条件和展示信息,比如系统回答时可以明确标注"依据2024年发布的某指南,而非2019年版本"。
第三,来源去重和版本核对。同一份指南可能从不同渠道拿到不同版本,需要以来源机构公开发布的版本为准做归一化处理。我通常会做一个简单的文档指纹比对,对重复度高的文档做人工确认,避免同一个知识点在知识库里被重复索引导致检索结果分裂。
3. 清洗阶段最容易翻车的三类问题:表格、单位、脱敏
采集和解析做完之后,原始文本的质量往往还不能直接用于RAG。医疗文本的清洗比通用文本清洗更棘手,我挑三个最容易翻车的方向展开说。
3.1 表格类医学资料的正确打开方式
表格是医疗文档里最常见的"信息炸弹"。一张药物相互作用表、一张生化指标参考范围表、一张分期评估表,信息密度极高,而且表格里随便一个单元格单独拎出来都没有意义——必须结合行标题和列标题才能理解。
我在处理表格时走过弯路。最初的做法是把表格转成Markdown格式塞进切块里,看起来保留了结构,但实际检索效果很差。后来我改用"表格语义化"的方式:把每个有实际含义的单元格组合成一句完整的自然语言描述。
拿一张检验参考范围表来说,原始表格大概长这样:
项目 标本 参考范围 备注 ALT 血清 0-40 U/L - AST 血清 0-45 U/L - 肌酐 血清 44-104 μmol/L 男我不会把这个表格直接扔给向量模型,而是做一层转换,生成这样的文本块:
检验项目ALT,标本为血清,参考范围为0-40 U/L。 检验项目AST,标本为血清,参考范围为0-45 U/L。 检验项目肌酐,标本为血清,男性参考范围为44-104 μmol/L。这样做的原因很简单:RAG的向量模型擅长对自然语言句子计算相似度,而对二维表格的语义理解非常差。用户问"ALT的正常值是多少",自然语言描述"ALT参考范围0-40 U/L"和查询的语义距离,远比一张Markdown表格要近得多。当然,这个转换过程要尽量自动化——逐行读取表格、按行拼接字段,同时保留"性别分层""年龄分层"等条件,必要时人工检查一遍高风险表格。
3.2 单位、缩写、数值范围的归一化
医疗知识库里大量存在"同一含义、不同写法"的情况。最常见的三个坑是:
- 计量单位不统一:血糖有"mmol/L"和"mg/dL"两种表示法,肌酐有"μmol/L"和"mg/dL",钙有"mmol/L"和"mg/dL"。同一份资料里可能混用,不同来源之间更是经常不一致。我建议在清洗时建立一套"单位归一化表",将单位统一换算为院内常用标准,并且在文本中保留一个括号标注的原始单位,例如"血糖 5.6 mmol/L(约101 mg/dL)"。
- 缩写和全称并存:"高血压"对应"HTN","充血性心力衰竭"对应"CHF","非甾体抗炎药"对应"NSAIDs"。清洗阶段我会维护一份术语词典,在文档入库时对缩写的首次出现位置补全全称,同时在全文保留缩写。这样无论用户用缩写还是全称提问,检索阶段都有更大的命中概率。
- 范围表达方式多样:"40-50岁""40到50岁""40~50岁""40~50岁"其实是同一个意思。如果文本里混用了不同的区间符号,用户检索"40-50岁适用人群"时召回就会不稳定。统一符号是小事,但很有必要。
做完这些归一化之后,我还会做一遍"数值完整性检查",专门看那些本来应该带数值的段落是不是在清洗过程中被误删了。比如药物剂量描述里"{商品名}每片含XXmg"如果被清洗工具误当成广告语删掉,后果就很严重。所以医疗数据的清洗规则一定要"保守",可删可不删的坚决不删。
3.3 隐私脱敏:宁多勿漏的两个兜底手段
医疗文本的隐私问题是高压线,尤其是病历、检查报告这类数据。清洗阶段必须做脱敏,但脱敏这件事光靠正则表达式是不够的。
我常用的脱敏方案分两层:
第一层是规则脱敏。用正则匹配身份证号、手机号、电话号码、住院号、邮箱、银行卡号等模式,直接替换为占位符。
第二层是模型辅助识别。规则覆盖不了的是姓名、科室+医生姓名、地址这类自由文本里的实体。我会用一个命名实体识别模型对全文跑一遍,把识别出的人名、地名、机构名再替换掉。注意这里的模型不需要是很大的模型,准确率够用就行,宁可把"疑似有人名"的片段标记出来让人工确认,也不能漏掉真实隐私信息。
我在实操中还有一个兜底方案:直接放弃高风险数据。如果某一批病历文本脱敏成本极高、风险极大,而且对问答质量贡献有限,我倾向于不把它们放进知识库。医疗场景里,数据安全的分量重于功能完整性,这个取舍值得做。项目上如果实在需要病历问答功能,我会建议单独做一个小范围的内网版,从物理层面隔离隐私风险。
另外一个容易被忽略的细节:脱敏不要只发生在入库前,也要在生成阶段做好防护。因为大模型可能会把用户问题里的上下文和知识库文本拼接后原样输出,如果知识库里的文本没有脱敏干净,隐私信息就会被"漏"出去。所以我会在输出侧也加一道隐私检测,发现可疑内容就直接遮罩。
4. 切分策略:按"检索友好"切,而不是按"阅读友好"切
切分是整个人数据准备流程里最核心、最值得反复打磨的环节。因为RAG系统检索的最小单元是"切块"而不是"整篇文档",切出来的块质量直接决定了召回质量。
4.1 固定长度切分在医疗文本上为什么不行
很多RAG教程会告诉你"按固定token数切块,块之间加重叠",这种方案在通用文本上勉强能用,但在医疗文本上几乎必然翻车。
原因有三点。
第一,医疗文档有严格的层级结构,比如指南的"章节→小节→条款→推荐意见"。固定长度切分很容易把一个小节从中间切断,导致一个知识点的前半段在一个块、后半段在另一个块,检索时哪个块都答不完整。
第二,表格在切分时被截断是最常见的灾难。一张药物相互作用表可能横跨半页,固定长度切分可能把这个表的头部切到上一个块、主体留在下一个块,检索时根本无法还原完整语义。
第三,医疗文本中的数值和条件通常是"捆绑"的。比如"对肾功能不全患者,推荐剂量减半",如果这一句话被切成两块,检索"肾功能不全用药剂量"时可能只召回"推荐剂量减半"而没有前面的适用条件,系统就会给出一个非常危险的结论。
所以我的核心原则是:切分必须感知文档结构,而不是机械地数token。
4.2 按文档结构切分:不同资料用不同的切块规则
在处理不同来源的医疗文档时,我倾向于为每一类资料设计专门的切分规则:
指南类文档:优先按照"章→节→条"的标题层级切分。每一段推荐意见最好独立成一个块,同时把对应的标题路径(如"第三章 药物治疗 / 3.2 降压药物 / 3.2.1 单片复方制剂")作为元数据挂在块上。这样检索出来的块自带"上下文坐标",生成阶段可以引用,用户也能知道答案来自指南的哪一部分。
药品说明书:这类文档的切分相对好办,因为绝大多数说明书都有固定的【适应症】【用法用量】【不良反应】【禁忌】等小标题。我按"小标题段落"切分,同时把药品通用名、商品名、剂型作为元数据。特别要注意的是,说明书里的用量表格要单独做表格语义化后再切,不能把表格硬塞进文本块。
病历文书:病历的行文结构虽然不如指南规范,但通常有"主诉、现病史、既往史、初步诊断、治疗意见"等固定段落。我会先用段落标题定位,把每个大段单独切开。同时病历里同一个时间点的各类记录尽量合并成一个块,避免同一就诊事件的描述被切得七零八落。
FAQ问答对:如果知识库里有一些整理好的问答对,直接"一问一答"作为一个块,这是最简单也最高效的切法。
对于实在找不到明显结构的文档,我会退回到"标题识别+语义完整性启发式+固定长度兜底"的组合方案:先看有没有标题,有标题按标题切;没有标题就按段落切;段落太长再按语义边界(比如"根据以上内容""综上所述"这类转折词)切;都不行再用固定长度切并加大重叠比例。这个兜底方案不是最优解,但能保证不出现灾难性的语义断裂。
4.3 块大小、重叠与元数据:容易被忽略的三个旋钮
除了切分策略本身,还有三个参数经常被忽略,但实际影响很大。
第一是块大小。医疗问答里,答案往往需要上下文才能判断是否适用。块太小,模型看不到前提条件;块太大,检索噪声增多,向量模型容易"稀释"。我在项目里的经验值是:指南类文档单块控制在450~650个中文字符左右,药品说明书和病历文书可以适当放宽到800~1000字符。注意这不是标准答案,最好上线前用评测集做A/B测试,对比不同块大小下的命中率。
第二是重叠。为了让一个知识点的主体部分不至于被块边界切断,我会在两个相邻块之间保留150~250字符的重叠。这会造成一定的存储冗余,但检索质量的提升是值得的。需要注意重叠区域不要包含独立的结论性文本,否则同一个结论可能在两个块里重复出现,生成阶段可能造成重复或混乱。
第三是元数据,这一点我认为比块大小还重要。每个块除了正文内容之外,我还会挂上一组元数据字段:文档标题、版本、发布时间、章节路径、来源类型、适用科室、相关疾病、相关药品等。后面做"带过滤条件的检索"时,元数据就是过滤器。比如用户限定"只要儿童用药信息",系统可以直接过滤掉正文里没有儿童相关描述的块,效率和质量都能提升。
5. 向量化与召回:别让"语义近似"耽误了"精确匹配"
切分完成之后,下一步是把文本块转成向量放到索引里,并在检索阶段计算查询和候选块的相关度。很多人以为这一步"选个embedding模型就完事了",但在医疗场景里,这里藏着不少问题。
5.1 通用向量模型在医疗术语上的失效场景
我在项目里实际测过:用通用领域的embedding模型处理医疗文本,在小样本上经常出现"语义相似度不可靠"的情况。
举几个真实发生过的例子:
- 用户输入"心衰",希望命中"心力衰竭""慢性心功能不全",通用模型的相似度分数有时会低于"心衰"和"心碎"的相似度,因为字面距离上"心衰"更接近"心碎"。
- 用户输入"ARB类药物",希望命中各类具体药名,比如"缬沙坦""氯沙坦"——通用模型虽然知道ARB是血管紧张素受体拮抗剂,但对具体药物名的关联度打分不稳定。
- 用户输入"降压目标130/80 mmHg",希望命中指南里"血压控制目标应<130/80 mmHg"的条款,但通用模型对数值型语义的匹配能力远不如关键词精确匹配。
这些问题的本质是:医疗文本里的专业术语、缩写、药名、数值,更像是一种"代码",而不是自然语言。语义近似在医疗问答里往往不够可靠,甚至会产生误导——模型以为"心衰"和"心碎"在语义上接近,但在医学上两者完全是两回事。
5.2 混合检索:把关键词精确匹配捡回来
通用的解决方案是:不要只用向量检索,而是把关键词检索(BM25)和向量检索结合起来做混合召回,再用重排序阶段综合打分。
这种做法在医疗场景里特别有效,因为用户的查询往往包含精确的专有名词,比如"阿司匹林""TNM分期""低钠血症"。这些词在知识库里以完全相同的字面出现的概率很高,纯粹的向量检索反而会为了"语义泛化"丢掉这些精确匹配信号。
我实际搭建的检索架构是:查询同时发给向量检索和关键词检索,两者各取Top 50,合并后去重,再过一个重排序模型,最终取Top 10作为生成阶段的上下文。实测效果比单独用向量检索的Top 10命中率有显著提升,尤其是在药品、检查项目这类专有名词密集的查询上。
这里有一个细节:关键词检索之前,查询也要做预处理。比如用户输入是口语化的"血压高该怎么办",需要先通过术语词典扩展成"高血压 处理 降压 治疗"等关键词组合,再做关键词检索。否则拼音输入、错别字、口语表达都会让关键词检索失灵。
5.3 查询端扩展:用户口语怎么映射到专业术语
说到查询预处理,这其实是数据准备阶段就要埋好的伏笔。我建议在知识库构建初期就同步整理一份"术语别名表",把用户可能说的口语和资料里的规范术语对应起来。比如:
| 用户可能输入 | 知识库里的规范表达 |
|---|---|
| 血糖高 | 高血糖 / 糖尿病 |
| 血压低 | 低血压 |
| 打针 | 注射 / 肌注 / 静滴 |
| 消炎药 | 抗生素 / 抗感染药物 |
| 化验尿 | 尿常规检查 |
这个表怎么用?一种方式是在查询阶段做查询扩展,把用户问题里的口语词替换或补充为规范术语,再去做向量检索和关键词检索。另一种方式是在清洗阶段给文档做"同义标注",在原文里用括号补充别名,例如"2型糖尿病(简称T2DM,俗称血糖高)"。两种方式可以结合,效果更好。
我曾经在项目里遇到用户大量输入"血糖高到多少算严重"这类问题,如果不做查询扩展,系统很难把"血糖高"和指南里的"高血糖危象""糖尿病酮症酸中毒"关联起来。加了同义映射之后,明显改善。
向量化环节还有一个选择:是直接用通用embedding模型,还是微调一个医疗领域的embedding模型。我的经验是,如果项目周期紧、数据量不大,先用通用模型+混合检索跑起来,把整个链路打通,同时积攒评测数据;等积累了一定量的真实查询和专家标注的相关文档对之后,再考虑用对比学习的方式微调一个领域embedding模型。在一开始就纠结"必须微调模型"往往会拖延项目进度。
6. 质检环节:预处理做得好不好,用评测集说话
数据准备一大圈做完,到底合不合格?不能靠感觉,必须用一套可量化的评测方式来判断。医疗场景的质检标准比通用场景更严格,因为错误答案的后果可能很严重。
6.1 构建医疗问答评测集
我在每个医疗RAG项目启动时,都会先花时间构建一个评测集。评测集不需要特别大,但结构要有代表性。
具体做法是:从真实的咨询记录里抽取和筛选50~100个问题,尽量覆盖知识库里的主要科室和主要知识类型——比如高血压用药、糖尿病饮食、检验指标解读、药品禁忌、手术后注意事项等。每个问题由临床医生或医学背景的产品同事给出标准答案,并标注答案对应的知识来源文档。
这个评测集有三个用途:第一,评估检索命中率;第二,评估生成答案的准确率;第三,作为后续每次调整数据预处理流程时的回归测试集。我每一次改变切分参数、清洗规则、检索策略,都会重新跑一遍评测集,对比前后指标变化,避免"改一个地方变好、其他地方变差"的情况。
6.2 命中率之外,还要盯哪些指标
在医疗RAG质检里,我会重点关注这几个指标:
- Top 5命中率:标准答案对应的文档是否出现在检索结果的前5条里。这是判断数据预处理质量最直接的指标。如果Top 5命中率低于75%,说明切分策略或向量化方案大概率有问题,要回去调。
- 块完整性:抽样检查检索到的Top 5块里,有多少块是"不完整的知识点"。比如指南里一条推荐意见被切开的比例。块不完整率高于20%就需要优化切分规则。
- 数值保留率:检查清洗后的文本里,剂量、参考范围、时间节点等关键数值是否仍然完整。这一步可以用规则自动检查,拿清洗前后的文本做数值差异对比。
- 隐私泄露率:抽样人工检查检索结果和生成答案里是否仍包含真实姓名、电话等信息。这一条不用多,出现一次就是事故。
除了这些技术指标之外,我还会专门盯一类"易混淆查询"。比如"阿司匹林能不能和布洛芬一起吃"和"阿司匹林能不能和氯吡格雷一起吃",答案完全不同,但查询在向量空间里可能离得很近。评测集里专门放一些这类"高相似度、不同答案"的问题,看系统能不能区分清楚。如果不能区分,说明知识库里的相关文本粒度不够,或者切分时把条件信息丢了。
6.3 抽样人工复审:医疗场景必须保留的一步
自动指标能解决大部分问题,但医疗场景的特殊性在于:召回对了不等于答案对了。检索阶段命中了一个关于剂量的片段,但生成阶段可能只参考了前半句,忽略了禁忌条件,输出结果就变成带风险的错误建议。
所以我在每个版本上线前,都会做一轮抽样人工复审。做法是把评测集里每个问题的检索结果和生成答案打出来,让有医学背景的同事逐条判断:检索到的文档是否真的是权威来源?切分后的文本是否保留了必要的限定条件?生成的回答有没有断章取义?引用来源标注是否清晰?
这个环节不需要自动化,因为医学判断本身就需要专家参与。但它能暴露很多自动指标看不到的问题。比如我们曾经在一次复审中发现,某指南里"不推荐常规使用"这句话被切出来后,检索到的块里缺少前文"对无并发症的轻度高血压患者"这个限定主语,导致系统回答了"不推荐使用"——单独看是在复述原文,放在具体问题语境里就是错误答案。
7. 数据更新与知识治理:医疗知识库的老化问题
最后聊一个经常被忽略、但医疗场景特别要命的问题:知识库是会过期的。
7.1 指南和说明书在"变",向量库不会自动变
医疗知识有一个显著特点:权威共识随时在更新。一部临床指南可能两三年就出一个新版,药品说明书可能因为新的不良反应监测结果而修改,医保目录每年调整,院内操作流程也经常修订。如果你的RAG知识库还停留在"一次性建好就不管"的状态,半年后它给出的答案就可能带着严重的时效性问题。
更麻烦的是,旧版本和新版本如果同时存在于知识库里,检索时系统可能把两者都召回,生成时就会产生"自相矛盾"的内容。用户问"这个药现在多少钱",系统可能引用两年前的定价,引发投诉甚至更严重的后果。
7.2 增量更新与版本管理的落地做法
我的做法是,从数据准备阶段就要设计一套"版本化+增量更新"机制:
- 文档版本管理:每一份入库的资料都记录版本号和生效日期,新版本入库时,旧版本不是直接被删除,而是标记为"已废弃"。检索时默认只在"生效中"的版本范围内执行,只有用户明确要求或者无新版时才触碰历史版本。
- 切块级替换:当某一份文档更新时,不需要整库重建,只需要把该文档对应的所有切块从索引里删除,重新走一遍清洗、切分、向量化流程,把新版本块写入即可。这要求切块生成时就要记录"来源文档ID",否则后面无法精准定位哪些块属于哪份文档。
- 批量重向量化:如果你的embedding模型在项目中期换过一次版本,那所有块的向量都要重新计算,不能新旧向量混用。我们吃过这个亏:换模型后没有重算历史向量,结果新查询在旧向量上匹配度波动很大,整个检索质量反而下降了。
- 定时巡检:我建议每隔一段时间(比如一个季度)就让医学背景的同学复核一遍当前知识库的有效性,拉出"知识来源清单",逐一确认哪些文档需要更新、哪些可以下架。这个工作看起来不性感,但它是医疗RAG系统长期稳定运行的基础。
7.3 让临床参与审核:数据闭环的最后一块拼图
数据准备和预处理不是一次性的技术任务,它本质上是一个需要持续运营的数据治理工程。尤其对医疗场景来说,不能只有工程师在维护知识库。
我的经验是,项目推进到一定阶段后,要让临床医生或药学人员真正参与到知识库的审核和反馈闭环里来。具体方式是:每期版本上线后,让临床医生先试用一批问题,把"答得不满意"的case提交出来,我们根据这些case反推数据侧的问题——是没采到对应的资料?是切分切断了一个限定条件?是术语词典缺了一条映射?
这个闭环跑起来之后,数据预处理的目标就不再是"跑完一遍流程",而是"持续让知识库更准确、更完整地覆盖临床关心的问题"。我也慢慢体会到,医疗RAG系统的上限,很大程度不取决于大模型能力,而是取决于知识和数据工程的组织能力。数据准备这一段看似苦活、累活,恰恰是整个系统最值得投入的地方。