# **企业级医学知识库 (EKB) 综合技术解决方案** 版本: v2.0 (增强版:临床数据全要素结构化) 核心目标: 构建高精度、可追溯、基于医学证据的企业级知识库 技术栈: Node.js, Python, PostgreSQL (pgvector), DeepSeek, pymupdf4llm 设计范式: R-C-R-G (Router \- Concurrent \- Rerank \- Generate) ## **1\. 总体架构设计** 本方案采用 **"Postgres-Only"** 极简架构,利用 Node.js 进行业务编排,Python 进行文档解析,外部 API 提供 AI 算力。 ### **1.1 核心组件** 1. **解析层 (Python Microservice)**: * **核心工具**:pymupdf4llm * **作用**:将 PDF(含复杂表格)转换为 **Markdown** 格式,保留结构化语义。 2. **存储层 (PostgreSQL 15+)**: * **三维信息架构**: 1. **文献属性信息** (Metadata):PMID、IF分、期刊等。 2. **文献关键内容信息** (Clinical Data):PICO、用药方案、不良反应、入排标准、终点指标等(JSONB存储)。 3. **向量信息** (Vector):全文切片的语义向量。 3. **计算层 (Node.js \+ External APIs)**: * **Embedding**:调用 text-embedding-v4 或 BGE-M3 API。 * **Rerank**:调用 qwen-rerank API。 * **Reasoning**:调用 DeepSeek V3 进行全要素提取和答案生成。 4. **文件层 (OSS)**: * 存储原始 PDF 和生成的 Markdown 文件。 ## **2\. 数据模型设计 (存储方案)** 利用 PostgreSQL 的强大扩展性,我们在单库中实现多种数据类型的融合存储,构建**健壮的临床数据库**。 ### **2.1 数据库 Schema (Prisma 描述)** // 1\. 文档主表:承载 "属性信息" 与 "关键内容信息" model EkbDocument { id String @id @default(uuid()) projectId String // 业务隔离 // \--- A. 文档属性信息 (Metadata) \- 用于基础筛选 \--- title String abstract String? @db.Text // 原始摘要 pmid String? @unique doi String? journal String? authors String\[\] publishYear Int // 用于 "2024年最新" 筛选 ifScore Float? // 用于 "高分文献" 筛选 docType String // 指南/RCT/综述/病例报告 // \--- B. 文档关键内容信息 (Clinical Data) \- AI 提取的结构化金矿 \--- // 使用 JSONB 存储,支持 GIN 索引,实现 "SQL 级" 的精准查询 // 1\. PICO 要素 // { "P": "晚期NSCLC", "I": "Keytruda", "C": "化疗", "O": "OS, PFS" } pico Json? // 2\. 研究设计与样本 // { "design": "Phase III RCT", "sampleSize": 500, "blinding": "Double-blind" } studyDesign Json? // 3\. 药物与剂量 (Regimen) // \[ { "drug": "Pembrolizumab", "dose": "200mg", "freq": "Q3W" } \] regimen Json? // 4\. 安全性与不良反应 (Safety) // { "ae\_all": \["Rash", "Fatigue"\], "ae\_grade34": \["Pneumonitis"\], "dropout\_rate": "5%" } safety Json? // 5\. 入排标准 (Criteria) // { "inclusion": \["Age \>= 18", "EGFR \-"\], "exclusion": \["Autoimmune disease"\] } criteria Json? // 6\. 观察指标 (Endpoints) // { "primary": \["PFS"\], "secondary": \["OS", "ORR"\], "results": {"PFS\_HR": 0.5} } endpoints Json? // \--- C. 系统信息 \--- fileKey String // PDF OSS 路径 mdKey String? // Markdown OSS 路径 status String // PENDING, PROCESSED, FAILED chunks EkbChunk\[\] // \--- 索引优化 \--- @@index(\[projectId\]) @@index(\[publishYear\]) @@index(\[ifScore\]) // GIN 索引:让 JSON 字段支持高速查询 (e.g. 搜特定不良反应) @@index(\[pico\], type: Gin) @@index(\[regimen\], type: Gin) @@index(\[safety\], type: Gin) } // 2\. 切片表:向量信息 \+ 文本内容 model EkbChunk { id String @id @default(uuid()) documentId String // \--- D. 切片内容 \--- content String @db.Text // Markdown 格式的切片文本 pageNumber Int // 溯源锚点 sectionType String? // 标记切片来源:Title, Abstract, Methods, Results, Discussion // \--- E. 向量信息 \--- // 使用 Unsupported 类型支持 pgvector embedding Unsupported("vector(1024)")? document EkbDocument @relation(fields: \[documentId\], references: \[id\], onDelete: Cascade) } ## **3\. 数据处理流水线 (Ingestion Pipeline)** 此流程负责将非结构化的 PDF 转化为结构化的数据库记录。 ### **步骤一:解析与转换 (Python)** * **工具**:pymupdf4llm * **输入**:PDF 文件流。 * **输出**:Markdown 文本(保留表格结构)。 ### **步骤二:全要素智能提取 (DeepSeek)** 这是构建健壮数据库的关键一步。 * **操作**:将全文 Markdown(或前 10k token)丢给 DeepSeek V3。 * **Prompt**:"你是一个医学数据专家。请阅读这篇文献,严格按照以下 JSON 格式提取关键信息。如果文中未提及,字段留空。 1. **pico**: { P, I, C, O } 2. **studyDesign**: { design (如RCT), sampleSize (数字), blinding } 3. **regimen**: 提取主要药物名称、剂量、给药频率。 4. **safety**: 提取主要不良反应(Adverse Events)及严重不良反应。 5. **criteria**: 简要概括核心入选和排除标准。 6. **endpoints**: 主要和次要观察指标。 输出必须是纯 JSON。" * **存储**:解析返回的 JSON,分别填入 EkbDocument 的对应字段。 ### **步骤三:切片与向量化 (Node.js)** * **切片器**:RecursiveCharacterTextSplitter。 * **增强策略**:在切片 content 前面加上元数据头。例如:\[Design: RCT\] \[Sample: 500\] ...原文...。这能显著增加向量检索的召回率。 * **存储**:存入 EkbChunk。 ## **4\. 检索与问答策略 (增强版 R-C-R-G)** 有了结构化数据,我们的检索策略从“模糊搜”升级为“精准筛 \+ 模糊搜”。 ### **4.1 Router (意图路由)** 用户提问后,调用 LLM 判断意图并提取**结构化参数**: 1. **安全性查询** \-\> 提取不良反应关键词 (e.g., "Rash")。 2. **方案对比** \-\> 提取药物名称 (e.g., "Keytruda")。 3. **高质筛选** \-\> 提取样本量阈值 (e.g., "n \> 100")。 ### **4.2 Concurrent Retrieval (并发混合召回)** Node.js 并行执行以下查询,最后取并集: * 路径 A (SQL 精准筛选 \- 新增杀手锏): 利用 JSONB 字段进行逻辑过滤。 * *Query*: SELECT id FROM EkbDocument WHERE safety-\>\>'ae\_all' ILIKE '%Pneumonitis%' (找提到肺炎副作用的) * *Query*: SELECT id FROM EkbDocument WHERE (studyDesign-\>\>'sampleSize')::int \> 100 (找大样本研究) * 路径 B (向量检索): 在路径 A 圈定的 ID 范围内,执行 ORDER BY embedding \<=\> query\_vec。 * 路径 C (关键词检索): 使用 ts\_rank 捕捉专有名词。 ### **4.3 Rerank (重排序)** * **工具**:qwen-rerank API。 * **策略**:输入用户问题 \+ 混合召回的 Top 50 切片。 ### **4.4 Generate (生成与溯源)** * **模型**:DeepSeek V3/R1。 * **优势**:此时 LLM 拿到的 Context 不仅有文本切片,还可以注入该文档的结构化信息(如样本量、PICO),使得回答更加立体。 ## **5\. 实施关键检查点** 1. **JSONB 性能**:PostgreSQL 的 JSONB 查询非常快,但务必建立 GIN 索引(如 @@index(\[safety\], type: Gin)),否则全表扫描会很慢。 2. **提取成本**:全要素提取会消耗更多 Input Token。按 1000 篇文献算,DeepSeek V3 成本约为 20-30 元人民币,完全可接受。 3. **数据清洗**:AI 提取的 JSON 可能会有格式错误,Node.js 端需要加一层 try-catch 和简单的格式校验(如 JSON.parse 失败重试)。 ## **6\. 总结** 这套升级后的方案,不仅是一个**知识库**,更是一个**轻量级的 RWE (真实世界证据) 数据库**。 * **查询能力质变**:从只能问“文章说了什么”,升级为能问“有哪些文章是用 200mg 剂量的”或“有哪些三期临床涉及了亚洲人”。 * **应用场景扩展**:支持自动生成 **Meta 分析草稿**、**竞品安全性对比表**、**指南用药推荐汇总** 等高级应用。