# AI 知识库 V2 — 统一知识管理平台设计规格 > 日期: 2026-05-26 | 状态: 草稿 | 作者: brainstorming session > 替代: 旧三层模型(ai_knowledge_rules / references / guides) ## 目录 1. **背景与目标** — 为什么要重做、解决什么问题 2. **架构概览** — 整体架构、核心模块、数据流 3. **数据模型** — 3 张新表、字段定义、索引策略 4. **文档处理管线** — 文件解析、智能切片、embedding、异步处理 5. **混合意图路由** — 三层漏斗:关键词 → 向量 → LLM 兜底 6. **管理后台 UI** — Dify 风格三页面:知识库列表 / 文档管理 / 命中测试 7. **AI 客服集成** — RAG 注入、System Prompt、引用溯源 8. **旧数据迁移** — 旧 3 表 → 新模型迁移策略 9. **API 端点清单** — 所有新增/变更的 API 10. **依赖与风险** — 新增 Rust 依赖、技术风险、缓解措施 ## 设计决策记录 | # | 决策 | 选项 | 选定 | 理由 | |---|------|------|------|------| | 1 | 服务对象 | A:AI引擎 B:医护查询 C:两者兼顾 | C(当前优先 AI 客服) | 渐进交付 | | 2 | 知识范围 | 机构信息/就医流程/健康科普 | 三类全覆盖 | 用户确认 | | 3 | 录入方式 | 单一/混合 | 混合(上传+表单+URL) | 灵活性 | | 4 | 架构方案 | A:MVP B:完整平台 C:渐进 | 方案 B | 一次做好更省时 | | 5 | 意图路由 | A:LLM B:向量 C:混合 | 混合(关键词+向量+LLM兜底) | 平衡准确性和速度 | | 6 | UI 风格 | A:Dify B:FastGPT C:简洁 | Dify 风格 | 用户确认 | | 7 | 数据模型 | 保留旧模型/新建/替换 | 替换旧模型 | 统一管理 | --- ## 1. 背景与目标 ### 1.1 现状问题 当前 AI 知识库基于三层模型(`ai_knowledge_rules` / `ai_knowledge_references` / `ai_knowledge_guides`),存在以下核心问题: | 优先级 | 问题 | 影响 | |--------|------|------| | P0 | **录入方式原始** — 仅支持手动文本输入到 textarea,无文件上传、无 PDF 解析、无 URL 导入 | 医护人员无法高效录入,200 页临床指南无法导入 | | P1 | **知识无分类体系** — 仅靠 `analysis_type` 一个维度(6 个选项)过滤 | 检索效率低,不同类型知识混杂 | | P1 | **无质量审核** — 任何人可直接发布,无版本控制 | 医疗知识错误影响患者安全 | | P2 | **无使用效果追踪** — 不知道哪些知识被 AI 引用、embedding 质量如何 | 投入产出不可衡量 | | P2 | **规则层无 UI** — `ai_knowledge_rules` 无 CRUD API 和管理界面 | 规则只能通过数据库操作 | | P2 | **引用不透明** — AI 分析结果不显示知识来源和置信度 | 用户无法验证 AI 推理依据 | ### 1.2 目标 **核心目标:** 构建 Dify 级的统一知识管理平台,作为 AI 客服的知识底座,让 AI 能准确回答机构相关问题。 **阶段性交付:** - **Phase 1(当前):** AI 客服知识底座 — 机构信息、就医流程、健康科普 - **Phase 2(未来):** 医护直接查询 — 医学文献检索、临床决策支持 - **Phase 3(未来):** AI 分析引擎增强 — 化验解读、趋势分析的知识增强 ### 1.3 成功标准 | 指标 | 目标值 | |------|--------| | 知识录入效率 | 从手动粘贴 200 页文档 → 上传 1 个 PDF,5 分钟内自动处理完成 | | 检索准确率 | 意图路由命中率 ≥ 90%(命中测试验证) | | AI 回答质量 | 知识库覆盖范围内的问题,85%+ 能基于知识库准确回答 | | 管理效率 | 非技术人员可在 10 分钟内完成一个知识库的创建和文档导入 | --- ## 2. 架构概览 ### 2.1 核心架构图 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 管理后台 (Web) │ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │ │ │ 知识库列表 │ │ 文档管理 │ │ 命中测试 + 切片预览 │ │ │ │ (卡片视图) │ │ (表格 + 上传) │ │ (检索验证) │ │ │ └──────┬───────┘ └──────┬───────┘ └───────────┬───────────┘ │ │ │ │ │ │ └─────────┼─────────────────┼───────────────────────┼──────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ API Layer (Axum) │ │ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐ │ │ │ KB CRUD Handler │ │ Document Handler │ │ Search Handler │ │ │ │ (知识库管理) │ │ (上传/状态/重处理) │ │ (命中测试) │ │ │ └────────┬────────┘ └────────┬─────────┘ └───────┬────────┘ │ └───────────┼─────────────────────┼────────────────────┼───────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Service Layer (Rust) │ │ │ │ ┌──────────────────┐ ┌──────────────────────────────────────┐ │ │ │ KnowledgeService │ │ DocumentPipeline │ │ │ │ - CRUD 知识库 │ │ - 文件解析 (PDF/Word/Excel/URL/TXT) │ │ │ │ - CRUD 文档 │ │ - 智能切片 (按 KB 策略) │ │ │ │ - 切片管理 │ │ - Embedding (复用 EmbeddingService) │ │ │ └────────┬─────────┘ │ - 异步处理 (tokio::spawn) │ │ │ │ └──────────────┬───────────────────────┘ │ │ ▼ ▼ │ │ ┌──────────────────────────────────────────────────────────────┐│ │ │ HybridKnowledgeRouter (实现 KnowledgeSource trait) ││ │ │ Layer 1: 关键词粗筛 → Layer 2: 向量检索 → Layer 3: LLM 兜底 ││ │ └──────────────────────────┬───────────────────────────────────┘│ │ │ │ └──────────────────────────────┼───────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ AI 客服集成 │ │ ┌──────────────┐ ┌─────────────────┐ ┌────────────────┐ │ │ │ chat_handler │───▶│ RAG Context 注入 │───▶│ LLM Provider │ │ │ │ (现有) │ │ (System Prompt) │ │ (Claude/Ollama)│ │ │ └──────────────┘ └─────────────────┘ └────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌────────────────┐ │ │ │ 前端 ChatPage │◀─── [ref:xxx] 引用 ◀────│ AI 回答 + 溯源 │ │ │ └──────────────┘ └────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ PostgreSQL (pgvector) │ │ ┌──────────────────┐ ┌───────────────────┐ ┌──────────────┐ │ │ │ ai_knowledge_bases│ │ ai_knowledge_docs │ │ ai_chunks │ │ │ │ (知识库目录) │ │ (文档元数据) │ │ (切片+向量) │ │ │ └──────────────────┘ └───────────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 2.2 核心模块职责 | 模块 | 位置 | 职责 | |------|------|------| | `KnowledgeService` | `erp-ai/src/service/knowledge.rs` | 知识库/文档/切片 CRUD、统计更新 | | `DocumentPipeline` | `erp-ai/src/knowledge/pipeline.rs`(新增) | 文件解析 → 切片 → embedding → 存储 | | `DocumentParser` | `erp-ai/src/knowledge/parser.rs`(新增) | PDF/Word/Excel/URL/Markdown/TXT 格式解析 | | `ChunkStrategy` | `erp-ai/src/knowledge/chunk.rs`(新增) | 按 KB 配置策略执行切片 | | `HybridKnowledgeRouter` | `erp-ai/src/knowledge/hybrid_router.rs`(新增) | 三层意图路由,实现 `KnowledgeSource` trait | | `EmbeddingService` | `erp-ai/src/service/embedding.rs`(现有) | 复用,无需修改 | | `KnowledgeSearchRepo` | `erp-ai/src/knowledge/vector_search.rs`(改造) | pgvector 查询,适配新表结构 | ### 2.3 关键数据流 **知识录入流:** ``` 用户上传文件 → POST /ai/knowledge/bases/{id}/documents → 创建 document 记录 (status=pending) → tokio::spawn 异步处理 → DocumentPipeline::process(document_id) → DocumentParser::parse(file) → 提取纯文本 → ChunkStrategy::chunk(text, strategy) → 生成切片 → EmbeddingService::embed_batch(chunks) → 生成向量 → 批量写入 ai_knowledge_chunks → 更新 document.status = completed ``` **知识检索流(AI 客服):** ``` 用户提问 → chat_handler → HybridKnowledgeRouter::get_context(query) → Layer 1: keyword_match(query, kb.intent_keywords) → 匹配知识库列表 → Layer 2: vector_search(query, kb_ids) → top 5, threshold 0.65 → Layer 3: (仅 top < 0.75) llm_classify(query) → 重定向知识库 → 重新 vector_search → 组装 RAG context (≤4000 tokens) → 注入 System Prompt → LLM 生成回答 + [ref:xxx] 引用 → 异步更新 chunk.hit_count ``` --- ## 3. 数据模型 ### 3.1 表设计概览 3 张新表替换旧 3 表(`ai_knowledge_rules` / `ai_knowledge_references` / `ai_knowledge_guides`): ``` ai_knowledge_bases (1) ──< ai_knowledge_documents (N) ──< ai_knowledge_chunks (N) 知识库目录 文档元数据 切片 + 向量 ``` 所有表包含标准审计字段:`id`(UUID v7) / `tenant_id` / `created_at` / `updated_at` / `created_by` / `updated_by` / `deleted_at`。`version_lock` 仅 bases 和 documents 表使用。 ### 3.2 ai_knowledge_bases(知识库目录) ```sql CREATE TABLE ai_knowledge_bases ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, name VARCHAR(200) NOT NULL, -- 知识库名称 kb_type VARCHAR(50) NOT NULL, -- 类型枚举 description TEXT, -- 描述(帮助 AI 理解用途) icon VARCHAR(50), -- 图标标识 chunk_strategy JSONB NOT NULL DEFAULT '{}', -- 切片策略 intent_keywords JSONB NOT NULL DEFAULT '[]', -- 意图关键词 embedding_model VARCHAR(100), -- embedding 模型(默认全局配置) is_enabled BOOLEAN NOT NULL DEFAULT true, document_count INT NOT NULL DEFAULT 0, -- 缓存:文档数 chunk_count INT NOT NULL DEFAULT 0, -- 缓存:切片总数 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), created_by UUID, updated_by UUID, deleted_at TIMESTAMPTZ, version_lock INT NOT NULL DEFAULT 1 ); -- 索引 CREATE INDEX idx_kb_tenant ON ai_knowledge_bases(tenant_id) WHERE deleted_at IS NULL; CREATE INDEX idx_kb_type ON ai_knowledge_bases(tenant_id, kb_type) WHERE deleted_at IS NULL; CREATE INDEX idx_kb_enabled ON ai_knowledge_bases(tenant_id, is_enabled) WHERE deleted_at IS NULL; ``` **kb_type 枚举值:** | 值 | 中文名 | 用途 | |----|--------|------| | `rule` | 规则 | KDIGO 分期、危急值阈值、药物相互作用 | | `reference` | 参考资料 | ICD-10 映射、药品数据库、检验参考范围 | | `clinical_guide` | 临床指南 | 诊疗规范、科室专科方案 | | `institution_info` | 机构信息 | 科室介绍、医生排班、服务项目、价格套餐 | | `medical_process` | 就医流程 | 预约挂号流程、体检须知、报告领取方式 | | `health_education` | 健康科普 | 疾病知识、检查项目解读、生活方式建议 | | `faq` | 常见问答 | 用户高频问答对 | **chunk_strategy 默认值(按 kb_type):** ```json // rule / reference { "max_tokens": 300, "overlap": 0, "separator": "\n\n", "strategy": "per_item" } // faq { "max_tokens": 400, "overlap": 0, "separator": "\n\n", "strategy": "qa_pair" } // institution_info / medical_process { "max_tokens": 500, "overlap": 50, "separator": "\n\n", "strategy": "paragraph" } // health_education { "max_tokens": 600, "overlap": 80, "separator": "\n\n", "strategy": "paragraph" } // clinical_guide { "max_tokens": 800, "overlap": 100, "separator": "\n##", "strategy": "section" } ``` ### 3.3 ai_knowledge_documents(文档元数据) ```sql CREATE TABLE ai_knowledge_documents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, knowledge_base_id UUID NOT NULL REFERENCES ai_knowledge_bases(id), title VARCHAR(500) NOT NULL, source_type VARCHAR(20) NOT NULL, -- upload / url / manual file_path VARCHAR(500), -- 文件存储路径(upload) file_type VARCHAR(20), -- pdf/docx/txt/md/xlsx/csv/html file_size BIGINT, -- 字节 source_url TEXT, -- 原始 URL(url 类型) raw_content TEXT, -- 解析后的完整纯文本(冗余存储) status VARCHAR(20) NOT NULL DEFAULT 'pending', chunk_count INT NOT NULL DEFAULT 0, error_message TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), created_by UUID, updated_by UUID, deleted_at TIMESTAMPTZ, version_lock INT NOT NULL DEFAULT 1 ); CREATE INDEX idx_doc_kb ON ai_knowledge_documents(knowledge_base_id) WHERE deleted_at IS NULL; CREATE INDEX idx_doc_status ON ai_knowledge_documents(knowledge_base_id, status) WHERE deleted_at IS NULL; CREATE INDEX idx_doc_tenant ON ai_knowledge_documents(tenant_id) WHERE deleted_at IS NULL; ``` **status 状态机:** ``` pending → processing → completed ↘ failed ``` - `pending`: 刚创建,等待处理 - `processing`: 正在解析/切片/embedding - `completed`: 处理完成,切片可用 - `failed`: 处理失败,`error_message` 记录原因 ### 3.4 ai_knowledge_chunks(切片 + 向量) ```sql CREATE TABLE ai_knowledge_chunks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, document_id UUID NOT NULL REFERENCES ai_knowledge_documents(id), knowledge_base_id UUID NOT NULL REFERENCES ai_knowledge_bases(id), -- 冗余加速查询 chunk_index INT NOT NULL, -- 文档内序号 (0-based) content TEXT NOT NULL, -- 切片原文 embedding vector(1536), -- pgvector 向量 token_count INT, -- token 数量 metadata JSONB DEFAULT '{}', -- 元数据: page, section, source_line hit_count INT NOT NULL DEFAULT 0, -- 命中次数 last_hit_at TIMESTAMPTZ, -- 最近命中时间 created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_by UUID ); -- 向量检索核心索引(HNSW,无需预热数据,pgvector >= 0.5.0) CREATE INDEX idx_chunk_embedding ON ai_knowledge_chunks USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); -- 按知识库查询 CREATE INDEX idx_chunk_kb ON ai_knowledge_chunks(knowledge_base_id); -- 按文档查询 CREATE INDEX idx_chunk_doc ON ai_knowledge_chunks(document_id); -- 按租户查询 CREATE INDEX idx_chunk_tenant ON ai_knowledge_chunks(tenant_id); -- 命中统计排序 CREATE INDEX idx_chunk_hits ON ai_knowledge_chunks(knowledge_base_id, hit_count DESC); ``` **metadata 字段示例:** ```json // PDF 文档切片 { "page": 3, "section": "第三章 血透适应症", "source_line": 45 } // Excel 行切片 { "row": 12, "columns": ["套餐名", "价格", "包含项目"] } // URL 导入切片 { "url": "https://xxx.com/about", "selector": ".main-content" } // Markdown 切片 { "heading": "## 体检前注意事项", "level": 2 } ``` --- ## 4. 文档处理管线 ### 4.1 管线架构 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │ 接收文件 │───▶│ 格式解析 │───▶│ 智能切片 │───▶│ Embedding │───▶│ 存储 │ │ upload/ │ │ Parser │ │ Chunker │ │ Service │ │ chunks │ │ url/manual│ │ │ │ │ │ (复用) │ │ table │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ └──────────┘ │ ▼ ┌──────────────┐ │ 错误处理 │ │ failed + msg │ └──────────────┘ ``` 整个管线在 `tokio::spawn` 中异步执行,前端通过轮询 `GET /documents/{id}` 获取状态。 ### 4.2 格式解析器(DocumentParser) 每种格式对应一个解析函数,统一输出 `ParsedDocument { title, text, metadata }`。 | 格式 | Rust 依赖 | 解析策略 | 特殊处理 | |------|-----------|----------|----------| | **PDF** | `pdf-extract` 或 `lopdf` | 逐页提取文本 | 检测表格结构 → Markdown 表格;纯图片页标记跳过 | | **Word (.docx)** | `docx-rs` | 按段落提取,保留标题层级 | 标题作为 metadata.section | | **TXT** | 标准库 | 直接读取,按空行分段 | 无特殊处理 | | **Markdown (.md)** | 标准库 + 自定义 | 按标题层级分割 | `#`/`##` 作为 metadata.heading | | **Excel (.xlsx)** | `calamine` | 逐行拼接为自然语言描述 | 表头 + 行数据 → "套餐A,价格599元,包含..." | | **CSV** | 标准库 | 同 Excel 策略 | 自动检测分隔符 | | **URL (HTML)** | `reqwest` + `scraper` | HTTP GET → 提取 body 正文 | SSRF 防护(禁止内网地址);去广告/导航/页脚 | **URL 导入的正文提取逻辑:** ```rust fn extract_main_content(html: &str) -> String { // 1. 用 scraper 解析 DOM // 2. 移除