适用环境: 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 分钟)
# 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
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
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
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, ...}
数据来源: data-pipeline/data/wiki_merged.json(13 个药品的维基百科临床专著,含概述/适应症/药理/不良反应等)+ sample_drugs.json(4 个药典示例)+ drug_guides.json(4 个用药指导)
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 向量化)
验证:
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
数据来源: /opt/2025/ 下 6317 个 DOCX 文件(2025 年版中国药典全文)
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,重复运行不会产生重复数据。如果中途中断,重新运行即可从断点继续(已入库的会被跳过)。
监控进度:
# 另一个终端,每隔 30 秒查看入库量
watch -n 30 "docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c 'SELECT COUNT(*) AS total_chunks FROM drug_chunks;'"
# 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
# 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
docker logs pharmacopoeia-pg --tail 20
docker exec pharmacopoeia-pg pg_isready -U postgres
# 检查 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"}}'
# 查看错误日志
tail -100 /var/log/pharmacopoeia/backend-error.log
# 常见原因: PG 未启动、端口被占用、API Key 无效
# docx_ingest.py 使用 ON CONFLICT DO NOTHING,直接重新运行即可
cd /opt/pharmacopoeia-ai/data-pipeline
python docx_ingest.py
# 确认数据已入库
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/