feat(rag): Complete RAG engine implementation with pgvector

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
This commit is contained in:
2026-01-21 20:24:29 +08:00
parent 1f5bf2cd65
commit 40c2f8e148
338 changed files with 11014 additions and 1158 deletions

View File

@@ -0,0 +1,944 @@
# 知识库引擎数据模型设计
> **文档版本**: 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` JSONBchunkSize, 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-L1Positive NonSmall-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 字段 |