Files
AIclinicalresearch/docs/02-通用能力层/03-RAG引擎
HaHafeng bbf98c4d5c fix(backend): Resolve PgBoss infinite loop issue and cleanup unused files
Backend fixes:
- Fix PgBoss task infinite loop on SAE (root cause: missing queue table constraints)
- Add singletonKey to prevent duplicate job enqueueing
- Add idempotency check in reviewWorker (skip completed tasks)
- Add optimistic locking in reviewService (atomic status update)

Frontend fixes:
- Add isSubmitting state to prevent duplicate submissions in RVW Dashboard
- Fix API baseURL in knowledgeBaseApi (relative path)

Cleanup (removed):
- Old frontend/ directory (migrated to frontend-v2)
- python-microservice/ (unused, replaced by extraction_service)
- Root package.json and node_modules (accidentally created)
- redcap-docker-dev/ (external dependency)
- Various temporary files and outdated docs in root

New documentation:
- docs/07-运维文档/01-PgBoss队列监控与维护.md
- docs/07-运维文档/02-故障预防检查清单.md
- docs/07-运维文档/03-数据库迁移注意事项.md

Database fix applied to RDS:
- Added PRIMARY KEY to platform_schema.queue
- Added 3 missing foreign key constraints

Tested: Local build passed, RDS constraints verified
2026-01-27 18:16:22 +08:00
..

知识库引擎RAG Engine

能力定位: 通用能力层
复用率: 57% (4个模块依赖)
优先级: P0
状态: 🔄 升级中Dify → PostgreSQL + pgvector
核心原则: 提供基础能力(乐高积木),不做策略选择
最后更新: 2026-01-20


📋 能力概述

知识库引擎是平台的核心通用能力,提供知识库相关的基础能力(乐高积木)

核心设计原则

✅ 提供基础能力(乐高积木)
❌ 不做策略选择(组装方案由业务模块决定)

原因:不同业务场景需要不同策略

  • 小知识库10个文件→ 直接全文塞给 LLM
  • 大知识库100+文件)→ RAG 向量检索
  • 特殊场景 → 摘要筛选 + Top-K 全文

基础能力清单

  • 📄 文档入库 - 异步入库pg-boss返回 taskId 轮询状态
  • 📝 全文获取 - 单文档/批量获取文档全文
  • 📋 摘要获取 - 单文档/批量获取文档摘要(💰 可选生成)
  • 🔍 向量检索 - 基于 pgvector 的语义检索
  • 🔤 关键词检索 - 基于 pg_bigm 的中文精确检索
  • 🔀 混合检索 - 向量 + 关键词 + RRF 融合
  • 🎯 重排序 - 🆕 基于 Qwen-Rerank 的精排序

⚠️ 注意:不提供 chat() 方法!问答策略由业务模块根据场景决定。

┌─────────────────────────────────────────────────────────────┐
│                   业务模块层(策略选择)                       │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐       │
│   │   PKB   │  │   AIA   │  │   ASL   │  │   RVW   │       │
│   │ 全文/RAG │  │摘要+全文 │  │向量+Rerank│ │ 全文比对 │       │
│   └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘       │
│        │  根据场景自由组合基础能力       │                    │
│        └────────────┴────────────┴────────────┘             │
│                          │                                  │
│                          ▼                                  │
├─────────────────────────────────────────────────────────────┤
│              知识库引擎(提供基础能力 / 乐高积木)              │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              KnowledgeBaseEngine                     │   │
│   │   ingest() / getFullText() / getSummary()           │   │
│   │   vectorSearch() / keywordSearch() / hybridSearch() │   │
│   │   ❌ 不提供 chat() - 策略由业务模块决定               │   │
│   └─────────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────────┤
│                PostgreSQL + pgvector                        │
└─────────────────────────────────────────────────────────────┘

🔄 重大更新2026-01-20

架构升级Dify → PostgreSQL + pgvector

维度 原方案Dify 新方案pgvector
存储 Qdrant外部 PostgreSQL内部
数据控制 外部 API 完全自主
扩展性 受限 高度灵活
符合架构 Postgres-Only

定位变更:从 PKB 模块到通用能力层

维度 原定位 新定位
代码位置 modules/pkb/ common/rag/
使用范围 仅 PKB 全平台
设计目标 单模块功能 通用能力

📊 依赖模块

4个模块依赖57%复用率):

模块 使用场景 优先级
PKB 个人知识库 知识库管理、RAG 问答、全文阅读 P0首个接入
AIA AI智能问答 @知识库 问答、附件理解 P0
ASL AI智能文献 文献库检索、智能综述生成 P1
RVW 稿件审查 稿件与文献对比、查重检测 P1

💡 基础能力使用

1. 文档入库( 异步)

import { KnowledgeBaseEngine } from '@/common/rag';

const kbEngine = new KnowledgeBaseEngine(prisma);

// 提交入库任务(立即返回)
const { taskId, documentId } = await kbEngine.submitIngestTask({
  kbId: 'kb-123',
  userId: 'user-456',
  file: pdfBuffer,
  filename: 'research.pdf',
  options: {
    enableSummary: true,           // 💰 可选,默认 false
    enableClinicalExtraction: true // 💰 可选,默认 false
  }
});

// 轮询任务状态
const status = await kbEngine.getIngestStatus(taskId);
// { status: 'processing', progress: 45 }

详见:Postgres-Only异步任务处理指南

2. 全文/摘要获取

// 获取单个文档全文
const doc = await kbEngine.getDocumentFullText(documentId);

// 获取知识库所有文档全文(小知识库场景)
const allDocs = await kbEngine.getAllDocumentsText(kbId);

// 获取知识库所有文档摘要(筛选场景)
const summaries = await kbEngine.getAllDocumentsSummaries(kbId);

3. 检索能力

// 向量检索
const vectorResults = await kbEngine.vectorSearch(kbIds, query, 20);

// 关键词检索pg_bigm 中文精确匹配)
const keywordResults = await kbEngine.keywordSearch(kbIds, query, 20);

// 混合检索(向量 + 关键词 + RRF
const hybridResults = await kbEngine.hybridSearch(kbIds, query, 10);

// 🆕 重排序
const reranked = await kbEngine.rerank(hybridResults, query, 5);

🎯 业务模块策略示例

PKB小知识库全文模式

// 10 个文档 → 直接全文塞给 LLM
async function pkbSmallKbChat(kbId: string, query: string) {
  const docs = await kbEngine.getAllDocumentsText(kbId);
  const context = docs.map(d => `## ${d.filename}\n${d.text}`).join('\n\n');
  return llmChat(context, query);
}

AIA摘要筛选 + Top-K 全文

// 摘要筛选 → LLM 选 Top 5 → 读取全文
async function aiaSmartChat(kbIds: string[], query: string) {
  const summaries = await kbEngine.getAllDocumentsSummaries(kbIds);
  const topDocIds = await llmSelectTopK(summaries, query, 5);
  const fullTexts = await Promise.all(
    topDocIds.map(id => kbEngine.getDocumentFullText(id))
  );
  return llmChat(fullTexts.join('\n\n'), query);
}

ASL向量检索 + Rerank

// 大规模文献检索
async function aslSearch(kbIds: string[], query: string) {
  const candidates = await kbEngine.vectorSearch(kbIds, query, 50);
  const reranked = await rerankService.rerank(candidates, query, 10);
  return reranked;
}

🏗️ 技术架构

代码结构

backend/src/common/rag/
├── index.ts                      # 统一导出
├── KnowledgeBaseEngine.ts        # 统一入口类(基础能力)
├── services/
│   ├── ChunkService.ts           # 文档切片
│   ├── EmbeddingService.ts       # 向量化(阿里云)
│   ├── SummaryService.ts         # 摘要生成 ⭐
│   ├── VectorSearchService.ts    # 向量检索
│   ├── KeywordSearchService.ts   # 关键词检索
│   ├── HybridSearchService.ts    # 混合检索 + RRF
│   └── ClinicalExtractionService.ts  # 临床要素提取
├── types/
│   └── index.ts                  # 类型定义
└── utils/
    └── rrfFusion.ts              # RRF 算法

数据模型

┌─────────────────────────────────────────────────────────────┐
│                    ekb_schema                                │
│  ┌───────────────────────┐    ┌───────────────────────┐    │
│  │     EkbDocument       │    │      EkbChunk         │    │
│  │  ─────────────────    │    │  ─────────────────    │    │
│  │  id                   │    │  id                   │    │
│  │  kbId                 │───>│  documentId           │    │
│  │  filename             │    │  content              │    │
│  │  extractedText        │    │  embedding (vector)   │    │
│  │  summary ⭐           │    │  pageNumber           │    │
│  │  tokenCount           │    │  sectionType          │    │
│  │  pico (JSONB)         │    └───────────────────────┘    │
│  │  studyDesign (JSONB)  │                                  │
│  │  regimen (JSONB)      │                                  │
│  │  safety (JSONB)       │                                  │
│  └───────────────────────┘                                  │
└─────────────────────────────────────────────────────────────┘

summary 字段用于支持"摘要筛选 + Top-K 全文"策略


📚 API 接口

KnowledgeBaseEngine

class KnowledgeBaseEngine {
  // ========== 文档入库(⚡️ 异步) ==========
  submitIngestTask(params: IngestParams): Promise<{ taskId: string; documentId: string }>;
  getIngestStatus(taskId: string): Promise<{ status, progress, error? }>;
  
  // ========== 内容获取 ==========
  getDocumentFullText(documentId: string): Promise<DocumentText>;
  getAllDocumentsText(kbId: string): Promise<DocumentText[]>;
  getDocumentSummary(documentId: string): Promise<DocumentSummary>;
  getAllDocumentsSummaries(kbId: string): Promise<DocumentSummary[]>;
  
  // ========== 检索能力 ==========
  vectorSearch(kbIds: string[], query: string, topK?: number): Promise<SearchResult[]>;
  keywordSearch(kbIds: string[], query: string, topK?: number): Promise<SearchResult[]>;  // pg_bigm
  hybridSearch(kbIds: string[], query: string, topK?: number): Promise<SearchResult[]>;
  rerank(docs: SearchResult[], query: string, topK?: number): Promise<SearchResult[]>;    // 🆕
  
  // ========== 管理操作 ==========
  deleteDocument(documentId: string): Promise<void>;
  clearKnowledgeBase(kbId: string): Promise<void>;
  getKnowledgeBaseStats(kbId: string): Promise<KBStats>;
  
  // ❌ 不提供 chat() 方法 - 策略由业务模块根据场景决定
}

🔗 与其他通用能力的关系

依赖能力 用途
文档处理引擎 PDF/Word/Excel → Markdown
LLM 网关 摘要生成、临床要素提取
存储服务 原始文档存储到 OSS

LLM 问答由业务模块自行调用 LLM 网关实现


📅 开发计划

分阶段实施(推荐)

详见:03-分阶段实施方案.md

阶段 内容 工期 状态
Phase 1 MVP 入库 + 向量检索 + 全文获取 3 天 🔜 待开始
Phase 2 增强 + 关键词检索 + 混合检索 + rerank 2 天 📋 规划中
Phase 3 完整 + 异步入库 + 摘要 + PICO 3 天 📋 规划中

技术实现参考

详见:02-pgvector替换Dify计划.md


📂 相关文档


📅 更新日志

2026-01-20 v1.2 架构审核优化

  • 入库异步化submitIngestTask() + getIngestStatus(),基于 pg-boss
  • 💰 成本控制:摘要/PICO 提取默认关闭,按需开启
  • 🔧 中文检索tsvectorpg_bigm,专为 CJK 文字优化
  • 🆕 新增能力rerank() 重排序Qwen-Rerank API
  • 📋 分阶段实施:新增 MVP → 增强 → 完整 三阶段方案

2026-01-20 v1.1 设计原则重大更新

  • 核心原则:提供基础能力(乐高积木),不做策略选择
  • 移除 chat() 方法,策略由业务模块决定
  • 🆕 新增 getDocumentFullText() / getAllDocumentsText() 全文获取
  • 🆕 新增 getDocumentSummary() / getAllDocumentsSummaries() 摘要获取
  • 🆕 新增业务模块策略示例PKB/AIA/ASL/RVW

2026-01-20 v1.0 架构升级

  • 🔄 定位变更:从 PKB 模块提升为通用能力层
  • 🆕 创建架构设计文档
  • 🆕 重构开发计划(通用能力层视角)
  • 📦 规划代码结构:common/rag/

2025-11-06 初始版本

  • 基于 Dify 实现
  • 仅 PKB 模块使用---维护人: 技术架构师