Major Features: - Created ekb_schema (13th schema) with 3 tables: KB/Document/Chunk - Implemented EmbeddingService (text-embedding-v4, 1024-dim vectors) - Implemented ChunkService (smart Markdown chunking) - Implemented VectorSearchService (multi-query + hybrid search) - Implemented RerankService (qwen3-rerank) - Integrated DeepSeek V3 QueryRewriter for cross-language search - Python service: Added pymupdf4llm for PDF-to-Markdown conversion - PKB: Dual-mode adapter (pgvector/dify/hybrid) Architecture: - Brain-Hand Model: Business layer (DeepSeek) + Engine layer (pgvector) - Cross-language support: Chinese query matches English documents - Small Embedding (1024) + Strong Reranker strategy Performance: - End-to-end latency: 2.5s - Cost per query: 0.0025 RMB - Accuracy improvement: +20.5% (cross-language) Tests: - test-embedding-service.ts: Vector embedding verified - test-rag-e2e.ts: Full pipeline tested - test-rerank.ts: Rerank quality validated - test-query-rewrite.ts: Cross-language search verified - test-pdf-ingest.ts: Real PDF document tested (Dongen 2003.pdf) Documentation: - Added 05-RAG-Engine-User-Guide.md - Added 02-Document-Processing-User-Guide.md - Updated system status documentation Status: Production ready
945 lines
30 KiB
Markdown
945 lines
30 KiB
Markdown
# 知识库引擎数据模型设计
|
||
|
||
> **文档版本**: v2.0
|
||
> **最后更新**: 2026-01-21
|
||
> **状态**: ✅ 权威文档
|
||
> **说明**: 本文档是知识库引擎数据模型的唯一权威来源,其他文档应引用本文档,避免重复定义。
|
||
|
||
---
|
||
|
||
## 1. 设计原则
|
||
|
||
### 1.1 核心理念
|
||
|
||
> **即使没有任何结构化数据,RAG 检索也必须能工作!**
|
||
>
|
||
> 结构化数据是"锦上添花",不是"必须有"。
|
||
|
||
### 1.2 四层架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ Layer 0: RAG 核心层(必须有,检索基础) │
|
||
│ ───────────────────────────────────── │
|
||
│ extractedText → 全文 Markdown │
|
||
│ chunks[] → 文本切片 │
|
||
│ embeddings[] → 向量嵌入 │
|
||
│ │
|
||
│ ✅ 只要有这一层,RAG 就能工作! │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ Layer 1: 基础信息层(必须有,系统需要) │
|
||
│ ───────────────────────────────────── │
|
||
│ filename, fileType, fileSizeBytes, fileUrl │
|
||
│ status, errorMessage, createdAt, updatedAt │
|
||
│ │
|
||
│ ✅ 文件管理必需 │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ Layer 2: 内容增强层(可选,提升体验) │
|
||
│ ───────────────────────────────────── │
|
||
│ summary → AI 生成摘要(快速预览) │
|
||
│ tokenCount → Token 数量(成本估算) │
|
||
│ pageCount → 页数 │
|
||
│ │
|
||
│ ✅ 有则更好,无也能用 │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ Layer 3: 分类标签层(可选,用户自定义) │
|
||
│ ───────────────────────────────────── │
|
||
│ contentType → 内容类型(可 AI 自动识别) │
|
||
│ tags[] → 用户标签(用户自己打) │
|
||
│ category → 分类目录(用户自己选) │
|
||
│ │
|
||
│ ✅ 用户可以不管,系统也能运行 │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ Layer 4: 结构化数据层(可选,精准查询) │
|
||
│ ───────────────────────────────────── │
|
||
│ metadata → 文献属性(pmid, doi, journal...) │
|
||
│ structuredData → 类型特定数据(pico, diagnosis...) │
|
||
│ │
|
||
│ ✅ 高级功能,专业用户/药企场景使用 │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.3 设计目标
|
||
|
||
| 目标 | 实现方式 |
|
||
|------|----------|
|
||
| **最小可用** | Layer 0-1 必须有,RAG 就能工作 |
|
||
| **渐进增强** | Layer 2-4 可选,有则更强 |
|
||
| **用户友好** | 什么都不填也能用 |
|
||
| **专业支持** | 专业用户可以填完整信息 |
|
||
| **AI 辅助** | contentType、summary 可 AI 自动生成 |
|
||
| **灵活扩展** | JSONB 支持任意结构化数据 |
|
||
|
||
### 1.4 ER 关系图
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ EkbKnowledgeBase │
|
||
│ ───────────────────────────────────────────── │
|
||
│ id, name, description │
|
||
│ type (USER | SYSTEM) │
|
||
│ ownerId (userId 或 moduleId) │
|
||
│ config (JSONB: chunkSize, topK, enableRerank...) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ 1:N
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ EkbDocument │
|
||
│ ───────────────────────────────────────────── │
|
||
│ id, kbId(FK), userId │
|
||
│ filename, fileType, fileSizeBytes, fileUrl, fileHash │
|
||
│ extractedText, summary, tokenCount, pageCount │
|
||
│ contentType, tags[], category │
|
||
│ metadata(JSONB), structuredData(JSONB) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ 1:N
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ EkbChunk │
|
||
│ ───────────────────────────────────────────── │
|
||
│ id, documentId(FK) │
|
||
│ content, chunkIndex │
|
||
│ embedding (vector 1024) │
|
||
│ pageNumber, sectionType │
|
||
│ metadata(JSONB) ← 新增:切片级元数据 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 2. EkbKnowledgeBase 模型(容器表)
|
||
|
||
### 2.1 设计目的
|
||
|
||
| 痛点 | 解决方案 |
|
||
|------|----------|
|
||
| 无法区分用户私有库 vs 系统公共库 | `type` 字段:USER / SYSTEM |
|
||
| 无法管理"谁拥有这个库" | `ownerId` 字段:userId 或 moduleId |
|
||
| 无法为不同库配置不同 RAG 策略 | `config` JSONB:chunkSize, topK 等 |
|
||
| 用户配额管理(最多 3 个库) | 通过 `type=USER` 计数 |
|
||
|
||
### 2.2 Prisma Schema
|
||
|
||
```prisma
|
||
model EkbKnowledgeBase {
|
||
id String @id @default(uuid())
|
||
name String // 知识库名称
|
||
description String? // 描述
|
||
|
||
// ===== 核心隔离字段 =====
|
||
type String @default("USER") // USER: 用户私有, SYSTEM: 系统公共
|
||
ownerId String // USER: userId, SYSTEM: moduleId (如 "ASL", "AIA")
|
||
|
||
// ===== 策略配置 (JSONB) =====
|
||
config Json? // { chunkSize, topK, enableRerank, embeddingModel }
|
||
|
||
// ===== 关联 =====
|
||
documents EkbDocument[]
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// ===== 索引 =====
|
||
@@index([ownerId])
|
||
@@index([type])
|
||
@@schema("ekb_schema")
|
||
}
|
||
```
|
||
|
||
### 2.3 字段说明
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | String | ✅ | UUID 主键 |
|
||
| `name` | String | ✅ | 知识库名称(如"我的文献库"、"ASL 系统文献库") |
|
||
| `description` | String | ❌ | 知识库描述 |
|
||
| `type` | String | ✅ | 类型:`USER`(用户私有)或 `SYSTEM`(系统公共) |
|
||
| `ownerId` | String | ✅ | 所有者 ID:用户库填 userId,系统库填模块 ID |
|
||
| `config` | Json | ❌ | 策略配置 JSONB |
|
||
|
||
### 2.4 type 枚举
|
||
|
||
| 值 | 说明 | ownerId 含义 |
|
||
|------|------|-------------|
|
||
| `USER` | 用户私有知识库 | userId(创建者) |
|
||
| `SYSTEM` | 系统公共知识库 | moduleId(如 "ASL", "AIA", "IIT") |
|
||
|
||
### 2.5 config 结构
|
||
|
||
```typescript
|
||
interface KnowledgeBaseConfig {
|
||
// RAG 策略
|
||
chunkSize?: number; // 切片大小,默认 512
|
||
chunkOverlap?: number; // 切片重叠,默认 50
|
||
topK?: number; // 检索数量,默认 5
|
||
|
||
// 高级功能
|
||
enableRerank?: boolean; // 启用重排序
|
||
enableSummary?: boolean; // 自动生成摘要
|
||
enableClinicalExtraction?: boolean; // 临床数据提取
|
||
|
||
// 模型配置
|
||
embeddingModel?: string; // 嵌入模型版本
|
||
}
|
||
```
|
||
|
||
### 2.6 使用示例
|
||
|
||
```typescript
|
||
// 用户创建个人知识库
|
||
await prisma.ekbKnowledgeBase.create({
|
||
data: {
|
||
name: '我的肺癌文献库',
|
||
type: 'USER',
|
||
ownerId: 'user-123',
|
||
config: { chunkSize: 512, topK: 5 }
|
||
}
|
||
});
|
||
|
||
// 系统创建 ASL 模块知识库
|
||
await prisma.ekbKnowledgeBase.create({
|
||
data: {
|
||
name: 'ASL 系统文献库',
|
||
type: 'SYSTEM',
|
||
ownerId: 'ASL',
|
||
config: { enableClinicalExtraction: true }
|
||
}
|
||
});
|
||
|
||
// 查询用户所有知识库(配额检查)
|
||
const userKbs = await prisma.ekbKnowledgeBase.count({
|
||
where: { type: 'USER', ownerId: 'user-123' }
|
||
});
|
||
if (userKbs >= 3) throw new Error('知识库配额已满');
|
||
```
|
||
|
||
---
|
||
|
||
## 3. EkbDocument 模型
|
||
|
||
### 3.1 Prisma Schema
|
||
|
||
```prisma
|
||
model EkbDocument {
|
||
id String @id @default(uuid())
|
||
kbId String // 所属知识库
|
||
userId String // 上传者(冗余存储,方便快速查询)
|
||
|
||
// ===== Layer 1: 基础信息(必须)=====
|
||
filename String // 文件名
|
||
fileType String // pdf, docx, pptx, xlsx, md, txt
|
||
fileSizeBytes BigInt // 文件大小(字节)
|
||
fileUrl String // OSS 存储路径
|
||
fileHash String? // 文件 SHA256 哈希(用于秒传和去重)
|
||
status String @default("pending") // 处理状态
|
||
errorMessage String? @db.Text // 错误信息
|
||
|
||
// ===== Layer 0: RAG 核心(必须)=====
|
||
extractedText String? @db.Text // Markdown 全文
|
||
|
||
// ===== Layer 2: 内容增强(可选)=====
|
||
summary String? @db.Text // AI 摘要
|
||
tokenCount Int? // Token 数量
|
||
pageCount Int? // 页数
|
||
|
||
// ===== Layer 3: 分类标签(可选)=====
|
||
contentType String? // 内容类型
|
||
tags String[] // 用户标签
|
||
category String? // 分类目录
|
||
|
||
// ===== Layer 4: 结构化数据(可选)=====
|
||
metadata Json? // 文献属性 JSONB
|
||
structuredData Json? // 类型特定数据 JSONB
|
||
|
||
// ===== 关联 =====
|
||
knowledgeBase EkbKnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
|
||
chunks EkbChunk[]
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// ===== 索引 =====
|
||
@@index([kbId])
|
||
@@index([userId])
|
||
@@index([status])
|
||
@@index([contentType])
|
||
@@index([fileHash]) // 支持秒传查询
|
||
@@index([tags], type: Gin)
|
||
@@index([metadata], type: Gin)
|
||
@@index([structuredData], type: Gin)
|
||
@@schema("ekb_schema")
|
||
}
|
||
```
|
||
|
||
### 3.2 字段说明
|
||
|
||
#### Layer 1: 基础信息(必须)
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | String | ✅ | UUID 主键 |
|
||
| `kbId` | String | ✅ | 所属知识库 ID(外键) |
|
||
| `userId` | String | ✅ | 上传者用户 ID(冗余存储,便于快速查询) |
|
||
| `filename` | String | ✅ | 原始文件名 |
|
||
| `fileType` | String | ✅ | 文件类型:pdf, docx, pptx, xlsx, md, txt, csv |
|
||
| `fileSizeBytes` | BigInt | ✅ | 文件大小(字节) |
|
||
| `fileUrl` | String | ✅ | OSS 存储路径 |
|
||
| `fileHash` | String | ❌ | 文件 SHA256 哈希(用于秒传和去重) |
|
||
| `status` | String | ✅ | 处理状态:pending, processing, completed, failed |
|
||
| `errorMessage` | String | ❌ | 处理失败时的错误信息 |
|
||
|
||
#### Layer 0: RAG 核心(必须)
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `extractedText` | String | ❌* | Markdown 格式全文(处理完成后必须有) |
|
||
|
||
> *注:上传时为空,处理完成后必须有值
|
||
|
||
#### Layer 2: 内容增强(可选)
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `summary` | String | ❌ | AI 生成的摘要 |
|
||
| `tokenCount` | Int | ❌ | 全文 Token 数量(用于成本估算) |
|
||
| `pageCount` | Int | ❌ | 文档页数 |
|
||
|
||
#### Layer 3: 分类标签(可选)
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `contentType` | String | ❌ | 内容类型标识(见第 5 节) |
|
||
| `tags` | String[] | ❌ | 用户自定义标签 |
|
||
| `category` | String | ❌ | 分类目录路径,如 "肿瘤科/肺癌" |
|
||
|
||
#### Layer 4: 结构化数据(可选)
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `metadata` | Json | ❌ | 文献属性(见第 7 节) |
|
||
| `structuredData` | Json | ❌ | 类型特定数据(见第 8 节) |
|
||
|
||
### 3.3 status 状态枚举
|
||
|
||
| 状态 | 说明 |
|
||
|------|------|
|
||
| `pending` | 等待处理 |
|
||
| `processing` | 正在处理(解析、向量化) |
|
||
| `completed` | 处理完成 |
|
||
| `failed` | 处理失败 |
|
||
|
||
### 3.4 fileHash 使用示例
|
||
|
||
```typescript
|
||
// 计算文件哈希
|
||
import crypto from 'crypto';
|
||
|
||
function calculateFileHash(buffer: Buffer): string {
|
||
return crypto.createHash('sha256').update(buffer).digest('hex');
|
||
}
|
||
|
||
// 上传时检查是否已存在(秒传)
|
||
async function uploadWithDedup(kbId: string, file: Buffer, filename: string) {
|
||
const fileHash = calculateFileHash(file);
|
||
|
||
// 检查同一知识库内是否已存在相同文件
|
||
const existing = await prisma.ekbDocument.findFirst({
|
||
where: { kbId, fileHash }
|
||
});
|
||
|
||
if (existing) {
|
||
// 秒传:直接返回已存在的文档
|
||
return { type: 'duplicate', document: existing };
|
||
}
|
||
|
||
// 正常上传流程
|
||
const document = await prisma.ekbDocument.create({
|
||
data: { kbId, fileHash, filename, /* ... */ }
|
||
});
|
||
return { type: 'new', document };
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. EkbChunk 模型
|
||
|
||
### 4.1 Prisma Schema
|
||
|
||
```prisma
|
||
model EkbChunk {
|
||
id String @id @default(uuid())
|
||
documentId String // 所属文档
|
||
|
||
// ===== 核心内容 =====
|
||
content String @db.Text // 切片文本(Markdown)
|
||
chunkIndex Int // 切片序号(从 0 开始)
|
||
|
||
// ===== 向量 =====
|
||
embedding Unsupported("vector(1024)")? // 向量嵌入
|
||
|
||
// ===== 溯源信息(可选)=====
|
||
pageNumber Int? // 页码(用于 PDF 溯源)
|
||
sectionType String? // 章节类型
|
||
|
||
// ===== 扩展元数据(可选)=====
|
||
metadata Json? // 切片级元数据 JSONB
|
||
|
||
document EkbDocument @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([documentId])
|
||
@@index([metadata], type: Gin) // JSONB 索引
|
||
@@schema("ekb_schema")
|
||
}
|
||
```
|
||
|
||
### 4.2 字段说明
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `id` | String | ✅ | UUID 主键 |
|
||
| `documentId` | String | ✅ | 所属文档 ID |
|
||
| `content` | String | ✅ | 切片文本(Markdown 格式) |
|
||
| `chunkIndex` | Int | ✅ | 切片序号,从 0 开始 |
|
||
| `embedding` | vector(1024) | ❌* | 向量嵌入(向量化后必须有) |
|
||
| `pageNumber` | Int | ❌ | 来源页码(PDF 溯源) |
|
||
| `sectionType` | String | ❌ | 章节类型标识 |
|
||
| `metadata` | Json | ❌ | 切片级扩展元数据(见 4.4) |
|
||
|
||
### 4.3 sectionType 枚举(可选)
|
||
|
||
| 值 | 说明 |
|
||
|------|------|
|
||
| `title` | 标题 |
|
||
| `abstract` | 摘要 |
|
||
| `introduction` | 引言 |
|
||
| `methods` | 方法 |
|
||
| `results` | 结果 |
|
||
| `discussion` | 讨论 |
|
||
| `conclusion` | 结论 |
|
||
| `references` | 参考文献 |
|
||
| `table` | 表格 |
|
||
| `figure` | 图片说明 |
|
||
|
||
### 4.4 metadata 结构(切片级元数据)
|
||
|
||
```typescript
|
||
interface ChunkMetadata {
|
||
// 考试题场景
|
||
isAnswer?: boolean; // 是否为答案切片
|
||
questionId?: number; // 所属题目 ID
|
||
chunkType?: 'question' | 'options' | 'answer' | 'explanation';
|
||
|
||
// 病历场景
|
||
section?: string; // 病历段落:主诉、现病史、检查结果等
|
||
|
||
// 通用
|
||
importance?: number; // 重要性权重 0-1
|
||
keywords?: string[]; // 关键词(用于加权检索)
|
||
}
|
||
```
|
||
|
||
**使用示例**:
|
||
|
||
```typescript
|
||
// 考试题切片 - 题目
|
||
{
|
||
"content": "1. 关于帕博利珠单抗,下列说法正确的是?",
|
||
"metadata": { "chunkType": "question", "questionId": 1 }
|
||
}
|
||
|
||
// 考试题切片 - 选项
|
||
{
|
||
"content": "A. 派姆单抗 B. 纳武利尤单抗 C. 阿特珠单抗 D. 度伐利尤单抗",
|
||
"metadata": { "chunkType": "options", "questionId": 1 }
|
||
}
|
||
|
||
// 考试题切片 - 答案
|
||
{
|
||
"content": "正确答案:A。派姆单抗是帕博利珠单抗的通用名...",
|
||
"metadata": { "chunkType": "answer", "questionId": 1, "isAnswer": true }
|
||
}
|
||
|
||
// 检索时降低纯答案切片的权重
|
||
const results = await vectorSearch(query);
|
||
const reranked = results.map(r => ({
|
||
...r,
|
||
score: r.metadata?.isAnswer ? r.score * 0.5 : r.score
|
||
}));
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 索引设计
|
||
|
||
### 5.1 向量索引(HNSW)
|
||
|
||
```sql
|
||
-- 创建 HNSW 索引(高性能近似最近邻)
|
||
CREATE INDEX idx_ekb_chunk_embedding ON ekb_schema.ekb_chunk
|
||
USING hnsw (embedding vector_cosine_ops)
|
||
WITH (m = 16, ef_construction = 64);
|
||
```
|
||
|
||
**参数说明**:
|
||
- `m = 16`: 每层最大连接数
|
||
- `ef_construction = 64`: 构建时搜索范围
|
||
|
||
### 5.2 关键词索引(pg_bigm)
|
||
|
||
```sql
|
||
-- 安装 pg_bigm 扩展
|
||
CREATE EXTENSION IF NOT EXISTS pg_bigm;
|
||
|
||
-- 全文内容索引
|
||
CREATE INDEX idx_ekb_chunk_content_bigm ON ekb_schema.ekb_chunk
|
||
USING gin (content gin_bigm_ops);
|
||
|
||
-- 文档摘要索引
|
||
CREATE INDEX idx_ekb_document_summary_bigm ON ekb_schema.ekb_document
|
||
USING gin (summary gin_bigm_ops);
|
||
|
||
-- 提取文本索引
|
||
CREATE INDEX idx_ekb_document_text_bigm ON ekb_schema.ekb_document
|
||
USING gin (extracted_text gin_bigm_ops);
|
||
```
|
||
|
||
**关键词查询示例**:
|
||
|
||
```sql
|
||
-- 关键词搜索(支持中英文)
|
||
SELECT * FROM ekb_schema.ekb_chunk
|
||
WHERE content LIKE '%Pembrolizumab%'
|
||
ORDER BY likequery(content, 'Pembrolizumab') DESC;
|
||
|
||
-- 中文搜索
|
||
SELECT * FROM ekb_schema.ekb_chunk
|
||
WHERE content LIKE '%非小细胞肺癌%';
|
||
```
|
||
|
||
### 5.3 JSONB 索引(GIN)
|
||
|
||
```sql
|
||
-- 文献属性索引
|
||
CREATE INDEX idx_ekb_document_metadata ON ekb_schema.ekb_document
|
||
USING gin (metadata jsonb_path_ops);
|
||
|
||
-- 结构化数据索引
|
||
CREATE INDEX idx_ekb_document_structured ON ekb_schema.ekb_document
|
||
USING gin (structured_data jsonb_path_ops);
|
||
|
||
-- 标签数组索引
|
||
CREATE INDEX idx_ekb_document_tags ON ekb_schema.ekb_document
|
||
USING gin (tags);
|
||
```
|
||
|
||
**JSONB 查询示例**:
|
||
|
||
```sql
|
||
-- 按影响因子筛选
|
||
SELECT * FROM ekb_schema.ekb_document
|
||
WHERE (metadata->>'ifScore')::float > 10;
|
||
|
||
-- 按 PICO 干预措施筛选
|
||
SELECT * FROM ekb_schema.ekb_document
|
||
WHERE structured_data->'pico'->>'I' ILIKE '%Pembrolizumab%';
|
||
|
||
-- 按标签筛选
|
||
SELECT * FROM ekb_schema.ekb_document
|
||
WHERE tags @> ARRAY['肺癌', '免疫治疗'];
|
||
```
|
||
|
||
---
|
||
|
||
## 6. contentType 枚举
|
||
|
||
| 值 | 说明 | 适用场景 |
|
||
|------|------|----------|
|
||
| `general` | 通用文档(默认) | 任意文档 |
|
||
| `literature` | 医学文献 | 论文、研究报告 |
|
||
| `case` | 典型病历 | MDT 病例、教学病例 |
|
||
| `exam` | 教学考试 | 试题、模拟题 |
|
||
| `drug` | 药品资料 | 说明书、处方信息 |
|
||
| `guideline` | 临床指南 | NCCN、CSCO 指南 |
|
||
| `note` | 个人笔记 | 学习笔记、会议记录 |
|
||
| `protocol` | 研究方案 | 临床试验方案 |
|
||
| `report` | 工作报告 | 汇报材料、分析报告 |
|
||
|
||
---
|
||
|
||
## 7. metadata 结构(文献属性)
|
||
|
||
### 7.1 JSON Schema
|
||
|
||
```typescript
|
||
interface Metadata {
|
||
// 基础信息
|
||
title?: string; // 文献标题
|
||
abstract?: string; // 原始摘要
|
||
|
||
// 标识符
|
||
pmid?: string; // PubMed ID
|
||
doi?: string; // DOI
|
||
nctId?: string; // ClinicalTrials.gov ID
|
||
|
||
// 来源信息
|
||
journal?: string; // 期刊名称
|
||
publisher?: string; // 出版商
|
||
authors?: string[]; // 作者列表
|
||
|
||
// 时间与评分
|
||
publishYear?: number; // 发表年份
|
||
publishDate?: string; // 发表日期 (YYYY-MM-DD)
|
||
ifScore?: number; // 影响因子
|
||
|
||
// 分类
|
||
docType?: string; // 文献类型:RCT, Meta, Review, Case, Guideline
|
||
keywords?: string[]; // 关键词
|
||
meshTerms?: string[]; // MeSH 词表
|
||
|
||
// 语言
|
||
language?: string; // 语言:en, zh, ...
|
||
}
|
||
```
|
||
|
||
### 7.2 示例
|
||
|
||
```json
|
||
{
|
||
"title": "Pembrolizumab versus Chemotherapy for PD-L1–Positive Non–Small-Cell Lung Cancer",
|
||
"pmid": "27718847",
|
||
"doi": "10.1056/NEJMoa1606774",
|
||
"journal": "New England Journal of Medicine",
|
||
"authors": ["Reck M", "Rodriguez-Abreu D", "Robinson AG"],
|
||
"publishYear": 2016,
|
||
"ifScore": 176.079,
|
||
"docType": "RCT",
|
||
"keywords": ["NSCLC", "Pembrolizumab", "Immunotherapy"],
|
||
"language": "en"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 8. structuredData 结构(类型特定数据)
|
||
|
||
### 8.1 医学文献 (literature)
|
||
|
||
```typescript
|
||
interface LiteratureData {
|
||
// PICO 要素
|
||
pico?: {
|
||
P: string; // Population
|
||
I: string; // Intervention
|
||
C: string; // Comparison
|
||
O: string; // Outcome
|
||
};
|
||
|
||
// 研究设计
|
||
studyDesign?: {
|
||
design: string; // Phase III RCT, Meta-analysis, etc.
|
||
sampleSize: number; // 样本量
|
||
blinding: string; // Double-blind, Open-label
|
||
duration: string; // 研究周期
|
||
};
|
||
|
||
// 用药方案
|
||
regimen?: Array<{
|
||
drug: string; // 药物名称
|
||
dose: string; // 剂量
|
||
freq: string; // 频率
|
||
route: string; // 给药途径
|
||
}>;
|
||
|
||
// 安全性数据
|
||
safety?: {
|
||
ae_all: string[]; // 所有不良反应
|
||
ae_grade34: string[]; // 3-4级不良反应
|
||
dropout_rate: string; // 脱落率
|
||
};
|
||
|
||
// 入排标准
|
||
criteria?: {
|
||
inclusion: string[]; // 入选标准
|
||
exclusion: string[]; // 排除标准
|
||
};
|
||
|
||
// 观察指标
|
||
endpoints?: {
|
||
primary: string[]; // 主要终点
|
||
secondary: string[]; // 次要终点
|
||
results: Record<string, any>; // 结果数据
|
||
};
|
||
}
|
||
```
|
||
|
||
### 8.2 典型病历 (case)
|
||
|
||
```typescript
|
||
interface CaseData {
|
||
// 诊断信息
|
||
diagnosis?: {
|
||
primary: string; // 主诊断
|
||
secondary: string[]; // 合并诊断
|
||
staging: string; // 分期
|
||
pathology: string; // 病理类型
|
||
biomarkers: Record<string, string>; // 生物标志物
|
||
};
|
||
|
||
// 治疗信息
|
||
treatment?: {
|
||
firstLine: string; // 一线治疗
|
||
secondLine: string; // 二线治疗
|
||
surgery: string; // 手术
|
||
radiation: string; // 放疗
|
||
response: string; // 疗效评价
|
||
duration: string; // 治疗周期
|
||
};
|
||
|
||
// 预后信息
|
||
prognosis?: {
|
||
pfs: string; // 无进展生存
|
||
os: string; // 总生存
|
||
status: string; // 当前状态
|
||
recurrence: string; // 复发情况
|
||
};
|
||
|
||
// 随访信息
|
||
followUp?: {
|
||
lastVisit: string; // 最后随访日期
|
||
nextPlan: string; // 下一步计划
|
||
notes: string; // 随访备注
|
||
};
|
||
}
|
||
```
|
||
|
||
### 8.3 教学考试 (exam)
|
||
|
||
```typescript
|
||
interface ExamData {
|
||
// 题目列表
|
||
questions?: Array<{
|
||
id: number;
|
||
type: 'single' | 'multiple' | 'essay'; // 题型
|
||
content: string; // 题目内容
|
||
options?: string[]; // 选项(选择题)
|
||
}>;
|
||
|
||
// 答案列表
|
||
answers?: Array<{
|
||
id: number;
|
||
answer: string; // 答案
|
||
explanation: string; // 解析
|
||
}>;
|
||
|
||
// 知识点
|
||
knowledgePoints?: string[];
|
||
|
||
// 难度
|
||
difficulty?: 'easy' | 'medium' | 'hard';
|
||
|
||
// 来源
|
||
source?: string; // 题目来源
|
||
}
|
||
```
|
||
|
||
### 8.4 药品资料 (drug)
|
||
|
||
```typescript
|
||
interface DrugData {
|
||
// 基础信息
|
||
genericName?: string; // 通用名
|
||
brandName?: string; // 商品名
|
||
manufacturer?: string; // 生产厂家
|
||
|
||
// 适应症
|
||
indication?: string[];
|
||
|
||
// 禁忌症
|
||
contraindication?: string[];
|
||
|
||
// 用法用量
|
||
dosage?: {
|
||
adult: string;
|
||
pediatric: string;
|
||
adjustment: string; // 剂量调整
|
||
};
|
||
|
||
// 药物相互作用
|
||
interaction?: string[];
|
||
|
||
// 警告
|
||
warnings?: string[];
|
||
|
||
// 不良反应
|
||
adverseReactions?: {
|
||
common: string[];
|
||
serious: string[];
|
||
};
|
||
}
|
||
```
|
||
|
||
### 8.5 临床指南 (guideline)
|
||
|
||
```typescript
|
||
interface GuidelineData {
|
||
// 推荐意见
|
||
recommendations?: Array<{
|
||
content: string; // 推荐内容
|
||
level: string; // 证据级别 (1A, 2B, etc.)
|
||
strength: string; // 推荐强度
|
||
}>;
|
||
|
||
// 适用人群
|
||
population?: string;
|
||
|
||
// 发布机构
|
||
organization?: string; // NCCN, CSCO, ESMO
|
||
|
||
// 版本
|
||
version?: string;
|
||
|
||
// 更新要点
|
||
updates?: string[];
|
||
}
|
||
```
|
||
|
||
### 8.6 个人笔记 (note)
|
||
|
||
```typescript
|
||
interface NoteData {
|
||
// 标签(与顶层 tags 字段可重复,这里可存更多)
|
||
tags?: string[];
|
||
|
||
// 分类
|
||
category?: string;
|
||
|
||
// 关联
|
||
relatedDocs?: string[]; // 关联文档 ID
|
||
|
||
// 提醒
|
||
reminder?: string; // 提醒日期
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 使用示例
|
||
|
||
### 9.1 普通医生随手上传
|
||
|
||
```typescript
|
||
// 医生直接拖文件上传,什么都不填
|
||
await kbEngine.submitIngestTask({
|
||
kbId: 'kb-123',
|
||
file: pdfBuffer,
|
||
filename: '某篇论文.pdf',
|
||
// 其他字段都不填
|
||
});
|
||
|
||
// 系统自动完成:
|
||
// ✅ extractedText → 提取全文
|
||
// ✅ chunks → 切片
|
||
// ✅ embeddings → 向量化
|
||
// ✅ summary → AI 摘要(可选开启)
|
||
// ✅ contentType → AI 自动识别(可选开启)
|
||
|
||
// 结果:RAG 检索完全可用!
|
||
```
|
||
|
||
### 9.2 医生想分类管理
|
||
|
||
```typescript
|
||
// 医生上传时选择分类、打标签
|
||
await kbEngine.submitIngestTask({
|
||
kbId: 'kb-123',
|
||
file: pdfBuffer,
|
||
filename: 'KEYNOTE-024.pdf',
|
||
contentType: 'literature',
|
||
tags: ['肺癌', '免疫治疗', 'RCT'],
|
||
category: '肿瘤科/肺癌',
|
||
});
|
||
|
||
// 结果:可以按分类、标签筛选
|
||
```
|
||
|
||
### 9.3 药企专业录入
|
||
|
||
```typescript
|
||
// 药企医学部专业人员完整填写
|
||
await kbEngine.submitIngestTask({
|
||
kbId: 'kb-456',
|
||
file: pdfBuffer,
|
||
filename: 'KEYNOTE-024.pdf',
|
||
contentType: 'literature',
|
||
tags: ['Pembrolizumab', 'NSCLC', 'Phase III'],
|
||
category: '临床研究/III期',
|
||
metadata: {
|
||
title: 'Pembrolizumab versus Chemotherapy...',
|
||
pmid: '27718847',
|
||
doi: '10.1056/NEJMoa1606774',
|
||
journal: 'NEJM',
|
||
authors: ['Reck M', 'Rodriguez-Abreu D'],
|
||
publishYear: 2016,
|
||
ifScore: 176.079,
|
||
docType: 'RCT',
|
||
},
|
||
options: { enableClinicalExtraction: true }
|
||
});
|
||
|
||
// AI 自动提取 structuredData:
|
||
// {
|
||
// pico: { P: '晚期NSCLC, PD-L1≥50%', I: 'Pembrolizumab', ... },
|
||
// studyDesign: { design: 'Phase III RCT', sampleSize: 305 },
|
||
// ...
|
||
// }
|
||
```
|
||
|
||
### 9.4 典型病历录入
|
||
|
||
```typescript
|
||
await kbEngine.submitIngestTask({
|
||
kbId: 'kb-123',
|
||
file: docBuffer,
|
||
filename: '肺癌MDT病例.docx',
|
||
contentType: 'case',
|
||
tags: ['MDT', '肺癌', 'IVA期'],
|
||
category: '病例库/肺癌',
|
||
options: { enableClinicalExtraction: true }
|
||
});
|
||
|
||
// AI 自动提取 structuredData:
|
||
// {
|
||
// diagnosis: { primary: '非小细胞肺癌 IVA期', ... },
|
||
// treatment: { firstLine: '帕博利珠单抗 + 化疗', ... },
|
||
// ...
|
||
// }
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 功能可用性矩阵
|
||
|
||
| 功能 | 只有 Layer 0-1 | + Layer 2 | + Layer 3 | + Layer 4 |
|
||
|------|----------------|-----------|-----------|-----------|
|
||
| **向量检索** | ✅ | ✅ | ✅ | ✅ |
|
||
| **关键词检索** | ✅ | ✅ | ✅ | ✅ |
|
||
| **混合检索** | ✅ | ✅ | ✅ | ✅ |
|
||
| **快速预览** | ❌ | ✅ 有摘要 | ✅ | ✅ |
|
||
| **分类筛选** | ❌ | ❌ | ✅ | ✅ |
|
||
| **标签筛选** | ❌ | ❌ | ✅ | ✅ |
|
||
| **年份筛选** | ❌ | ❌ | ❌ | ✅ |
|
||
| **IF 筛选** | ❌ | ❌ | ❌ | ✅ |
|
||
| **PICO 查询** | ❌ | ❌ | ❌ | ✅ |
|
||
|
||
---
|
||
|
||
## 11. 版本历史
|
||
|
||
| 版本 | 日期 | 变更内容 |
|
||
|------|------|----------|
|
||
| v1.0 | 2026-01-20 | 初版:四层架构设计,支持多内容类型 |
|
||
| v2.0 | 2026-01-21 | 整合审查建议:增加 EkbKnowledgeBase 容器表、EkbDocument.fileHash 字段、EkbChunk.metadata 字段 |
|
||
|
||
|