# **知识库引擎架构设计** 文档版本: v2.0 (架构修正版) 创建日期: 2026-01-20 最后更新: 2026-01-21 核心原则: 引擎负责“执行”,业务负责“思考”。 ## **📋 概述** ### **能力定位修正** **KnowledgeBaseEngine** 是一个**纯粹的检索执行器**。它不负责“理解用户意图”,只负责“执行检索指令”。 **❌ 错误的设计:** * 引擎内部调用 LLM 分析聊天记录。 * 引擎依赖 Chat History 数据结构。 **✅ 正确的设计:** * **业务模块 (AIA/ASL)**:调用 DeepSeek 分析意图 \-\> 生成 \[Query1, Query2, Query3\]。 * **引擎模块 (EKB)**:接收 queries\[\] \-\> 执行向量/关键词检索 \-\> RRF 融合 \-\> 返回结果。 ## **🏗️ 交互流程图 (The "Brain-Hand" Model)** sequenceDiagram participant User participant Biz as 业务模块 (AIA/ASL) participant LLM as DeepSeek V3 (Brain) participant Engine as 知识库引擎 (Hand) participant DB as PostgreSQL User-\>\>Biz: "副作用大吗?" (带着上下文) rect rgb(240, 248, 255\) Note over Biz, LLM: 🧠 思考阶段 (策略层) Biz-\>\>LLM: Prompt: "结合历史,生成检索词" LLM--\>\>Biz: \["NSCLC一线治疗副作用", "Pembrolizumab AE"\] end rect rgb(255, 240, 245\) Note over Biz, Engine: ✋ 执行阶段 (机制层) Biz-\>\>Engine: search(queries=\[...\]) Engine-\>\>DB: 并行向量检索 \+ 关键词检索 Engine-\>\>Engine: RRF 融合 & Rerank Engine--\>\>Biz: 返回 Top-K 文档 end Biz-\>\>LLM: Prompt: "基于这些文档回答用户" LLM--\>\>User: 最终回答 ## **📦 API 设计 (KnowledgeBaseEngine)** 引擎的 API 变得更加干净、通用: export class KnowledgeBaseEngine { /\*\* \* 纯粹的检索接口 \* @param kbIds 知识库 ID 列表 \* @param searchQueries 检索词列表(由业务层生成好的) \*/ async search( kbIds: string\[\], searchQueries: string\[\], // 👈 接收一组词,而不是一个 query options?: { topK?: number; filters?: SearchFilters; // 结构化过滤,如 { year: 2024 } } ): Promise\ { // 1\. 并行执行所有 query 的检索 (Fan-out) const allResults \= await Promise.all( searchQueries.map(q \=\> this.vectorSearchInternal(kbIds, q)) ); // 2\. RRF 融合 const fusedResults \= this.rrfFusion(allResults.flat()); // 3\. Rerank (可选) // 使用第一个 Query 作为基准进行重排序 return this.rerank(fusedResults, searchQueries\[0\]); } } 把“语义理解”和“意图分析”强行塞进底层的 RAG 引擎,确实会让引擎变得臃肿且不通用。 ### **为什么你的思路是“架构级”的提升?** 1. **解耦 (Decoupling)**: * **RAG 引擎 (KnowledgeBaseEngine)** 应该是一个\*\*“精准的执行者”\*\*(机制)。它的职责是:“你给我一组词,我给你找出最匹配的文档”。它不应该关心“这组词是来自一个愤怒的医生,还是来自一个做作业的学生”。 * **业务模块 (AIA/ASL)** 才是\*\*“聪明的决策者”\*\*(策略)。只有业务模块才知道当前的对话上下文(Context)、用户的角色(Role)以及当前任务的目标(Goal)。 2. **场景化差异 (Context Matters)**: * **AIA(聊天)**:上下文是 `Chat History`,策略是“意图补全”。 * **ASL(文献筛选)**:上下文是 `Inclusion Criteria`(入排标准),策略是“PICO 拆解”。 * **如果都塞进引擎**:引擎内部就要写一堆 `if (isChat) ... else if (isLiterature) ...`,这是架构的大忌。 --- 我根据你的这个关键修正,将 **《01-知识库引擎架构设计》** 和 **《08-技术方案》** 进行了**最终架构对齐**。 ### **修改点概览** 1. **RAG 引擎**:回归纯粹。删除 `search(history)` 这种带业务逻辑的接口,只保留 `search(queries[])`。 2. **业务层**:新增 **“检索策略层”**。DeepSeek 的思考过程发生在业务层。 也就是说,利用DeepSeek做翻译,做语义理解都不应该放在RAG引擎里,对吗?还是说我们只保留翻译?还是都不保留,在业务模块调用DeepSeek的时候,就考虑中英文翻译的事 **结论:是的,应该全部剥离。** 在 KnowledgeBaseEngine(RAG 引擎)里,**既不保留语义理解,也不保留翻译**。它应该是一个“没有任何感情的杀手”,只负责执行。 ### **1\. 最终架构定调:各司其职** 为了让你跟团队沟通更明确,我把这种模式总结为 **“决策与执行分离”**: | 层级 | 角色 | 职责 (谁做?) | 核心逻辑 | | :---- | :---- | :---- | :---- | | **业务层** (AIA/ASL) | **决策者** (The Brain) | **DeepSeek V3** | **“怎么搜?”** 它负责看懂用户的话,看懂历史记录,然后决定:“我要用中文搜一遍,再用英文搜一遍,还要查一下 K 药的学名”。 最终产出:\["K药", "Keytruda", "Pembrolizumab"\] | | **引擎层** (EKB) | **执行者** (The Hand) | **Postgres \+ Vector** | **“去搜!”** 它根本不知道什么是“K药”,它只收到一个指令:search(queries: string\[\])。 它负责把这 3 个词扔进数据库,并行跑向量检索和关键词检索,然后把结果捞上来。 | ### **2\. 为什么要连“翻译”都移出去?** 你可能会问:“翻译不是通用的吗?为什么不留在引擎里?” 因为在医学场景下,**“翻译”往往依赖“上下文”**,而引擎是没有上下文的。 * **场景 A(AIA 聊天)**: * 用户说:“阳性吗?”(上文在聊 **EGFR 基因突变**)。 * **业务层 DeepSeek**:结合历史,生成检索词 \["EGFR mutation positive", "EGFR 突变 阳性"\]。 * **如果是引擎层做翻译**:引擎只看到“阳性吗?”,翻译成 Is it positive?,去搜可能会搜出“新冠阳性”或“艾滋病阳性”,完全跑偏。 * **场景 B(ASL 文献筛选)**: * 用户设定:“年龄 \> 60岁”。 * **业务层 DeepSeek**:生成检索词 \["Elderly patients", "Geriatric", "Age \> 60"\]。 * **如果是引擎层做翻译**:引擎根本不知道这代表“老年人”,可能直译。 **所以,只有业务层才有资格做“精准的翻译(即意图理解)”。**