|
|
@@ -0,0 +1,374 @@
|
|
|
+# 线上部署与数据导入完整操作方案
|
|
|
+
|
|
|
+> **适用环境**: Linux 生产服务器
|
|
|
+> **项目路径**: `/opt/pharmacopoeia-ai`
|
|
|
+> **药典数据源**: `/opt/2025`(DOCX 文件)
|
|
|
+> **操作前提**: 已拉取最新代码,JDK 21 可用
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、操作总览
|
|
|
+
|
|
|
+```
|
|
|
+Step 0: 确认环境(1 分钟)
|
|
|
+Step 1: 启动基础设施 PostgreSQL + Redis(2 分钟)
|
|
|
+Step 2: 初始化/迁移数据库(1 分钟)
|
|
|
+Step 3: 启动 Java 后端验证连通性(2 分钟)
|
|
|
+Step 4: 导入 Wiki 临床数据 via import_all.py(~2 分钟)
|
|
|
+Step 5: 导入药典 DOCX 原文 via docx_ingest.py(~数小时)
|
|
|
+Step 6: 验证搜索功能(2 分钟)
|
|
|
+Step 7: 正式启动服务(2 分钟)
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、详细步骤
|
|
|
+
|
|
|
+### Step 0: 确认环境
|
|
|
+
|
|
|
+```bash
|
|
|
+# 0.1 确认 Java 版本
|
|
|
+java -version
|
|
|
+# 期望: java version "21.x.x"
|
|
|
+
|
|
|
+# 如果 JAVA_HOME 未设置:
|
|
|
+export JAVA_HOME=/usr/lib/jvm/jdk-21
|
|
|
+export PATH=$JAVA_HOME/bin:$PATH
|
|
|
+
|
|
|
+# 0.2 确认项目目录
|
|
|
+cd /opt/pharmacopoeia-ai
|
|
|
+git status
|
|
|
+ls data-pipeline/ backend-java/ deploy/ database/
|
|
|
+
|
|
|
+# 0.3 确认数据源存在
|
|
|
+ls /opt/2025/output*/品种正文/*.docx | head -5
|
|
|
+# 应能看到 DOCX 文件
|
|
|
+
|
|
|
+# 0.4 创建日志目录
|
|
|
+mkdir -p /var/log/pharmacopoeia
|
|
|
+
|
|
|
+# 0.5 确认 .env 配置
|
|
|
+cat .env | grep QWEN_API_KEY
|
|
|
+# 确保 QWEN_API_KEY 已填写真实的 DashScope API Key
|
|
|
+# 如果 .env 不存在,复制模板:
|
|
|
+# cp .env.example .env && vim .env
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 1: 启动基础设施
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /opt/pharmacopoeia-ai/deploy
|
|
|
+
|
|
|
+# 启动 PostgreSQL + Redis
|
|
|
+docker-compose up -d
|
|
|
+
|
|
|
+# 等待健康检查通过(约 15 秒)
|
|
|
+sleep 15
|
|
|
+docker-compose ps
|
|
|
+# pharmacopoeia-pg Up (healthy)
|
|
|
+# pharmacopoeia-redis Up (healthy)
|
|
|
+
|
|
|
+# 验证 PG 连接
|
|
|
+docker exec pharmacopoeia-pg pg_isready -U postgres
|
|
|
+# 输出: /var/run/postgresql:5432 - accepting connections
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 2: 初始化/迁移数据库
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /opt/pharmacopoeia-ai
|
|
|
+
|
|
|
+# 2.1 导入表结构(首次部署)
|
|
|
+docker exec -i pharmacopoeia-pg psql -U postgres -d pharmacopoeia < database/schema.sql
|
|
|
+
|
|
|
+# 2.2 执行 json → jsonb 迁移(如果是旧库升级)
|
|
|
+docker exec -i pharmacopoeia-pg psql -U postgres -d pharmacopoeia < database/migrate_json_to_jsonb.sql
|
|
|
+
|
|
|
+# 2.3 确认表已创建
|
|
|
+docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c "\dt"
|
|
|
+# 期望看到: drugs, drug_chunks, knowledge_points, questions, conversations, messages, users, user_progress, answer_records
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 3: 启动 Java 后端(验证连通性)
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /opt/pharmacopoeia-ai/backend-java
|
|
|
+
|
|
|
+# 3.1 编译打包
|
|
|
+export JAVA_HOME=/usr/lib/jvm/jdk-21
|
|
|
+mvn clean package -DskipTests -q
|
|
|
+# 输出: BUILD SUCCESS
|
|
|
+
|
|
|
+# 3.2 临时启动验证(前台运行,Ctrl+C 可停止)
|
|
|
+java -jar target/pharmacopoeia-ai-1.0.0.jar
|
|
|
+
|
|
|
+# 或以后台方式启动:
|
|
|
+# nohup java -Xms512m -Xmx2g -Dfile.encoding=UTF-8 \
|
|
|
+# -jar target/pharmacopoeia-ai-1.0.0.jar \
|
|
|
+# > /var/log/pharmacopoeia/backend.log 2>&1 &
|
|
|
+
|
|
|
+# 3.3 验证健康检查
|
|
|
+curl http://localhost:9000/api/v1/health
|
|
|
+# 期望: {"status":"UP"}
|
|
|
+
|
|
|
+# 3.4 验证当前数据量(此时应为零)
|
|
|
+curl http://localhost:9000/api/v1/admin/stats
|
|
|
+# 期望: {"total_drugs":0, "total_chunks":0, "total_queries":0, ...}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 4: 导入 Wiki 临床数据
|
|
|
+
|
|
|
+**数据来源**: `data-pipeline/data/wiki_merged.json`(13 个药品的维基百科临床专著,含概述/适应症/药理/不良反应等)+ `sample_drugs.json`(4 个药典示例)+ `drug_guides.json`(4 个用药指导)
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /opt/pharmacopoeia-ai/data-pipeline
|
|
|
+
|
|
|
+# 4.1 安装 Python 依赖
|
|
|
+pip install httpx sqlalchemy asyncpg psycopg2-binary python-docx
|
|
|
+
|
|
|
+# 4.2 执行导入
|
|
|
+python import_all.py
|
|
|
+```
|
|
|
+
|
|
|
+**预期输出**:
|
|
|
+```
|
|
|
+📂 扫描数据目录: .../data-pipeline/data
|
|
|
+ ✅ sample_drugs.json — 兼容,将导入
|
|
|
+ ✅ wiki_merged.json — 兼容,将导入
|
|
|
+ ✅ drug_guides.json — 兼容,将导入
|
|
|
+ ⏭️ drug_index.json — 跳过
|
|
|
+ ⏭️ catalog_volume1.json — 跳过
|
|
|
+ ...
|
|
|
+🎉 全部导入完成!
|
|
|
+```
|
|
|
+
|
|
|
+**耗时**: 约 1-2 分钟(~200 个 chunk 向量化)
|
|
|
+
|
|
|
+**验证**:
|
|
|
+```bash
|
|
|
+curl http://localhost:9000/api/v1/admin/stats
|
|
|
+# total_drugs 应为 21 左右
|
|
|
+
|
|
|
+# 验证甲硝唑、布洛芬等已入库
|
|
|
+curl -s http://localhost:9000/api/v1/drug/search?keyword=甲硝唑 | python3 -m json.tool | head -20
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 5: 导入药典 DOCX 原文
|
|
|
+
|
|
|
+**数据来源**: `/opt/2025/` 下 6317 个 DOCX 文件(2025 年版中国药典全文)
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /opt/pharmacopoeia-ai/data-pipeline
|
|
|
+
|
|
|
+# 5.1 确认环境变量
|
|
|
+export DOCX_SOURCE_DIR=/opt/2025
|
|
|
+export QWEN_API_KEY=$(grep QWEN_API_KEY ../.env | cut -d= -f2)
|
|
|
+
|
|
|
+# 5.2 执行导入(建议在 screen/tmux 中运行,防止断连)
|
|
|
+screen -S ingest
|
|
|
+python docx_ingest.py
|
|
|
+# Ctrl+A D 分离 screen,screen -r ingest 重新连接
|
|
|
+```
|
|
|
+
|
|
|
+**预期输出**:
|
|
|
+```
|
|
|
+📂 扫描 DOCX 文件...
|
|
|
+ 发现 6317 个 DOCX 文件
|
|
|
+📦 解析完成: 6xxx 个有效条目 (跳过 xx 个)
|
|
|
+ 分类分布:
|
|
|
+ 化学药: 2930
|
|
|
+ 中药: 2276
|
|
|
+ 通则: 473
|
|
|
+ 药用辅料: 387
|
|
|
+ ...
|
|
|
+🚀 第 1/13x 批 (50 个药品) ...
|
|
|
+ ✂️ 250 个 chunks,向量化中...
|
|
|
+ 向量化: 10/250
|
|
|
+ 向量化: 20/250
|
|
|
+ ...
|
|
|
+ ✅ 入库: 50 药品, 250 chunks
|
|
|
+
|
|
|
+🚀 第 2/13x 批 ...
|
|
|
+```
|
|
|
+
|
|
|
+**耗时估算**:
|
|
|
+
|
|
|
+| 阶段 | 数量 | 耗时 |
|
|
|
+|------|------|------|
|
|
|
+| 解析 DOCX | 6317 个 | ~5 分钟 |
|
|
|
+| 向量化 | ~35,000 个 chunk / 10 条每批 = 3500 次 API 调用 | ~2-3 小时 |
|
|
|
+| 写入 PG | ~35,000 行 | ~5 分钟 |
|
|
|
+| **合计** | | **约 2-4 小时** |
|
|
|
+
|
|
|
+**断点续传**: 脚本使用 `ON CONFLICT DO NOTHING`,重复运行不会产生重复数据。如果中途中断,重新运行即可从断点继续(已入库的会被跳过)。
|
|
|
+
|
|
|
+**监控进度**:
|
|
|
+```bash
|
|
|
+# 另一个终端,每隔 30 秒查看入库量
|
|
|
+watch -n 30 "docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c 'SELECT COUNT(*) AS total_chunks FROM drug_chunks;'"
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 6: 验证搜索功能
|
|
|
+
|
|
|
+```bash
|
|
|
+# 6.1 确认数据量
|
|
|
+curl -s http://localhost:9000/api/v1/admin/stats | python3 -m json.tool
|
|
|
+# total_drugs: ~6300+, total_chunks: ~35000+
|
|
|
+
|
|
|
+# 6.2 测试药品搜索
|
|
|
+curl -s "http://localhost:9000/api/v1/drug/search?keyword=布洛芬" | python3 -m json.tool | head -30
|
|
|
+
|
|
|
+# 6.3 测试 AI 问答(非流式)
|
|
|
+curl -s -X POST http://localhost:9000/api/v1/chat/ask \
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
+ -d '{"message":"布洛芬缓释胶囊的用法用量"}' | python3 -m json.tool | head -50
|
|
|
+
|
|
|
+# 6.4 测试 AI 问答(流式 SSE)
|
|
|
+curl -N -X POST http://localhost:9000/api/v1/chat/stream \
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
+ -d '{"message":"甲硝唑的不良反应有哪些"}'
|
|
|
+
|
|
|
+# 6.5 验证 Wiki 数据(临床专著格式)
|
|
|
+curl -s "http://localhost:9000/api/v1/drug/search?keyword=二甲双胍" | python3 -m json.tool | head -20
|
|
|
+
|
|
|
+# 6.6 测试分类树
|
|
|
+curl -s http://localhost:9000/api/v1/drug/category/tree | python3 -m json.tool | head -20
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### Step 7: 正式启动服务
|
|
|
+
|
|
|
+```bash
|
|
|
+# 7.1 关闭临时 Java 进程
|
|
|
+pkill -f pharmacopoeia-ai-1.0.0.jar
|
|
|
+
|
|
|
+# 7.2 使用 supervisor 管理(推荐)
|
|
|
+cp deploy/supervisord-java.conf /etc/supervisor/conf.d/pharmacopoeia.conf
|
|
|
+
|
|
|
+# 编辑 supervisor 配置,填入真实环境变量
|
|
|
+vim /etc/supervisor/conf.d/pharmacopoeia.conf
|
|
|
+# 修改 environment 行:
|
|
|
+# POSTGRES_PASSWORD="实际密码",
|
|
|
+# QWEN_API_KEY="实际的Key"
|
|
|
+
|
|
|
+supervisorctl reread
|
|
|
+supervisorctl update
|
|
|
+supervisorctl start pharmacopoeia-backend
|
|
|
+
|
|
|
+# 7.3 或者用 systemd
|
|
|
+cat > /etc/systemd/system/pharmacopoeia.service << 'EOF'
|
|
|
+[Unit]
|
|
|
+Description=Pharmacopoeia AI Backend
|
|
|
+After=network.target docker.service
|
|
|
+
|
|
|
+[Service]
|
|
|
+Type=simple
|
|
|
+User=root
|
|
|
+WorkingDirectory=/opt/pharmacopoeia-ai/backend-java
|
|
|
+Environment="JAVA_HOME=/usr/lib/jvm/jdk-21"
|
|
|
+Environment="POSTGRES_PASSWORD=pharma2025"
|
|
|
+Environment="QWEN_API_KEY=sk-your-key"
|
|
|
+ExecStart=/usr/lib/jvm/jdk-21/bin/java -Xms512m -Xmx2g -Dfile.encoding=UTF-8 -jar target/pharmacopoeia-ai-1.0.0.jar
|
|
|
+Restart=always
|
|
|
+RestartSec=10
|
|
|
+StandardOutput=append:/var/log/pharmacopoeia/backend.log
|
|
|
+StandardError=append:/var/log/pharmacopoeia/backend-error.log
|
|
|
+
|
|
|
+[Install]
|
|
|
+WantedBy=multi-user.target
|
|
|
+EOF
|
|
|
+
|
|
|
+systemctl daemon-reload
|
|
|
+systemctl enable pharmacopoeia
|
|
|
+systemctl start pharmacopoeia
|
|
|
+systemctl status pharmacopoeia
|
|
|
+
|
|
|
+# 7.4 最终验证
|
|
|
+curl http://localhost:9000/api/v1/health
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、故障排查
|
|
|
+
|
|
|
+### PG 连接失败
|
|
|
+```bash
|
|
|
+docker logs pharmacopoeia-pg --tail 20
|
|
|
+docker exec pharmacopoeia-pg pg_isready -U postgres
|
|
|
+```
|
|
|
+
|
|
|
+### Embedding API 报错
|
|
|
+```bash
|
|
|
+# 检查 QWEN_API_KEY 是否正确
|
|
|
+grep QWEN_API_KEY /opt/pharmacopoeia-ai/.env
|
|
|
+# 手动测试 API
|
|
|
+curl -X POST https://dashscope.aliyuncs.com/api/v1/services/embeddings/text-embedding/text-embedding \
|
|
|
+ -H "Authorization: Bearer $QWEN_API_KEY" \
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
+ -d '{"model":"text-embedding-v3","input":{"texts":["测试"]},"parameters":{"text_type":"query"}}'
|
|
|
+```
|
|
|
+
|
|
|
+### Java 后端启动失败
|
|
|
+```bash
|
|
|
+# 查看错误日志
|
|
|
+tail -100 /var/log/pharmacopoeia/backend-error.log
|
|
|
+# 常见原因: PG 未启动、端口被占用、API Key 无效
|
|
|
+```
|
|
|
+
|
|
|
+### DOCX 导入中断恢复
|
|
|
+```bash
|
|
|
+# docx_ingest.py 使用 ON CONFLICT DO NOTHING,直接重新运行即可
|
|
|
+cd /opt/pharmacopoeia-ai/data-pipeline
|
|
|
+python docx_ingest.py
|
|
|
+```
|
|
|
+
|
|
|
+### 搜索无结果
|
|
|
+```bash
|
|
|
+# 确认数据已入库
|
|
|
+docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c "
|
|
|
+SELECT COUNT(*) AS drugs FROM drugs WHERE is_active=TRUE;
|
|
|
+SELECT COUNT(*) AS chunks FROM drug_chunks WHERE vec IS NOT NULL;
|
|
|
+SELECT name FROM drugs WHERE name LIKE '%布洛芬%' LIMIT 5;
|
|
|
+"
|
|
|
+# 如果 drugs 有数据但搜索无结果,检查 vec 列是否为 NULL:
|
|
|
+# SELECT drug_id, vec IS NULL FROM drug_chunks LIMIT 5;
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、数据导入决策表
|
|
|
+
|
|
|
+| 场景 | 导入内容 | 命令 | 耗时 |
|
|
|
+|------|----------|------|------|
|
|
|
+| 快速验证 | Wiki (21 条) | `python import_all.py` | 2 分钟 |
|
|
|
+| 完整部署 | Wiki + 6317 DOCX | `python import_all.py && python docx_ingest.py` | 2-4 小时 |
|
|
|
+| 增量更新 | 仅新增 DOCX | `python docx_ingest.py` | 首次长/后续短 |
|
|
|
+| 清空重建 | 全部重来 | `TRUNCATE drug_chunks, drugs CASCADE;` 然后重新导入 | 2-4 小时 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、关键路径汇总
|
|
|
+
|
|
|
+```
|
|
|
+部署路径: /opt/pharmacopoeia-ai/
|
|
|
+DOCX 源: /opt/2025/output*/.../*.docx (6317 个)
|
|
|
+PG 容器: pharmacopoeia-pg (5432)
|
|
|
+Redis 容器: pharmacopoeia-redis (6379)
|
|
|
+Java 后端: http://localhost:9000
|
|
|
+API 前缀: /api/v1
|
|
|
+Supervisor: /etc/supervisor/conf.d/pharmacopoeia.conf
|
|
|
+日志: /var/log/pharmacopoeia/
|
|
|
+```
|