# 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 ``` --- ## 📅 版本历史 | 版本 | 日期 | 变更内容 | |------|------|----------| | v1.1 | 2026-01-24 | pg_bigm v1.2 安装完成,关键词检索性能大幅提升 | | v1.0 | 2026-01-21 | 初版:基于 "Brain-Hand" 架构重构完成 |