From 10c28df1521741a80479b6ea9aa2e7e282fc9d22 Mon Sep 17 00:00:00 2001 From: iven Date: Tue, 26 May 2026 22:11:29 +0800 Subject: [PATCH] =?UTF-8?q?docs(ai):=20AI=20=E7=9F=A5=E8=AF=86=E5=BA=93=20?= =?UTF-8?q?V2=20=E8=AE=BE=E8=AE=A1=E8=A7=84=E6=A0=BC=20=E2=80=94=20?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E7=9F=A5=E8=AF=86=E7=AE=A1=E7=90=86=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 替换旧三层模型(rules/references/guides)为 Dify 风格统一知识库: - 3 张新表:knowledge_bases / documents / chunks(切片+向量) - 文档处理管线:PDF/Word/Excel/URL/Markdown/手动录入 → 智能切片 → embedding - 混合意图路由:关键词粗筛 → 向量检索 → LLM 兜底 - AI 客服集成:RAG context 注入 + [ref:xxx] 引用溯源 --- .../2026-05-26-ai-knowledge-base-v2-design.md | 1155 +++++++++++++++++ 1 file changed, 1155 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-26-ai-knowledge-base-v2-design.md diff --git a/docs/superpowers/specs/2026-05-26-ai-knowledge-base-v2-design.md b/docs/superpowers/specs/2026-05-26-ai-knowledge-base-v2-design.md new file mode 100644 index 0000000..a852d3e --- /dev/null +++ b/docs/superpowers/specs/2026-05-26-ai-knowledge-base-v2-design.md @@ -0,0 +1,1155 @@ +# 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() +); + +-- 向量检索核心索引(IVFFlat,适合 < 100 万切片) +CREATE INDEX idx_chunk_embedding ON ai_knowledge_chunks + USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); + +-- 按知识库查询 +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. 移除