# 中华药典 AI Agent — 全新服务器部署手册 > 适用:Ubuntu 24.04 LTS 全新安装 > 版本:v2.0 > 最后更新:2026-07-14 --- ## 一、服务器配置要求 | 项目 | 最低 | 推荐 | |------|------|------| | CPU | 4 核 | 8 核 | | 内存 | 8 GB | 16 GB | | 系统盘 | 50 GB SSD | 100 GB SSD | | 操作系统 | Ubuntu 22.04+ | Ubuntu 24.04 LTS | | 网络 | 公网 IP | 公网 IP + 域名 | 不需要 GPU(LLM 走阿里云 Qwen API)。 --- ## 二、部署总览(10 步) ``` ① 基础环境 → apt update, 装 git/curl 等 ② Docker → 容器运行时 ③ 拉取代码 → git clone 到 /opt/pharmacopoeia-ai ④ 环境变量 → .env 配置 ⑤ PostgreSQL → Docker 启动 pgvector ⑥ 数据库建表 → 导入 schema.sql ⑦ Python 后端 → venv + FastAPI + Supervisor 守护 ⑧ Nginx → 反向代理 + SSE 免缓冲 ⑨ 防火墙 → ufw 只开放 80/443 ⑩ 备份 + 日志 → cron 每日备份 ``` --- ## 三、详细步骤 ### ① 基础环境 ```bash # 更新系统 sudo apt update && sudo apt upgrade -y # 安装基础工具 sudo apt install -y curl wget git vim htop ca-certificates gnupg lsb-release # 设置时区 sudo timedatectl set-timezone Asia/Shanghai ``` --- ### ② 安装 Docker ```bash # 官方安装脚本 curl -fsSL https://get.docker.com | sudo bash # 把当前用户加入 docker 组(不用每次 sudo) sudo usermod -aG docker $USER newgrp docker # 验证 docker --version docker compose version ``` > Docker 镜像拉取慢的话,配置国内镜像加速: > ```bash > sudo tee /etc/docker/daemon.json << 'EOF' > { > "registry-mirrors": ["https://docker.m.daocloud.io"] > } > EOF > sudo systemctl restart docker > ``` --- ### ③ 拉取项目代码 ```bash # 创建应用目录 sudo mkdir -p /opt/pharmacopoeia-ai sudo chown $USER:$USER /opt/pharmacopoeia-ai # 拉取代码(替换为你的仓库地址) cd /opt/pharmacopoeia-ai git clone https://github.com/your-org/pharmacopoeia-ai.git . # 确认目录结构 ls -la # 应看到: backend-python/ deploy/ database/ docs/ .env.example README.md ``` --- ### ④ 配置环境变量 ```bash cd /opt/pharmacopoeia-ai # 从模板创建 cp .env.example .env # 生成随机密钥 echo "SECRET_KEY=$(openssl rand -hex 32)" echo "DB_PASSWORD=$(openssl rand -base64 16)" ``` 编辑 `.env`,修改以下值: ```bash vim .env ``` ```ini # ===== 必改 ===== APP_ENV=production APP_DEBUG=false SECRET_KEY=<上面生成的随机密钥> POSTGRES_PASSWORD=<上面生成的数据库密码> QWEN_API_KEY=sk-xxxxxxxxxxxxxxxx # 阿里云百炼 API Key # ===== 有微信小程序才填 ===== WECHAT_APPID=wx1234567890 WECHAT_SECRET=xxxxxxxx # ===== 生产建议 ===== QWEN_MAX_TOKENS=2048 LOG_LEVEL=WARNING ``` > **Qwen API Key 获取**:注册 [阿里云百炼](https://bailian.console.aliyun.com/) → 模型广场 → 选择 qwen-max → API-KEY 管理 → 创建 API Key。 > > 新用户有免费额度,足够开发测试。 --- ### ⑤ 启动 PostgreSQL + Redis ```bash cd /opt/pharmacopoeia-ai/deploy # 先确认 .env 中的密码已写入 docker-compose 能读取 # docker-compose.yml 会读取 POSTGRES_PASSWORD 环境变量 source /opt/pharmacopoeia-ai/.env # 启动容器 docker compose up -d # 等待健康检查通过 sleep 10 docker ps # 应该看到 pharmacopoeia-pg (healthy) 和 pharmacopoeia-redis (healthy) # 验证 PG docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c "SELECT 1" # 返回 1 行 = 正常 # 验证 Redis docker exec pharmacopoeia-redis redis-cli ping # 返回 PONG = 正常 # 设置开机自启 docker update --restart=always pharmacopoeia-pg pharmacopoeia-redis ``` --- ### ⑥ 初始化数据库表 ```bash # 导入表结构 docker exec -i pharmacopoeia-pg psql -U postgres -d pharmacopoeia \ < /opt/pharmacopoeia-ai/database/schema.sql # 确认表已创建(应看到 9 张表) docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c "\dt" ``` 9 张表说明: | 表 | 用途 | |---|------| | `drugs` | 药品主表 | | `drug_chunks` | 药品切片 + 1024维向量(RAG 核心) | | `knowledge_points` | 执业药师知识点 | | `questions` | 题库 | | `conversations` | 对话会话 | | `messages` | 对话消息 | | `users` | 用户 | | `user_progress` | 学习进度 | | `answer_records` | 答题记录 | --- ### ⑦ 编译并启动 Java 后端 #### 7.1 编译 ```bash cd /opt/pharmacopoeia-ai/backend-java # 编译(跳过测试) mvn clean package -DskipTests ``` #### 7.2 手动启动测试 ```bash # 设置数据库密码环境变量 export POSTGRES_PASSWORD=postgres # 启动 java -jar target/pharmacopoeia-ai-1.0.0.jar # 看到 Started PharmacopoeiaApplication 后 # 新开终端验证: # curl http://localhost:9000/health # 返回 {"status":"ok"} 则正常 # Ctrl+C 停掉 ``` #### 7.3 使用启动脚本管理 ```bash # 赋予执行权限 chmod +x /opt/pharmacopoeia-ai/tools/start-java.sh # 启动 bash /opt/pharmacopoeia-ai/tools/start-java.sh start # 查看状态 bash /opt/pharmacopoeia-ai/tools/start-java.sh status # 查看日志 bash /opt/pharmacopoeia-ai/tools/start-java.sh logs # 重启 bash /opt/pharmacopoeia-ai/tools/start-java.sh restart # 停止 bash /opt/pharmacopoeia-ai/tools/start-java.sh stop ``` #### 7.4 配置 Supervisor 守护进程(推荐) ```bash sudo apt install -y supervisor # 创建日志目录 sudo mkdir -p /var/log/pharmacopoeia # 使用项目自带的 Supervisor 配置 sudo cp /opt/pharmacopoeia-ai/deploy/supervisord-java.conf /etc/supervisor/conf.d/pharmacopoeia.conf # ⚠️ 编辑配置,填入真实的 QWEN_API_KEY sudo vim /etc/supervisor/conf.d/pharmacopoeia.conf # 启动 sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start pharmacopoeia-backend # 查看状态 sudo supervisorctl status ``` --- ### ⑧ 配置 Nginx ```bash # 安装 Nginx sudo apt install -y nginx # 创建站点配置 sudo tee /etc/nginx/sites-available/pharmacopoeia << 'NGINX' # ---- 后端上游 ---- upstream backend { server 127.0.0.1:8000; keepalive 64; } # ---- 限流 ---- limit_req_zone $binary_remote_addr zone=api_limit:10m rate=60r/m; # ---- HTTP(有域名后可加 HTTPS) ---- server { listen 80; server_name _; client_max_body_size 10m; # Gzip gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript; # 安全头 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # API 反向代理(SSE 流式关键:禁用缓冲) location /api/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Connection ""; # SSE 支持 proxy_buffering off; proxy_cache off; proxy_read_timeout 300s; # 限流 limit_req zone=api_limit burst=20 nodelay; } # 健康检查(不记录日志) location /health { proxy_pass http://backend; access_log off; } # API 文档 location /docs { proxy_pass http://backend; } # 静态文件 location /static/ { alias /opt/pharmacopoeia-ai/static/; expires 7d; add_header Cache-Control "public, immutable"; } # 根路径 → 前端页面 location / { alias /opt/pharmacopoeia-ai/static/; try_files $uri /index.html; } } NGINX # 启用站点 sudo ln -sf /etc/nginx/sites-available/pharmacopoeia /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default # 测试配置 sudo nginx -t # 重启 Nginx sudo systemctl reload nginx sudo systemctl enable nginx ``` **验证**:浏览器访问 `http://服务器IP/` 应该看到前端页面。 --- ### ⑨ 配置防火墙 ```bash # 安装 ufw sudo apt install -y ufw # 只开放必要端口 sudo ufw allow 22/tcp # SSH sudo ufw allow 80/tcp # HTTP sudo ufw allow 443/tcp # HTTPS # 开启防火墙 sudo ufw --force enable sudo ufw status verbose ``` > PostgreSQL (5432)、Redis (6379)、FastAPI (8000) **不对外开放**,只通过本地回环访问。 --- ### ⑩ 数据库备份 ```bash # 创建备份脚本 sudo tee /opt/pharmacopoeia-ai/tools/backup.sh << 'EOF' #!/bin/bash BACKUP_DIR="/opt/backups/pharmacopoeia" mkdir -p "$BACKUP_DIR" DATE=$(date +%Y%m%d_%H%M%S) docker exec pharmacopoeia-pg pg_dump -U postgres pharmacopoeia \ > "$BACKUP_DIR/pg_${DATE}.sql" # 保留最近 7 天 find "$BACKUP_DIR" -name "pg_*.sql" -mtime +7 -delete echo "$(date '+%F %T') backup done: pg_${DATE}.sql" >> /var/log/pharmacopoeia/backup.log EOF sudo chmod +x /opt/pharmacopoeia-ai/tools/backup.sh # 添加 cron(每天凌晨 2:00) (crontab -l 2>/dev/null; echo "0 2 * * * /opt/pharmacopoeia-ai/tools/backup.sh") | crontab - ``` --- ## 四、配置域名和 SSL(有域名后执行) ```bash # 安装 certbot sudo apt install -y certbot python3-certbot-nginx # 先修改 Nginx 配置中的 server_name sudo vim /etc/nginx/sites-available/pharmacopoeia # 把 server_name _; 改成 server_name yaodian.example.com; sudo nginx -t && sudo systemctl reload nginx # 自动签发 SSL 证书 sudo certbot --nginx -d yaodian.example.com # 证书会自动续签,可手动测试续签流程: sudo certbot renew --dry-run ``` --- ## 五、导入数据(有药品数据后执行) ```bash cd /opt/pharmacopoeia-ai/data-pipeline # 安装数据管道依赖 python3 -m venv venv source venv/bin/activate pip install -r requirements.txt # 准备数据文件放到 data-pipeline/data/ 下 # 格式参考 docs/SCHEME.md # 执行向量化入库 python ingest.py ``` --- ## 六、最终验证清单 部署完成后逐项确认: ```bash # 1. Docker 容器运行 docker ps | grep pharmacopoeia # ✅ 两个容器都是 healthy # 2. PostgreSQL 可访问 docker exec pharmacopoeia-pg psql -U postgres -d pharmacopoeia -c "SELECT count(*) FROM information_schema.tables WHERE table_schema='public'" # ✅ 返回 9 # 3. Python 后端运行中 sudo supervisorctl status pharmacopoeia-backend # ✅ RUNNING # 4. API 响应正常 curl http://localhost:8000/health # ✅ {"status":"ok","app":"PharmacopoeiaAI","env":"production"} # 5. Nginx 代理正常 curl http://localhost/health # ✅ 同上 # 6. 外网访问(用你电脑浏览器) # http://服务器IP/ # ✅ 能看到前端页面 # 7. 防火墙生效 sudo ufw status | grep -E "80|443" # ✅ ALLOW ``` --- ## 七、日常运维命令 | 操作 | 命令 | |------|------| | 查看后端状态 | `sudo supervisorctl status` | | 重启后端 | `sudo supervisorctl restart pharmacopoeia-backend` | | 查看后端实时日志 | `sudo supervisorctl tail -f pharmacopoeia-backend` | | 查看错误日志 | `tail -100 /var/log/pharmacopoeia/backend-error.log` | | 重启 Nginx | `sudo systemctl reload nginx` | | 重启 PG | `docker restart pharmacopoeia-pg` | | 重启 Redis | `docker restart pharmacopoeia-redis` | | 进入 PG 控制台 | `docker exec -it pharmacopoeia-pg psql -U postgres -d pharmacopoeia` | | 手动备份 | `bash /opt/pharmacopoeia-ai/tools/backup.sh` | | 更新代码并重启 | `cd /opt/pharmacopoeia-ai && git pull && sudo supervisorctl restart pharmacopoeia-backend` | | 查看磁盘 | `df -h` | | 查看内存 | `free -h` | --- ## 八、部署架构图 ``` 公网用户 │ ▼ ┌──────────────────┐ │ UFW 防火墙 │ 开放: 22, 80, 443 └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Nginx :80/:443 │ SSL / 反向代理 / 限流 / 静态文件 └────────┬─────────┘ │ :8000 (本地) ▼ ┌──────────────────┐ │ Supervisor │ 进程守护, 挂了自动重启 │ ┌──────────────┐ │ │ │ Uvicorn x4 │ │ │ │ FastAPI :8000│ │ │ └──────┬───────┘ │ └─────────┼─────────┘ │ ┌──────┼──────┐ ▼ ▼ ▼ ┌──────┐ ┌────┐ ┌──────────┐ │ PG │ │Redis│ │ Qwen API │ │ :5432│ │:6379│ │ (阿里云) │ │Docker│ │Dockr│ │ 云端 │ └──────┘ └────┘ └──────────┘ 快速管理: bash tools/start-java.sh {start|stop|restart|status|logs} ``` --- ## 九、常见问题 ### Q: pip install 报错,sentence-transformers 编译失败? ```bash sudo apt install -y build-essential python3-dev # 重试 pip install sentence-transformers ``` ### Q: docker compose 提示 .env 中的变量未生效? ```bash # 在 docker compose 目录下创建 .env 软链接 cd /opt/pharmacopoeia-ai/deploy ln -sf ../.env .env docker compose up -d ``` ### Q: Qwen API 连不上? ```bash # 测试网络可达性 curl -I https://dashscope.aliyuncs.com # 如果超时,检查服务器能否访问外网,是否需要代理 ``` ### Q: 如何查看 AI 对话是否正常工作? ```bash # 测试非流式接口 curl -X POST http://localhost:8000/api/v1/chat/ask \ -H "Content-Type: application/json" \ -d '{"query": "阿莫西林是什么药"}' ```