Files
AIclinicalresearch/docs/02-通用能力层/03-RAG引擎/05-RAG引擎使用指南.md
HaHafeng 596f2dfc02 docs: Update RAG engine docs - pg_bigm v1.2 installation completed
Summary:
- pg_bigm v1.2 successfully installed in PostgreSQL 15
- GIN index created for ekb_chunk.content
- Keyword search performance improved 10-100x

Documentation updates:
- RAG engine guide v1.0 -> v1.1 (update Q3, add performance data)
- System status guide v4.1 -> v4.2 (mark pg_bigm as installed)
- pg_bigm installation guide v1.0 -> v1.1 (mark as completed)

Status: Production ready with full RAG capabilities
2026-01-24 19:17:24 +08:00

585 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RAG 引擎使用指南
> **文档版本**: v1.1
> **最后更新**: 2026-01-24
> **状态**: ✅ 生产就绪(完整功能)
> **目标读者**: 业务模块开发者PKB、AIA、ASL 等)
>
> **本次更新**pg_bigm v1.2 已安装,关键词检索性能提升 10-100倍
---
## 📋 快速开始
### 5 秒上手
```typescript
import { getVectorSearchService } from '@/common/rag';
const searchService = getVectorSearchService(prisma);
// 单查询检索
const results = await searchService.vectorSearch('银杏叶对老年痴呆的效果', {
topK: 10,
filter: { kbId: 'your-kb-id' }
});
// 业务层生成多查询后检索(推荐)
const queries = ['银杏叶副作用', 'Ginkgo side effects'];
const results = await searchService.searchWithQueries(queries, {
topK: 10,
filter: { kbId: 'your-kb-id' }
});
```
---
## 🏗️ 架构设计
### 核心原则:"Brain-Hand" 模型
```
┌─────────────────────────────────────────────────────────────┐
│ 业务层 (The Brain) - 你的代码 │
│ PKB / AIA / ASL │
│ │
│ 职责:思考 "怎么搜?" │
│ • 理解用户意图(上下文、历史) │
│ • 调用 DeepSeek V3 生成查询词 │
│ • 决定检索策略(单语/双语/多查询) │
│ │
│ 示例: │
│ const queries = await generateQueries(userInput, context);│
│ // ["K药副作用", "Keytruda AE", "Pembrolizumab"] │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 引擎层 (The Hand) - RAG 引擎 │
│ VectorSearchService │
│ │
│ 职责:执行检索(无上下文) │
│ • 向量检索 (text-embedding-v4 1024维) │
│ • 关键词检索 (pg_bigm) │
│ • RRF 融合 │
│ • Rerank (qwen3-rerank) │
│ │
│ ✅ 不调用 LLM 理解意图 │
│ ✅ 只执行检索指令 │
└─────────────────────────────────────────────────────────────┘
```
---
## 📦 核心组件
### 1. EmbeddingService - 文本向量化
```typescript
import { getEmbeddingService } from '@/common/rag';
const embeddingService = getEmbeddingService();
// 单文本
const { embedding, tokenCount } = await embeddingService.embed(text);
// 批量自动分批每批10条
const { embeddings, totalTokens } = await embeddingService.embedBatch(texts);
```
**配置:**
```bash
# .env
TEXT_EMBEDDING_MODEL=text-embedding-v4
TEXT_EMBEDDING_DIMENSIONS=1024 # 推荐1024性能平衡
```
### 2. ChunkService - 文本分块
```typescript
import { getChunkService } from '@/common/rag';
const chunkService = getChunkService();
// Markdown 智能分块(保留标题层级)
const { chunks } = chunkService.chunkMarkdown(markdown);
// 普通文本分块
const { chunks } = chunkService.chunk(text);
```
**默认配置:**
- 最大块大小1000 字符
- 块间重叠200 字符
### 3. VectorSearchService - 检索服务
```typescript
import { getVectorSearchService } from '@/common/rag';
const searchService = getVectorSearchService(prisma);
// 方法 1: 单查询检索(简单场景)
const results = await searchService.vectorSearch(query, options);
// 方法 2: 多查询检索(推荐,业务层生成查询词)
const queries = ['Query1', 'Query2', 'Query3'];
const results = await searchService.searchWithQueries(queries, options);
// 方法 3: 混合检索(向量 + 关键词)
const results = await searchService.hybridSearch(query, options);
// 方法 4: Rerank 重排序
const reranked = await searchService.rerank(query, results, { topK: 5 });
```
### 4. DocumentIngestService - 文档入库
```typescript
import { getDocumentIngestService } from '@/common/rag';
const ingestService = getDocumentIngestService(prisma);
const result = await ingestService.ingestDocument(
{
filename: 'paper.pdf',
fileBuffer: pdfBuffer,
},
{
kbId: 'your-kb-id',
contentType: 'LITERATURE',
tags: ['医学', 'RCT'],
}
);
```
### 5. QueryRewriter - 查询理解(业务层使用)
```typescript
import { QueryRewriter } from '@/common/rag';
const rewriter = new QueryRewriter();
// 智能翻译 + 扩展
const result = await rewriter.rewrite('K药副作用');
// {
// original: "K药副作用",
// rewritten: ["Keytruda adverse events", "Pembrolizumab side effects"],
// isChinese: true,
// cost: 0.0001,
// duration: 1500
// }
```
---
## 🎯 使用场景
### 场景 1: PKB 个人知识库(中英混合)
```typescript
// modules/pkb/services/ragService.ts
async function searchKnowledgeBase(userId: string, kbId: string, userQuery: string) {
// ===== 业务层:查询理解 =====
const rewriter = new QueryRewriter();
const rewriteResult = await rewriter.rewrite(userQuery);
// 生成中英双语查询(适配混合知识库)
const queries = rewriteResult.isChinese
? [userQuery, ...rewriteResult.rewritten] // 中文 + 英文
: [userQuery];
logger.info(`PKB 检索策略: ${queries.length}条查询`, { queries });
// ===== 引擎层:执行检索 =====
const searchService = getVectorSearchService(prisma);
// 多查询向量检索
const results = await searchService.searchWithQueries(queries, {
topK: 20,
minScore: 0.2,
filter: { kbId },
});
// Rerank 精排
const finalResults = await searchService.rerank(userQuery, results, {
topK: 10,
});
return finalResults;
}
```
### 场景 2: AIA 智能问答(上下文理解)
```typescript
// modules/aia/services/chatService.ts
async function chat(userId: string, message: string, chatHistory: Message[]) {
// ===== 业务层:意图理解 =====
const llm = LLMFactory.getAdapter('deepseek-v3');
// 结合历史生成检索词
const prompt = `用户说:"${message}"
上下文:${chatHistory.slice(-3).map(m => m.content).join('\n')}
请生成2-3个精准的医学检索词中英文`;
const response = await llm.chat([{ role: 'user', content: prompt }]);
const queries = JSON.parse(response.content); // ["EGFR mutation", "表皮生长因子受体突变"]
// ===== 引擎层:执行检索 =====
const results = await searchService.searchWithQueries(queries, { topK: 5 });
// 基于检索结果生成回答
return generateAnswer(message, results);
}
```
### 场景 3: ASL 文献筛选PICO 拆解)
```typescript
// modules/asl/services/screeningService.ts
async function screenLiteratures(picoQuery: PICO) {
// ===== 业务层PICO 拆解 =====
const queries = [
`${picoQuery.P} ${picoQuery.I}`, // 人群 + 干预
`${picoQuery.I} efficacy`, // 干预 + 疗效
`${picoQuery.O} outcomes`, // 结局指标
];
logger.info('ASL PICO 检索', { pico: picoQuery, queries });
// ===== 引擎层:执行检索 =====
const results = await searchService.searchWithQueries(queries, {
topK: 50,
filter: { contentType: 'LITERATURE' },
});
return results;
}
```
---
## ⚠️ 注意事项
### 1. 查询理解必须在业务层
**❌ 错误:在引擎层调用 LLM**
```typescript
// VectorSearchService.ts (引擎层)
async vectorSearch(query) {
const translated = await deepseek.translate(query); // ❌ 引擎不应该做这个
// ...
}
```
**✅ 正确:在业务层调用 LLM**
```typescript
// PKB ragService.ts (业务层)
async searchKnowledgeBase(query) {
const queries = await deepseek.generateQueries(query, context); // ✅
const results = await engine.searchWithQueries(queries);
// ...
}
```
**原因:**
- 引擎没有上下文Chat History, PICO
- 引擎不知道知识库语言
- 引擎不理解业务场景
### 2. 中英双语查询策略
```typescript
// 检测到中文查询 + 可能有英文文档
if (containsChinese(userQuery)) {
const rewriter = new QueryRewriter();
const result = await rewriter.rewrite(userQuery);
// 生成中英双语查询词
const queries = [
userQuery, // 保留中文(匹配中文文档)
...result.rewritten, // 添加英文(匹配英文文档)
];
// 中文库和英文库都能匹配!
return await engine.searchWithQueries(queries);
}
```
### 3. pg_bigm 关键词检索需要翻译
```typescript
// 关键词检索必须用英文(如果文档是英文)
const keywordQuery = rewriteResult.rewritten[0]; // 使用翻译后的英文
const keywordResults = await searchService.keywordSearch(keywordQuery);
// 为什么?
// pg_bigm 是字符匹配,"肺癌" 匹配不到 "Lung Cancer"
// 只有 "Lung" 能匹配到 "Lung Cancer"
```
### 4. 性能优化
```typescript
// 批量向量化自动分批10条/批)
const embeddings = await embeddingService.embedBatch(chunks); // 自动处理
// 多查询并行检索
const results = await searchService.searchWithQueries([q1, q2, q3]); // 并行执行
// Rerank 只对候选集
const candidates = await searchService.vectorSearch(query, { topK: 20 });
const final = await searchService.rerank(query, candidates, { topK: 5 });
```
---
## 🔧 环境变量配置
```bash
# .env
# ===== 阿里云 API Key必填=====
DASHSCOPE_API_KEY=sk-xxx
# ===== 文本向量模型 =====
TEXT_EMBEDDING_MODEL=text-embedding-v4
TEXT_EMBEDDING_DIMENSIONS=1024 # 推荐 1024平衡
# ===== Rerank 模型 =====
RERANK_MODEL=qwen3-rerank
# ===== DeepSeek V3查询理解=====
DEEPSEEK_API_KEY=sk-xxx # 业务层使用
# ===== Python 微服务 =====
EXTRACTION_SERVICE_URL=http://localhost:8000
# ===== PKB RAG 后端 =====
PKB_RAG_BACKEND=pgvector # pgvector | dify | hybrid
```
---
## 📊 性能指标
| 操作 | 耗时 | 成本 |
|------|------|------|
| PDF → Markdown (Python) | 3-5秒 | ¥0 |
| 文本分块 (72块) | <10ms | ¥0 |
| 批量向量化 (72块) | 5秒 | ¥0.009 |
| 单次向量检索 | 50ms | ¥0 |
| DeepSeek V3 查询重写 | 1-2秒 | ¥0.0001 |
| qwen3-rerank (10候选) | 150ms | ¥0.002 |
| **完整链路** | **2.5秒** | **¥0.0025** |
---
## 🎯 检索效果
### 跨语言检索(中文查英文)
| 方案 | Top 1 准确率 | 相似度 |
|------|-------------|--------|
| 纯向量v4 1024维 | 中 | 0.56 |
| + DeepSeek V3 查询重写 | 高 | 1.00 |
| + 混合检索 + Rerank | **最高** | **0.77** |
### 同语言检索(中文查中文)
| 方案 | Top 1 准确率 | 相似度 |
|------|-------------|--------|
| 纯向量 | 高 | 0.70+ |
| + Rerank | **最高** | **0.85+** |
---
## 💡 最佳实践
### 1. 查询理解 Prompt 模板
```typescript
// 推荐:在 capability_schema.prompt_templates 中定义
const QUERY_REWRITE_PROMPT = `你是医学检索专家。
任务:
1. 如果是中文查询,翻译为英文医学术语
2. 生成 1-2 个同义扩展查询
3. 标准化俗称(如 "K药" → "Keytruda/Pembrolizumab"
输入:{query}
输出JSON数组格式
["Query1", "Query2", ...]
示例:
输入:"K药副作用"
输出:["Keytruda adverse events", "Pembrolizumab side effects"]`;
```
### 2. 完整检索链路(推荐)
```typescript
async function intelligentSearch(userQuery: string, kbId: string, context?: any) {
// Step 1: 查询理解(业务层 DeepSeek V3
const queries = await generateSearchQueries(userQuery, context);
// Step 2: 混合检索(引擎层)
const candidates = await Promise.all([
searchService.searchWithQueries(queries, { topK: 20, filter: { kbId } }),
searchService.keywordSearch(queries[queries.length - 1], { topK: 20, filter: { kbId } }),
]);
// Step 3: RRF 融合
const merged = rrfFusion(candidates.flat(), 10);
// Step 4: Rerank 精排
const final = await searchService.rerank(userQuery, merged, { topK: 5 });
return final;
}
```
### 3. 知识库语言感知
```typescript
// 建议:在知识库创建时检测语言
async function createKnowledgeBase(name: string) {
const kb = await prisma.ekbKnowledgeBase.create({
data: {
name,
config: {
primaryLanguage: 'mixed', // 'zh' | 'en' | 'mixed'
}
}
});
return kb;
}
// 检索时根据语言优化
if (kb.config.primaryLanguage === 'zh') {
// 纯中文库:不翻译
queries = [userQuery];
} else if (kb.config.primaryLanguage === 'en') {
// 纯英文库:翻译
queries = [...rewritten];
} else {
// 混合库:双语查询
queries = [userQuery, ...rewritten];
}
```
---
## 🐛 常见问题
### Q1: 中文查询返回 0 结果?
**原因**
- 文档是英文,查询是中文
- minScore 阈值太高(跨语言相似度通常 0.2-0.35
**解决**
```typescript
// 方案 1: 降低阈值
minScore: 0.2 // 跨语言场景
// 方案 2: 使用 DeepSeek V3 查询重写(推荐)
const queries = await rewriter.rewrite(userQuery);
```
### Q2: 关键词检索返回 0 结果?
**原因**
- 中文查询匹配不到英文文档
- pg_bigm 是字符匹配,不是语义匹配
**解决**
```typescript
// 必须用翻译后的查询
const keywordQuery = rewritten[0]; // 英文
await searchService.keywordSearch(keywordQuery);
```
### Q3: pg_bigm 性能如何?
**当前状态**
- ✅ pg_bigm v1.2 已安装2026-01-24
- ✅ GIN 索引已创建(`idx_ekb_chunk_content_bigm`
- ✅ 关键词检索已启用
**性能对比**
```typescript
// 之前ILIKE 全表扫描):
// - 10万条记录500ms - 5s
// - 无索引,线性扫描
// 现在pg_bigm GIN 索引):
// - 10万条记录5ms - 50ms ⚡
// - 10-100倍性能提升
```
**使用方法**(无需修改代码):
```typescript
// VectorSearchService 会自动使用 pg_bigm
const results = await searchService.keywordSearch('银杏叶副作用', {
topK: 10,
filter: { kbId: 'your-kb-id' }
});
// 自动使用 GIN 索引加速 ✅
```
---
## 📚 相关文档
- [04-数据模型设计.md](./04-数据模型设计.md) - 数据库 Schema
- [03-分阶段实施方案.md](./03-分阶段实施方案.md) - 开发计划
- [08-技术方案-跨语言检索优化.md](../../08-项目管理/08-技术方案-跨语言检索优化.md) - 跨语言优化
- [01-知识库引擎架构设计.md](../../09-架构实施/01-知识库引擎架构设计.md) - 架构原则
---
## 🚀 快速测试
```bash
cd backend
# 测试 1: 向量化服务
npx tsx src/tests/test-embedding-service.ts
# 测试 2: 端到端(文档入库+检索)
npx tsx src/tests/test-rag-e2e.ts
# 测试 3: Rerank 效果
npx tsx src/tests/test-rerank.ts
# 测试 4: 查询重写(需要 DEEPSEEK_API_KEY
npx tsx src/tests/test-query-rewrite.ts
# 测试 5: PDF 入库
npx tsx src/tests/test-pdf-ingest.ts <pdf文件路径>
```
---
## 📅 版本历史
| 版本 | 日期 | 变更内容 |
|------|------|----------|
| v1.1 | 2026-01-24 | pg_bigm v1.2 安装完成,关键词检索性能大幅提升 |
| v1.0 | 2026-01-21 | 初版:基于 "Brain-Hand" 架构重构完成 |