发布于 Fri Apr 17 2026 08:00:00 GMT+0800 (中国标准时间)
案例医疗合规RAG
案例 · 医疗机构知识库 RAG 怎么做到 0 信息泄漏
一家互联网医院上线 AI 健康咨询,最大挑战是 PHI 信息不能被 LLM 看见。本文公开他们的「分层 KB + Pipeline 脱敏 + 审计」三段式架构。
背景#
- 业务:互联网医院(含线上问诊、电子处方、药品配送)
- 月活:~80 万
- 日均咨询:~4,000(其中健康问题 ~1,200)
- 团队:23 位医师 + 8 位药师 + 12 位客服
- 法律边界:「AI 不做诊断」+「PHI 信息零泄漏」
为什么要做 AI 客服#
医师宝贵时间被大量消耗在「我的检查报告什么意思」「这个药能不能跟那个一起吃」「医保能报销吗」这类信息查询上。统计发现:
- 65% 的咨询其实可以用「公开医学知识 + 公开政策」回答
- 25% 需要患者历史(PHI 信息),需要医师人工
- 10% 紧急(症状描述),需要立刻分诊
目标:把 65% 的「信息查询」类咨询交给 AI,前提是 0 信息泄漏。
架构(三段式)#
第 1 段:分层知识库#
| 层 | 内容 | 谁能看 |
|---|---|---|
| L1 公开 | 医院信息、就诊流程、医保政策、常见健康知识、药品说明 | AI + 任何客户 |
| L2 半私域 | 已认证用户的预约、缴费记录、检查报告下载链接 | AI 通过工具调用 + 该客户本人 |
| L3 私域 PHI | 病历、检查报告原文、医师笔记 | 永远不进 RAG,只医师本人查 |
L1 进 RAGFlow 知识库,L2 走业务接口(结构化数据),L3 完全隔离。
第 2 段:Pipeline 脱敏中间件#
所有客户消息经过 Open WebUI Pipelines 处理:
# pipelines/healthcare_redact.py
import re
PATTERNS = [
(re.compile(r'\b\d{15,18}[Xx0-9]?\b'), '[ID]'),
(re.compile(r'\b1[3-9]\d{9}\b'), '[PHONE]'),
(re.compile(r'病历号[::]\s*\w+'), '病历号:[CASE_ID]'),
# 还有 50+ 模式覆盖检查报告号、医保号等
]
EMERGENCY_KEYWORDS = [
'胸痛', '昏迷', '出血不止', '自杀', '吞药',
'呼吸困难', '抽搐', '中风', '心梗', '休克',
# ...总计 80+
]
class Pipeline:
def __init__(self):
self.name = "Healthcare Redact + Emergency Detect"
def pipe(self, body, user, **kwargs):
msg = body['messages'][-1]['content']
# 紧急关键词检测
if any(k in msg for k in EMERGENCY_KEYWORDS):
body['skip_llm'] = True
body['fallback'] = {
'role': 'assistant',
'content': '检测到紧急关键词。已为您接通急救通道,请立即拨打 120。在线医师将在 30 秒内联系您。'
}
# 同步发送医师告警
notify_oncall_doctor(user, msg)
return body
# 脱敏
for pattern, repl in PATTERNS:
msg = pattern.sub(repl, msg)
body['messages'][-1]['content'] = msg
# 审计日志
audit_log(user, msg)
return body
第 3 段:审计存证#
每条对话留 4 份记录:
| 类型 | 存储 |
|---|---|
| 原文(脱敏前) | 加密 + 仅医师可访问 |
| 脱敏后文本(送 LLM 的) | WORM 存储,6 个月在线、5 年归档 |
| LLM 回复 | WORM 存储,同上 |
| 决策链(检索了哪几条 KB) | WORM 存储,同上 |
监管检查时 5 分钟内能调出任意会话的完整链路。
AI 回复的强约束#
Prompt 末尾必然追加:
重要声明:以上信息基于公开医学知识与本院政策,仅供参考,不构成医疗诊断或治疗建议。如您有具体健康问题,请就诊或咨询执业医师。
且 Dify Workflow 强制以下规则:
- 出现「应该吃什么药」之类问题 → 不给具体药名,只回「请咨询医师」
- 出现「能不能停药」 → 直接转人工
- 涉及孕妇 / 儿童 / 老人 → 加重免责声明
- 涉及精神健康 → 永远转人工
上线 4 个月数据#
| 指标 | 上线前 | 上线后 |
|---|---|---|
| 日均咨询 | 4,000 | 4,800(轻微上升) |
| AI 自助解决 | 0 | 62%(接近预期 65%) |
| 平均响应 | 8 分钟 | 1.8 秒(AI 段) |
| 医师工时 | 280h/天 | 105h/天 |
| 紧急关键词命中 | — | 平均每天 18 次(全部 30 秒内人工接管) |
| 信息泄漏事件 | — | 0 |
一次真实的紧急事件#
某夜 23:47,一位用户在普通问诊问「我胸痛喘不上气」。
- Pipelines 0.2 秒内检测到「胸痛」+「喘不上气」
- 立刻返回紧急回复 + 拨打 120 引导
- 同时给值班医师发飞书 + 短信
- 值班医师 28 秒后进入对话
- 引导用户拨打 120,5 分钟后用户被救护车接走
事后复盘:这是上线 4 个月的第 1,847 次紧急关键词触发,也是第一次真实救人。值。
合规审计#
3 个月时省/市卫健委联合审查:
| 检查项 | 我们的应对 |
|---|---|
| 是否做诊断 | 调出 200 条样本,全部带免责声明 |
| PHI 是否进 LLM | 调出 50 条样本的脱敏前后对比 |
| 紧急情况处理 | 调出 50 个紧急触发记录 |
| 审计日志完整性 | 调出任意时刻的完整链路 |
| 患者知情同意 | 提供注册时的协议条款 |
审查通过,被授予「数字化健康咨询规范单位」称号。
没解决的难题#
1. 老年用户体验差#
老年人用语言不规范、错别字多、断句奇怪——RAG 检索效果差很多。临时改用更宽松的 Embedding 阈值 + 加重「转人工」倾向,但本质问题没解决。
2. 方言识别#
南方方言、川渝方言用户的文本输入有时 Qwen 都搞不懂。在做「方言转普通话」预处理模型。
3. 多轮上下文混淆#
患者 5 轮后问「那个药」不指明哪个,AI 经常猜错。在做「实体追踪」机制。
给医疗同行的 5 个忠告#
- L1 / L2 / L3 分层是命:PHI 永远不能进 RAG,没有例外
- 紧急关键词词典每月更新:医务团队维护,加新词比删旧词重要
- 免责声明必须每条都有:法律意义上不可省
- Pipelines 比 Workflow 更适合脱敏:在 LLM 调用前一层,更可靠
- 审计链路不光保存对话:检索的 chunk、Prompt 版本、模型版本都要记
成本#
| 项 | 月成本 |
|---|---|
| GPU 推理(2 × A100 40GB) | ¥30k |
| Chatwoot + RAGFlow + Open WebUI 服务器 | ¥6k |
| 审计存储(WORM) | ¥4k |
| 软件 / 安全许可 | ¥5k |
| 维护团队(2 人) | ¥40k |
| 合计 | ¥85k / 月 |
医师工时节省:175h/天 × 30 天 × ¥200/h = ¥1,050k / 月。净省 ¥965k / 月。