|
|
@@ -0,0 +1,614 @@
|
|
|
+# Nihaisha RAG — 合并部署与水平扩容分析
|
|
|
+
|
|
|
+> **版本**: v1.0
|
|
|
+> **日期**: 2026-07-28
|
|
|
+> **目标**: 将倪海厦 RAG 代码合并到药典助手项目 `D:\project\AIyaodianzhushou`,分析部署方案和扩容路径
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 目录
|
|
|
+
|
|
|
+1. [现有项目对比](#1-现有项目对比)
|
|
|
+2. [合并策略](#2-合并策略)
|
|
|
+3. [代码合并方案](#3-代码合并方案)
|
|
|
+4. [部署拓扑](#4-部署拓扑)
|
|
|
+5. [水平扩容路径](#5-水平扩容路径)
|
|
|
+6. [数据库规划](#6-数据库规划)
|
|
|
+7. [API 设计](#7-api-设计)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1. 现有项目对比
|
|
|
+
|
|
|
+| 维度 | 药典助手 (AIyaodianzhushou) | 倪海厦 RAG (nihaisha-nishi-tcm) |
|
|
|
+|------|:---:|:---:|
|
|
|
+| **数据依赖** | 2025 年版中国药典 | 倪海厦中医课程资料(22 个 PDF)|
|
|
|
+| **框架** | Spring Boot 3.3 + JPA/Hibernate | 计划 Spring Boot 3.3 + MyBatis |
|
|
|
+| **Java** | 21 | 21 |
|
|
|
+| **数据库** | PostgreSQL 16 + pgvector | PostgreSQL 16 + pgvector(新) |
|
|
|
+| **缓存** | Redis 7 | Redis 7(可共用) |
|
|
|
+| **LLM** | 百炼 DashScope (Qwen) | Ollama 主 + 百炼降级 |
|
|
|
+| **向量嵌入** | DashScope text-embedding-v3 (1024维) | BGE-M3 ONNX Runtime 本地 (1024维) |
|
|
|
+| **重排序** | 规则型 Reranker(关键词+权重) | BGE-Reranker ONNX Runtime 本地 |
|
|
|
+| **鉴权** | Spring Security + JWT | 需共用药典的鉴权体系 |
|
|
|
+| **端口** | 9000 | 计划 8080 |
|
|
|
+| **构建** | 单模块 Maven | 计划单模块 Maven |
|
|
|
+| **部署** | Standalone JAR + supervisord + nginx | — |
|
|
|
+| **ORM** | JPA/Hibernate | MyBatis |
|
|
|
+
|
|
|
+### 关键冲突点
|
|
|
+
|
|
|
+| 冲突 | 分析 |
|
|
|
+|------|------|
|
|
|
+| **ORM 不一致** | 药典用 JPA,倪海厦计划用 MyBatis。同一项目混用两套 ORM 维护成本高 |
|
|
|
+| **Embedding 模型不同** | 药典用 DashScope API(远程),倪海厦用 ONNX(本地)。两个模型是独立的,不冲突 |
|
|
|
+| **端口不同** | 如果不合并,需要两个端口、两个 JAR、两套部署 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 2. 合并策略
|
|
|
+
|
|
|
+### 2.1 推荐方案:统一 ORM + 独立模块
|
|
|
+
|
|
|
+```
|
|
|
+AIyaodianzhushou/
|
|
|
+├── backend-java/ # 现有项目(保持 JPA)
|
|
|
+│ ├── pom.xml
|
|
|
+│ ├── src/main/java/com/pharmacopoeia/
|
|
|
+│ │ ├── PharmacopoeiaApplication.java
|
|
|
+│ │ ├── entity/ # 药典实体(JPA)
|
|
|
+│ │ ├── repository/ # JPA Repository
|
|
|
+│ │ ├── service/ # 药典服务
|
|
|
+│ │ ├── controller/ # 药典 Controller
|
|
|
+│ │ ├── config/ # 共用配置
|
|
|
+│ │ ├── security/ # 共用鉴权
|
|
|
+│ │ │
|
|
|
+│ │ └── nihaisha/ # ★ 新增:倪海厦 RAG 子包
|
|
|
+│ │ ├── entity/ # 倪海厦实体(JPA,统一风格)
|
|
|
+│ │ ├── repository/ # JPA Repository
|
|
|
+│ │ ├── service/ # 倪海厦检索服务
|
|
|
+│ │ ├── controller/ # 倪海厦 Controller
|
|
|
+│ │ ├── engine/ # ONNX Runtime 引擎
|
|
|
+│ │ └── config/ # 倪海厦专属配置
|
|
|
+│ │
|
|
|
+│ └── src/main/resources/
|
|
|
+│ ├── application.yml
|
|
|
+│ └── db/migration/ # Flyway 迁移(新增倪海厦表)
|
|
|
+```
|
|
|
+
|
|
|
+### 2.2 为什么改 JPA 而不是 MyBatis
|
|
|
+
|
|
|
+| 维度 | 用 JPA(推荐) | 混用 MyBatis + JPA |
|
|
|
+|------|:---:|:---:|
|
|
|
+| 维护成本 | ✅ 一套规范,团队只学一个 | ❌ 两套规范,排查问题分裂 |
|
|
|
+| 代码一致性 | ✅ entity/repository 模式统一 | ❌ entity + mapper.xml 双模式 |
|
|
|
+| 连接池 | ✅ 共用 HikariCP | ✅ 可共用 |
|
|
|
+| 事务管理 | ✅ 统一 `@Transactional` | ⚠️ 需注意跨 ORM 事务 |
|
|
|
+| Spring Data 生态 | ✅ 审计、分页、Specification 统一 | ❌ 各用各的 |
|
|
|
+| 动态查询 | JPA Criteria / QueryDSL | MyBatis XML 更灵活(但药典已有 JPA) |
|
|
|
+
|
|
|
+**结论**:药典项目已经用 JPA 跑了生产,强行引入 MyBatis 会增加认知负担。倪海厦的 11 张表查询用 JPA + Native Query(向量搜索、全文搜索本来就是写 SQL 的)完全够用。
|
|
|
+
|
|
|
+### 2.3 共用 vs 独立
|
|
|
+
|
|
|
+| 共用 | 独立 |
|
|
|
+|------|------|
|
|
|
+| Spring Security + JWT 鉴权 | ONNX Runtime 引擎(BGE-M3 + Reranker) |
|
|
|
+| Redis 缓存 | 数据层(独立的表,不跨库 join) |
|
|
|
+| HikariCP 连接池 | Controller(独立路径 `/api/v1/nihaisha/`) |
|
|
|
+| Flyway 迁移 | 100 MB 日志文件(追加到 logback) |
|
|
|
+| 日志框架 (Logback) | |
|
|
|
+| 同一个 PostgreSQL 实例 | |
|
|
|
+| 同一个 Nginx 反向代理 | |
|
|
|
+| 同一个 supervisord 进程 | |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3. 代码合并方案
|
|
|
+
|
|
|
+### 3.1 目录结构
|
|
|
+
|
|
|
+```
|
|
|
+backend-java/
|
|
|
+├── pom.xml # 加入 ONNX Runtime 依赖
|
|
|
+├── src/main/java/com/pharmacopoeia/
|
|
|
+│ ├── PharmacopoeiaApplication.java
|
|
|
+│ │
|
|
|
+│ ├── config/ # 现有共用配置
|
|
|
+│ │ ├── SecurityConfig.java
|
|
|
+│ │ ├── WebConfig.java
|
|
|
+│ │ └── RedisConfig.java
|
|
|
+│ │
|
|
|
+│ ├── entity/ # 药典实体 (不变)
|
|
|
+│ ├── repository/ # 药典 Repository (不变)
|
|
|
+│ ├── service/ # 药典服务 (不变)
|
|
|
+│ ├── controller/ # 药典 Controller (不变)
|
|
|
+│ │
|
|
|
+│ ├── nihaisha/ # ★ 倪海厦 RAG
|
|
|
+│ │ ├── entity/
|
|
|
+│ │ │ ├── NihMeta.java
|
|
|
+│ │ │ ├── NihDocument.java
|
|
|
+│ │ │ ├── NihParagraph.java
|
|
|
+│ │ │ ├── NihRetrievalUnit.java
|
|
|
+│ │ │ ├── NihVectorEmbedding.java
|
|
|
+│ │ │ ├── NihKnowledgeUnit.java
|
|
|
+│ │ │ ├── NihGuideNode.java
|
|
|
+│ │ │ ├── NihEvidenceRecord.java
|
|
|
+│ │ │ ├── NihGraphEntity.java
|
|
|
+│ │ │ └── NihRelation.java
|
|
|
+│ │ │
|
|
|
+│ │ ├── repository/
|
|
|
+│ │ │ ├── NihMetaRepository.java
|
|
|
+│ │ │ ├── NihDocumentRepository.java
|
|
|
+│ │ │ ├── NihParagraphRepository.java
|
|
|
+│ │ │ ├── NihRetrievalUnitRepository.java
|
|
|
+│ │ │ ├── NihVectorEmbeddingRepository.java
|
|
|
+│ │ │ ├── NihKnowledgeUnitRepository.java
|
|
|
+│ │ │ ├── NihGuideNodeRepository.java
|
|
|
+│ │ │ ├── NihEvidenceRecordRepository.java
|
|
|
+│ │ │ ├── NihGraphEntityRepository.java
|
|
|
+│ │ │ └── NihRelationRepository.java
|
|
|
+│ │ │
|
|
|
+│ │ ├── service/
|
|
|
+│ │ │ ├── NihSearchService.java # 单通道检索
|
|
|
+│ │ │ ├── NihHybridSearchService.java # 混合检索 + RRF
|
|
|
+│ │ │ ├── NihKnowledgeService.java # 知识三元组
|
|
|
+│ │ │ ├── NihGraphService.java # 知识图谱
|
|
|
+│ │ │ ├── NihEvidenceService.java # 证据链
|
|
|
+│ │ │ ├── NihGuideNodeService.java # 导航节点
|
|
|
+│ │ │ ├── NihQueryRewriterService.java # 查询改写
|
|
|
+│ │ │ ├── NihEmbeddingService.java # ONNX BGE-M3
|
|
|
+│ │ │ └── NihRerankerService.java # ONNX BGE-Reranker
|
|
|
+│ │ │
|
|
|
+│ │ ├── controller/
|
|
|
+│ │ │ ├── NihSearchController.java # /api/v1/nihaisha/search
|
|
|
+│ │ │ ├── NihKnowledgeController.java # /api/v1/nihaisha/knowledge
|
|
|
+│ │ │ ├── NihGuideController.java # /api/v1/nihaisha/guide
|
|
|
+│ │ │ ├── NihGraphController.java # /api/v1/nihaisha/graph
|
|
|
+│ │ │ └── NihEvidenceController.java # /api/v1/nihaisha/evidence
|
|
|
+│ │ │
|
|
|
+│ │ ├── engine/
|
|
|
+│ │ │ ├── OnnxEmbeddingEngine.java # BGE-M3 ONNX 会话
|
|
|
+│ │ │ ├── OnnxRerankerEngine.java # BGE-Reranker ONNX 会话
|
|
|
+│ │ │ └── BertTokenizer.java # HuggingFace Tokenizer
|
|
|
+│ │ │
|
|
|
+│ │ ├── dto/
|
|
|
+│ │ │ ├── request/
|
|
|
+│ │ │ └── response/
|
|
|
+│ │ │
|
|
|
+│ │ ├── enums/
|
|
|
+│ │ │ ├── UnitType.java
|
|
|
+│ │ │ ├── KnowledgeUnitType.java
|
|
|
+│ │ │ └── ...
|
|
|
+│ │ │
|
|
|
+│ │ └── config/
|
|
|
+│ │ └── OnnxRuntimeConfig.java
|
|
|
+│ │
|
|
|
+│ └── security/ # 共用鉴权(需补充倪海厦路径)
|
|
|
+│
|
|
|
+├── src/main/resources/
|
|
|
+│ ├── application.yml
|
|
|
+│ ├── application-dev.yml
|
|
|
+│ ├── application-prod.yml
|
|
|
+│ ├── logback-spring.xml
|
|
|
+│ └── db/migration/
|
|
|
+│ ├── V1__init_core.sql # 现有药典表
|
|
|
+│ ├── V2__init_exam.sql
|
|
|
+│ ├── V3__init_nihaisha_extensions.sql # ★ pgvector + pg_trgm
|
|
|
+│ ├── V4__init_nihaisha_core.sql # ★ meta, documents, paragraphs
|
|
|
+│ ├── V5__init_nihaisha_retrieval.sql # ★ retrieval_units, vector_embeddings
|
|
|
+│ ├── V6__init_nihaisha_knowledge.sql # ★ knowledge_units, guide_nodes
|
|
|
+│ ├── V7__init_nihaisha_graph.sql # ★ evidence_records, entities, relations
|
|
|
+│ └── V8__init_nihaisha_fulltext.sql # ★ tsvector + trigram 索引
|
|
|
+│
|
|
|
+├── models/ # ONNX 模型文件
|
|
|
+│ ├── bge-m3-fp16/
|
|
|
+│ │ ├── model.onnx
|
|
|
+│ │ └── tokenizer.json
|
|
|
+│ └── bge-reranker-fp16/
|
|
|
+│ ├── model.onnx
|
|
|
+│ └── tokenizer.json
|
|
|
+│
|
|
|
+└── Dockerfile # ★ 新增:应用容器化
|
|
|
+```
|
|
|
+
|
|
|
+### 3.2 ORM 选择:JPA + Native Query
|
|
|
+
|
|
|
+向量搜索和全文搜索需要写原生 SQL,用 `@Query(nativeQuery=true)` 或 `JdbcTemplate`。药典项目已经在 `RetrieverService` 中这样做了(pgvector `<=>` 通过 JdbcTemplate 执行)。
|
|
|
+
|
|
|
+```java
|
|
|
+// NihVectorEmbeddingRepository.java
|
|
|
+public interface NihVectorEmbeddingRepository extends JpaRepository<NihVectorEmbedding, String> {
|
|
|
+
|
|
|
+ // pgvector 近似搜索 — 原生 SQL
|
|
|
+ @Query(value = """
|
|
|
+ SELECT ru.*, p.title, p.text, p.source_path, p.page_start, p.page_end,
|
|
|
+ ve.embedding <=> CAST(:queryVector AS vector) AS distance
|
|
|
+ FROM nih_vector_embeddings ve
|
|
|
+ JOIN nih_retrieval_units ru ON ru.unit_id = ve.unit_id
|
|
|
+ JOIN nih_paragraphs p ON p.paragraph_id = ru.paragraph_id
|
|
|
+ ORDER BY ve.embedding <=> CAST(:queryVector AS vector)
|
|
|
+ LIMIT :limit
|
|
|
+ """, nativeQuery = true)
|
|
|
+ List<Object[]> searchByVector(String queryVector, int limit);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3.3 表名前缀
|
|
|
+
|
|
|
+为避免与药典现有表冲突,倪海厦表统一加 `nih_` 前缀:
|
|
|
+
|
|
|
+| 原始表名 | 实际表名 |
|
|
|
+|----------|----------|
|
|
|
+| `meta` | `nih_meta` |
|
|
|
+| `documents` | `nih_documents` |
|
|
|
+| `paragraphs` | `nih_paragraphs` |
|
|
|
+| `retrieval_units` | `nih_retrieval_units` |
|
|
|
+| `vector_embeddings` | `nih_vector_embeddings` |
|
|
|
+| `knowledge_units` | `nih_knowledge_units` |
|
|
|
+| `guide_nodes` | `nih_guide_nodes` |
|
|
|
+| `evidence_records` | `nih_evidence_records` |
|
|
|
+| `entities` | `nih_entities` |
|
|
|
+| `relations` | `nih_relations` |
|
|
|
+| `eval_cases` | `nih_eval_cases` |
|
|
|
+
|
|
|
+> 药典已有 `entities` 相关概念?检查后没有冲突,但仍加前缀隔离,便于未来分库。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4. 部署拓扑
|
|
|
+
|
|
|
+### 4.1 单机部署(当前)
|
|
|
+
|
|
|
+```
|
|
|
+┌─────────────────────────────────────────────────────────┐
|
|
|
+│ 线上服务器 │
|
|
|
+│ │
|
|
|
+│ ┌──────────────────────────────────────────────────┐ │
|
|
|
+│ │ Nginx (:80/:443) │ │
|
|
|
+│ │ /api/v1/chat/* → localhost:9000 (药典对话) │ │
|
|
|
+│ │ /api/v1/drug/* → localhost:9000 (药典药品) │ │
|
|
|
+│ │ /api/v1/nihaisha/* → localhost:9000 (倪海厦 RAG) │ │
|
|
|
+│ │ /api/v1/exam/* → localhost:9000 (药典考试) │ │
|
|
|
+│ └──────────────────────┬───────────────────────────┘ │
|
|
|
+│ │ │
|
|
|
+│ ┌──────────────────────┴───────────────────────────┐ │
|
|
|
+│ │ pharmacopoeia-ai.jar (:9000) │ │
|
|
|
+│ │ │ │
|
|
|
+│ │ ┌─────────────┐ ┌────────────────────────────┐ │ │
|
|
|
+│ │ │ 药典服务 │ │ 倪海厦 RAG (nihaisha/) │ │ │
|
|
|
+│ │ │ ├ Chat │ │ ├ Search (四通道) │ │ │
|
|
|
+│ │ │ ├ Drug │ │ ├ Knowledge │ │ │
|
|
|
+│ │ │ ├ Exam │ │ ├ Graph │ │ │
|
|
|
+│ │ │ └ Admin │ │ ├ Evidence │ │ │
|
|
|
+│ │ └──────┬───────┘ │ └───────────┬──────────────┘ │ │
|
|
|
+│ │ │ │ │ │ │
|
|
|
+│ │ ┌──────┴──────────┴─────────────┴──────────────┐ │ │
|
|
|
+│ │ │ 共用基础设施 │ │ │
|
|
|
+│ │ │ ├ Spring Security (JWT 鉴权) │ │ │
|
|
|
+│ │ │ ├ Redis (QA 缓存 + Embedding 缓存) │ │ │
|
|
|
+│ │ │ ├ Flyway (数据库迁移) │ │ │
|
|
|
+│ │ │ ├ ONNX Runtime (BGE-M3 + Reranker) │ │ │
|
|
|
+│ │ │ └ HikariCP (连接池) │ │ │
|
|
|
+│ │ └────────────────────┬──────────────────────────┘ │ │
|
|
|
+│ └───────────────────────┼────────────────────────────┘ │
|
|
|
+│ │ │
|
|
|
+│ ┌───────────────────────┴──────────────────────────┐ │
|
|
|
+│ │ PostgreSQL 16 + pgvector │ │
|
|
|
+│ │ ├ pharmacopoeia 库(药典: drugs, drug_chunks...)│ │
|
|
|
+│ │ └ nih_* 表(倪海厦: 11 张表) │ │
|
|
|
+│ └──────────────────────────────────────────────────┘ │
|
|
|
+│ │
|
|
|
+│ ┌──────────┐ ┌──────────┐ │
|
|
|
+│ │ Redis 7 │ │ 模型文件 │ │
|
|
|
+│ │ (缓存) │ │ bge-m3/ │ │
|
|
|
+│ │ :6379 │ │ bge-reranker/ │
|
|
|
+│ └──────────┘ └──────────┘ │
|
|
|
+└─────────────────────────────────────────────────────────┘
|
|
|
+ │
|
|
|
+ │ HTTP (查询改写)
|
|
|
+ ▼
|
|
|
+┌─────────────────────────┐
|
|
|
+│ 本地 GPU 服务器 │
|
|
|
+│ Ollama │
|
|
|
+│ ├ qwen2.5:14b (主) │
|
|
|
+│ └ :11434 │
|
|
|
+└─────────────────────────┘
|
|
|
+ │ 降级
|
|
|
+ ▼
|
|
|
+┌─────────────────────────┐
|
|
|
+│ 百炼 API (阿里云) │
|
|
|
+│ qwen-plus (兜底) │
|
|
|
+└─────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+### 4.2 Nginx 路由配置
|
|
|
+
|
|
|
+```nginx
|
|
|
+# 倪海厦 RAG API
|
|
|
+location /api/v1/nihaisha/ {
|
|
|
+ proxy_pass http://127.0.0.1:9000;
|
|
|
+ proxy_set_header Host $host;
|
|
|
+ proxy_set_header X-Real-IP $remote_addr;
|
|
|
+ proxy_read_timeout 60s; # 混合搜索可能较慢
|
|
|
+}
|
|
|
+
|
|
|
+# 药典对话(现有,不变)
|
|
|
+location /api/v1/chat/ {
|
|
|
+ proxy_pass http://127.0.0.1:9000;
|
|
|
+ proxy_buffering off; # SSE 流式
|
|
|
+ proxy_read_timeout 300s;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 4.3 资源配置
|
|
|
+
|
|
|
+| 组件 | 内存 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| JVM 堆 | **3 GB**(原 2GB) | 新增 ONNX 模型 + 倪海厦检索 |
|
|
|
+| ONNX 模型 (FP16) | ~1.7 GB | BGE-M3 + Reranker 常驻内存 |
|
|
|
+| PostgreSQL | ~2 GB | shared_buffers |
|
|
|
+| Redis | ~0.5 GB | 缓存 |
|
|
|
+| OS | ~1 GB | |
|
|
|
+| **合计** | **~8 GB** | 线上服务器需 8-16 GB 内存 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 5. 水平扩容路径
|
|
|
+
|
|
|
+### 5.1 阶段 1:单体(当前 → 上线初期)
|
|
|
+
|
|
|
+```
|
|
|
+ Nginx
|
|
|
+ │
|
|
|
+ ┌───────────┴───────────┐
|
|
|
+ │ :9000 │
|
|
|
+ │ pharmacopoeia-ai.jar │
|
|
|
+ │ (药典 + 倪海厦) │
|
|
|
+ └───────────┬───────────┘
|
|
|
+ │
|
|
|
+ ┌───────────┴───────────┐
|
|
|
+ │ PostgreSQL (单机) │
|
|
|
+ └───────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+- **适用**:QPS < 100,数据量 < 100 万条
|
|
|
+- **操作**:无需任何改动,合并代码部署即可
|
|
|
+
|
|
|
+### 5.2 阶段 2:读写分离(流量增长)
|
|
|
+
|
|
|
+```
|
|
|
+ Nginx
|
|
|
+ │
|
|
|
+ ┌───────────┴───────────┐
|
|
|
+ │ 应用服务器 × 2 │
|
|
|
+ │ (药典 + 倪海厦) │
|
|
|
+ │ :9000 :9000 │
|
|
|
+ └───────────┬───────────┘
|
|
|
+ │
|
|
|
+ ┌───────────────┼───────────────┐
|
|
|
+ │ │ │
|
|
|
+ ┌───────┴───────┐ ┌─────┴─────┐ ┌───────┴───────┐
|
|
|
+ │ PG 主库 (写) │ │ PG 从库 1 │ │ PG 从库 2 │
|
|
|
+ │ │ │ (只读) │ │ (只读) │
|
|
|
+ └───────────────┘ └───────────┘ └───────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+**Java 侧改动**:Spring 读写分离数据源配置
|
|
|
+
|
|
|
+```yaml
|
|
|
+spring:
|
|
|
+ datasource:
|
|
|
+ master:
|
|
|
+ url: jdbc:postgresql://pg-master:5432/pharmacopoeia
|
|
|
+ slaves:
|
|
|
+ - url: jdbc:postgresql://pg-slave-1:5432/pharmacopoeia
|
|
|
+ - url: jdbc:postgresql://pg-slave-2:5432/pharmacopoeia
|
|
|
+```
|
|
|
+
|
|
|
+- 搜索请求走从库(倪海厦 RAG 是读密集型)
|
|
|
+- 对话记录写入走主库
|
|
|
+- **适用**:QPS 100-500,读多写少
|
|
|
+
|
|
|
+### 5.3 阶段 3:服务拆分 + 独立扩容
|
|
|
+
|
|
|
+```
|
|
|
+ Nginx / API Gateway
|
|
|
+ │
|
|
|
+ ┌───────────────┼───────────────┐
|
|
|
+ │ │ │
|
|
|
+ ┌───────┴───────┐ ┌─────┴──────┐ ┌──────┴──────┐
|
|
|
+ │ 药典对话服务 │ │ 倪海厦 RAG │ │ 考试服务 │
|
|
|
+ │ × 2 实例 │ │ × 3 实例 │ │ × 1 实例 │
|
|
|
+ │ :9001 │ │ :9002 │ │ :9003 │
|
|
|
+ └───────┬───────┘ └─────┬──────┘ └──────┬──────┘
|
|
|
+ │ │ │
|
|
|
+ └───────────────┼───────────────┘
|
|
|
+ │
|
|
|
+ ┌───────────┴───────────┐
|
|
|
+ │ PostgreSQL 集群 │
|
|
|
+ │ + Redis 集群 │
|
|
|
+ └───────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+**拆分方式**(与当前单模块不冲突,渐进式演进):
|
|
|
+
|
|
|
+```
|
|
|
+backend-java/ # 当前单体
|
|
|
+├── pharmacopoeia-chat/ # 未来:拆为独立模块
|
|
|
+├── pharmacopoeia-exam/ # 未来:拆为独立模块
|
|
|
+├── nihaisha-rag/ # 未来:拆为独立模块
|
|
|
+└── pharmacopoeia-common/ # 共用:entity, security, config
|
|
|
+```
|
|
|
+
|
|
|
+**拆分触发条件**:
|
|
|
+
|
|
|
+| 指标 | 阈值 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| 倪海厦 RAG QPS | > 200 | 单独扩容倪海厦实例 |
|
|
|
+| 药典对话 QPS | > 100 | 单独扩容药典实例 |
|
|
|
+| ONNX 模型内存压力 | JVM 堆 > 4GB | 倪海厦独立部署,独占 ONNX 模型 |
|
|
|
+| 数据库连接数 | > 80 | 加从库或分库 |
|
|
|
+
|
|
|
+### 5.4 分库路径
|
|
|
+
|
|
|
+倪海厦和药典的数据天然隔离(不跨库 join),随时可分库:
|
|
|
+
|
|
|
+```yaml
|
|
|
+# 未来分库配置
|
|
|
+spring:
|
|
|
+ datasource:
|
|
|
+ pharmacopoeia:
|
|
|
+ url: jdbc:postgresql://pg-pharma:5432/pharmacopoeia
|
|
|
+ nihaisha:
|
|
|
+ url: jdbc:postgresql://pg-nihaisha:5432/nihaisha_rag
|
|
|
+```
|
|
|
+
|
|
|
+当前阶段放在同一个 PostgreSQL 实例、同一个 database 内(`nih_` 前缀隔离),减少运维复杂度。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 6. 数据库规划
|
|
|
+
|
|
|
+### 6.1 当前数据库
|
|
|
+
|
|
|
+```
|
|
|
+PostgreSQL 16 (pgvector)
|
|
|
+└── pharmacopoeia 库
|
|
|
+ ├── 药典表(现有 9 张)
|
|
|
+ │ ├── conversations
|
|
|
+ │ ├── messages
|
|
|
+ │ ├── drugs
|
|
|
+ │ ├── drug_chunks
|
|
|
+ │ ├── users
|
|
|
+ │ ├── knowledge_points
|
|
|
+ │ ├── questions
|
|
|
+ │ ├── answer_records
|
|
|
+ │ └── user_progress
|
|
|
+ │
|
|
|
+ └── 倪海厦表(新增 11 张,nih_ 前缀)
|
|
|
+ ├── nih_meta
|
|
|
+ ├── nih_documents
|
|
|
+ ├── nih_paragraphs
|
|
|
+ ├── nih_retrieval_units
|
|
|
+ ├── nih_vector_embeddings # pgvector 向量
|
|
|
+ ├── nih_knowledge_units
|
|
|
+ ├── nih_guide_nodes
|
|
|
+ ├── nih_evidence_records
|
|
|
+ ├── nih_entities
|
|
|
+ ├── nih_relations
|
|
|
+ └── nih_eval_cases
|
|
|
+```
|
|
|
+
|
|
|
+### 6.2 存储增量
|
|
|
+
|
|
|
+| 数据 | 磁盘占用 |
|
|
|
+|------|----------|
|
|
|
+| 药典现有数据 | ~2 GB |
|
|
|
+| 倪海厦段落 + 检索单元 | ~3 GB |
|
|
|
+| 倪海厦向量 (1024维 × 50万) | ~2 GB |
|
|
|
+| 倪海厦索引 (HNSW + GIN + trigram) | ~2 GB |
|
|
|
+| **总计(新增)** | **~7 GB** |
|
|
|
+| **数据库总大小** | **~9 GB** |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 7. API 设计
|
|
|
+
|
|
|
+### 7.1 路径规划
|
|
|
+
|
|
|
+| 领域 | 路径前缀 | 鉴权 |
|
|
|
+|------|----------|:---:|
|
|
|
+| 药典对话 | `/api/v1/chat/**` | ✅ JWT |
|
|
|
+| 药典药品 | `/api/v1/drug/**` | ✅ JWT |
|
|
|
+| 药典考试 | `/api/v1/exam/**` | ✅ JWT |
|
|
|
+| 药典管理 | `/api/v1/admin/**` | ✅ JWT + admin-token |
|
|
|
+| 药典快问 | `/api/v1/yaodian/**` | ❌ 公开 |
|
|
|
+| **倪海厦搜索** | **`/api/v1/nihaisha/search/**`** | **✅ JWT** |
|
|
|
+| **倪海厦知识** | **`/api/v1/nihaisha/knowledge/**`** | **✅ JWT** |
|
|
|
+| **倪海厦导航** | **`/api/v1/nihaisha/guide/**`** | **✅ JWT** |
|
|
|
+| **倪海厦图谱** | **`/api/v1/nihaisha/graph/**`** | **✅ JWT** |
|
|
|
+| **倪海厦证据** | **`/api/v1/nihaisha/evidence/**`** | **✅ JWT** |
|
|
|
+| 健康检查 | `/health` | ❌ 公开 |
|
|
|
+
|
|
|
+### 7.2 Security 配置补充
|
|
|
+
|
|
|
+在现有 `SecurityConfig` 中补充倪海厦路径:
|
|
|
+
|
|
|
+```java
|
|
|
+// 现有公开路径
|
|
|
+"/health", "/api/v1/auth/**", "/api/v1/yaodian/**", "/static/**"
|
|
|
+
|
|
|
+// 倪海厦搜索暂不单独公开,走 JWT 鉴权(与药典对话一致)
|
|
|
+// 所有 /api/v1/nihaisha/** 需要 Bearer Token
|
|
|
+```
|
|
|
+
|
|
|
+### 7.3 前端问答框模型选择
|
|
|
+
|
|
|
+前端需要一个问答框,支持选择模型。在现有药典对话系统基础上扩展:
|
|
|
+
|
|
|
+```
|
|
|
+POST /api/v1/nihaisha/search/hybrid
|
|
|
+Authorization: Bearer <jwt>
|
|
|
+
|
|
|
+Request:
|
|
|
+{
|
|
|
+ "query": "桂枝汤的组成和用法",
|
|
|
+ "model": "nihaisha", // ★ 新增字段
|
|
|
+ "channels": ["vector", "text", "knowledge", "graph"],
|
|
|
+ "limit": 20
|
|
|
+}
|
|
|
+
|
|
|
+Response:
|
|
|
+{
|
|
|
+ "results": [...],
|
|
|
+ "tookMs": 380,
|
|
|
+ "model": "nihaisha" // 回显模型选择
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+前端对话页可以加一个下拉选择:
|
|
|
+- "药典助手" → 走 `/api/v1/chat/stream`(现有)
|
|
|
+- "倪海厦中医" → 走 `/api/v1/nihaisha/search/hybrid`(新增)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 附录 A:pom.xml 新增依赖
|
|
|
+
|
|
|
+在现有 `backend-java/pom.xml` 中追加:
|
|
|
+
|
|
|
+```xml
|
|
|
+<!-- ONNX Runtime — BGE-M3 Embedding + Reranker 本地推理 -->
|
|
|
+<dependency>
|
|
|
+ <groupId>com.microsoft.onnxruntime</groupId>
|
|
|
+ <artifactId>onnxruntime</artifactId>
|
|
|
+ <version>1.18.0</version>
|
|
|
+</dependency>
|
|
|
+
|
|
|
+<!-- HuggingFace Tokenizers — 加载 tokenizer.json(Rust JNI) -->
|
|
|
+<dependency>
|
|
|
+ <groupId>com.huggingface</groupId>
|
|
|
+ <artifactId>tokenizers</artifactId>
|
|
|
+ <version>0.21.0</version>
|
|
|
+</dependency>
|
|
|
+```
|
|
|
+
|
|
|
+> 不需要加 MyBatis 依赖,统一用 JPA;不需要加 Flyway 依赖,药典项目已有。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 附录 B:扩容决策树
|
|
|
+
|
|
|
+```
|
|
|
+QPS < 100 且 内存 < 8GB?
|
|
|
+ ├── 是 → 阶段 1:单体,不做任何拆分
|
|
|
+ └── 否 → 倪海厦 RAG QPS > 200?
|
|
|
+ ├── 是 → 阶段 3:拆分倪海厦为独立服务
|
|
|
+ └── 否 → 数据库 CPU > 70%?
|
|
|
+ ├── 是 → 阶段 2:加 PG 从库,读写分离
|
|
|
+ └── 否 → 阶段 2:加应用实例 + 负载均衡
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+> **文档版本**: v1.0 | **下一步**: 确认方案后开始写代码
|