From 6bcb88cf7660301f2be00be467efb83b2a88f9bd Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 12 Sep 2026 20:05:57 +0800 Subject: [PATCH] =?UTF-8?q?docs(deploy):=20=E9=83=A8=E7=BD=B2=E6=96=B9?= =?UTF-8?q?=E6=B3=95=20Skill=20=E5=8C=96=E2=80=94=E2=80=94=E5=90=AB?= =?UTF-8?q?=E6=8D=A2=E6=9C=BA/=E6=97=A0=E7=94=9F=E4=BF=A1/=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=BA=93=E8=B7=AF=E5=BE=84=E5=8F=98=E4=BD=93?= =?UTF-8?q?=E4=B8=8E=E6=8F=90=E7=A4=BA=E8=AF=8D=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与本地 Claude Code skill(plantai-deploy)同源,面向 agent 自动执行; 新增 §7 部署变体(7.1 换机=密钥+路径+基础设施一次准备;7.2 无生信= 不部署 bioflow 树+env 关 BIOFLOW_ENABLED,start_all 自动跳过;7.3 自定义 库路径=QA_DB_ROOT/VSTORE_ROOT env 纯配置)与 §9 提示词示例(全量/新机 裁剪/纯前端/换库四种)。 Co-Authored-By: Claude Fable 5 --- docs/DEPLOY_SKILL.md | 189 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 docs/DEPLOY_SKILL.md diff --git a/docs/DEPLOY_SKILL.md b/docs/DEPLOY_SKILL.md new file mode 100644 index 0000000..9817abe --- /dev/null +++ b/docs/DEPLOY_SKILL.md @@ -0,0 +1,189 @@ +# PlantAI-rag-new 打包部署 Skill(175 构建机 → 176 生产) + +> 本文件是 Claude Code skill 形态的部署方法(与 DEPLOY_FLOW.md 流程互补,侧重 agent 自动执行)。 +> 生成于 2026-09-12,融合当日全部实战陷阱;2026-09-12 晚增补部署变体(换机/无生信/自定义库路径)与提示词示例。 +> skill 源文件:本地 ~/.claude/skills/plantai-deploy/SKILL.md。 + +## 0. 前置事实(agent 必读,勿想当然) + +- **175 = 构建机/开发仓库**(8.163.92.8,公网 `ssh -p 26518 xzq@8.163.92.8`):仓库 `/home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new`,分支 `feature/bioflow-conversation-orchestration`,Gitea 在 `http://127.0.0.1:3000`。 +- **176 = 生产**(8.138.231.183,公网 `ssh -p 26518 xzq@8.138.231.183`):部署根 `/srv/plantai/`(install/ + qa-db/ + data/ + docgen/ + bioflow/ + mineru-*)。 +- **端口终态**:nginx 80(唯一客户入口)→ BFF 8090;QA 8091/methodology 8092/legacy 8093/vstore 8094/bioflow 8098 全回环;裸进程库 Neo4j 19888/Qdrant 27433;Ollama 11434。 +- **两机传输用 P2P 内网直连**(175 上密钥 `~/.ssh/id_ed25519_p2p`,勿走跳板机): + `rsync -a --numeric-ids -e 'ssh -i ~/.ssh/id_ed25519_p2p -p 26518 -o BatchMode=yes' / xzq@192.168.0.176:/` +- **BFF 静态托管 ui/dist**:前端改动部署 = 只同步 dist 资产 + 清旧哈希文件,不需整包重编。 + +## 1. 构建(175,全量约 30-40 分钟) + +```bash +cd /home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new +git status --short # 先确认无未提交改动 +bash tooling/build_all.sh # 串行:五树 Cython 编译→双审计→冒烟 import→组装→SHA256SUMS→泄露门禁 +``` + +- 版本与 env 在 `tooling/tooling.env`(VERSION=2.0.0,SKIP_KB=1 数据库未定版)。 +- **产物断言**:`tooling/build/2.0.0/install/` 应含 sdk/qa/methodology/legacy-rag/vstore/ui/start_all.sh/vstore_restart.sh/ollama_restart.sh/SHA256SUMS。 +- **SHA256SUMS 校验的已知良性失败**:`./SHA256SUMS: 失败` 是清单自引用条目,永远不匹配;其余 1367 项应全 OK。 +- **start_all.sh 由 build_all 模板生成**(heredoc),改动模板=`tooling/build_all.sh`,不是产物文件。 +- **UI dist 内置**:build_all 内部会跑 `npm run build`;前端单测(r3debug 89 + 主套件 373)在构建前跑一遍: + `cd ui && npx vitest run --config tests/r3debug/vitest.config.js && npx vitest run` + +## 2. 部署前准备 + +```bash +# 2.1 176 备份(必做;恢复依据) +ssh -p 26518 xzq@8.138.231.183 "cp -a /srv/plantai/install /srv/plantai/install.bak-$(date +%s)" +# 2.2 从 175 发起 P2P 连通性预检 +ssh -i ~/.ssh/id_ed25519_p2p -p 26518 -o BatchMode=yes -o ConnectTimeout=8 xzq@192.168.0.176 'hostname' +``` + +## 3. 传输(rsync --delete,必须 exclude 四个本地产物) + +```bash +cd /home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new/tooling/build/2.0.0 +rsync -a --numeric-ids --delete \ + --exclude 'venv' \ + --exclude 'sdk/data' \ + --exclude '.env' \ + -e 'ssh -i ~/.ssh/id_ed25519_p2p -p 26518 -o BatchMode=yes' \ + install/ xzq@192.168.0.176:/srv/plantai/install/ +``` + +**exclude 原理**(2026-09-12 实测,漏掉会删生产数据):源构建树不含 176 的 `install/venv`(1.8G Python 环境)、`install/sdk/data`(plantai.db/docgen 数据)、`install/.env`、`install/sdk/.env`;`--delete` 会把这些删掉。 + +**传输后必做——恢复三份 prod.env**:rsync 会删 176 的 `{qa,methodology,legacy-rag}/env/prod.env`(源构建树只有 .example)。从刚做的备份恢复: + +```bash +ssh -p 26518 xzq@8.138.231.183 ' +for t in qa methodology legacy-rag; do + cp /srv/plantai/install.bak-*/$t/env/prod.env /srv/plantai/install/$t/env/prod.env +done +# 幸存校验:venv/sdk/data/.env 应仍在 +ls -d /srv/plantai/install/venv /srv/plantai/install/sdk/data /srv/plantai/install/sdk/.env +' +``` + +## 4. 重启(注意 BFF 不随 start_all 换进程) + +```bash +# 4.1 手动杀旧 BFF(lsof 只取 LISTEN;start_all 不替换在跑进程——E-6 陷阱) +ssh -p 26518 xzq@8.138.231.183 'kill $(lsof -ti tcp:8090 -sTCP:LISTEN) 2>/dev/null; sleep 2' +# 4.2 杀 QA/methodology/legacy(让它们吃到新代码) +ssh -p 26518 xzq@8.138.231.183 ' +for p in 8091 8092 8093; do kill $(lsof -ti tcp:$p -sTCP:LISTEN) 2>/dev/null; done; sleep 2' +# 4.3 新版 start_all.sh 一键拉起(五服务 + 生信编排,自带 disown 不卡) +ssh -p 26518 xzq@8.138.231.183 'cd /srv/plantai/install && timeout 180 bash start_all.sh' +``` + +**lsof 陷阱**:`lsof -ti tcp:PORT` 会返回该端口**所有 socket** 的进程(含已建立连接);**必须加 `-sTCP:LISTEN` 只取监听者**,且 kill 不加引号。vstore/bioflow 的 restart.sh 已内置此过滤,直接调即可: + +```bash +bash /srv/plantai/install/vstore_restart.sh # vstore 幂等重启(自带 lsof LISTEN + disown) +bash /srv/plantai/bioflow/bioflow_service/restart.sh # 生信(独立树,不在 install 内) +``` + +**start_all 编排行为**(2026-09-12 起):ollama → QA/methodology/legacy(已跑则跳过)→ vstore → **探测 install 同级 bioflow/ 树,存在则启动/重启生信 8098**(不存在静默跳过)→ BFF。BFF 段有 `disown -a`,脚本正常退出不会卡。 + +## 5. 部署后质检(逐条核对) + +```bash +# 5.1 六服务端口全景(8090/8091/8092/8093/8094/8098 应全 LISTEN 且是新进程 lstart) +ssh -p 26518 xzq@8.138.231.183 'for p in 8090 8091 8092 8093 8094 8098; do + ss -tlnp | grep ":$p " | grep -o "pid=[0-9]*" | head -1; done' +# 5.2 BFF health 五上游全 ok +curl -s http://127.0.0.1:8090/api/health +# 5.3 生信 TAB 依赖的端点(掉进程时 TAB 静默消失;无生信部署此项应为 UPSTREAM_DOWN 且属预期) +curl -s http://127.0.0.1:8090/api/bioflow/health +# 5.4 nginx 80 全链(唯一客户入口) +curl -s http://127.0.0.1:80/api/health +# 5.5 前端新资产已服务 + 旧哈希已清 +curl -s http://127.0.0.1:80/ | grep -o 'index-[A-Za-z0-9_-]*\.\(js\|css\)' +# 5.6 SHA256SUMS(排除 SHA256SUMS 自引用条目,其余应全 OK) +cd /srv/plantai/install && sha256sum -c SHA256SUMS 2>&1 | grep -cv 'OK$' +``` + +## 6. 纯前端改动快速部署(不重编) + +```bash +# 175 构建后: +rsync -a --numeric-ids -e 'ssh -i ~/.ssh/id_ed25519_p2p -p 26518 -o BatchMode=yes' \ + ui/dist/ xzq@192.168.0.176:/srv/plantai/install/ui/dist/ +# 176 清旧哈希资产(先看 index.html 引用哪个,删其余): +ssh -p 26518 xzq@8.138.231.183 'cd /srv/plantai/install/ui/dist && grep -o "index-[A-Za-z0-9_-]*\.\(js\|css\)" index.html' +# BFF 是静态托管,无需重启;浏览器强刷即生效 +``` + +## 7. 部署变体(换机/裁剪/自定义库路径) + +本 skill 主体以「175 → 176 全量」为模板;以下变体全部实测可行,机制均内建: + +### 7.1 部署到其他机器 + +业务层流程(§1-6)原样复用,只需替换三处: +- **P2P 密钥**:把 175 的 `~/.ssh/id_ed25519_p2p.pub` 装进新机器 authorized_keys(或改用新机器自己的 SSH 端口/凭据),rsync 命令的目标地址同步替换。 +- **部署根路径**:rsync 目标与后续命令里的 `/srv/plantai` 换成新机器路径。 +- **基础设施一次准备**(新机器首次,业务层外):按 `docs/DEPLOY_FLOW.md` §5.1-5c 做 py3.12 venv+依赖清单、各树 env(路径类键改目标机布局)、nginx 80 反代、MinerU(可选)、Ollama(可选);数据库用 `deploy/qa-db/` 的 systemd 脚本裸装(数据目录见 §7.3)。 +- 数据库数据从现网同步:整目录 rsync(82G 约 8 分钟),或 `replace_db.sh` 整库替换(自动探活+回滚)。 + +### 7.2 不含生信部分(零配置,自动行为) + +start_all 的生信编排(9d7ed1b)探测 `install 同级 bioflow/bioflow_service/restart.sh`,**树不存在即静默跳过**。彻底不含生信的做法: +1. **不部署 bioflow 树**(不传 `/srv/plantai/bioflow/`),也不搬运 8 个镜像(40G); +2. `sdk/.env` 不加 `BIOFLOW_ENABLED`(或设为 false)——前端生信 TAB 按 `/api/bioflow/health` 轮询显隐,自然不显示。 +> 注意:start_all 只看「树是否存在」,不看 env——若树在而 env 关,8098 仍会拉起。要彻底不含,树和 env 都去掉。 +> 质检时 §5.3 的 bioflow health 返回 UPSTREAM_DOWN 属预期,跳过该项。 + +### 7.3 三个向量库用自定义路径(纯配置,零代码改动) + +| 库 | 数据路径决定 | 连接键(QA 服务 env) | +|---|---|---| +| Neo4j | `QA_DB_ROOT` env → `$QA_DB_ROOT/neo4j/data`(install_neo4j.sh 的 server.directories.data) | `NEO4J_URI` | +| Qdrant | 同脚本 `storage_path: $STORAGE`(源于 QA_DB_ROOT) | `QDRANT_URL` / `V15_QDRANT_COLLECTION` / `NORMALIZED_RELEASE_ID` | +| vstore | `VSTORE_ROOT` env(vstore_restart.sh source 自己的 .env) | `VSTORE_BASE_URL`(BFF 侧) | + +- 「向量库放 xxxx 路径」= 数据库 systemd 安装阶段设 `QA_DB_ROOT=xxxx` + qa env 连接 URI 指向对应端口——无代码改动。 +- 换库(如水产库)是同一机制:换路径 + 换 `NORMALIZED_RELEASE_ID`/`V15_QDRANT_COLLECTION` 两个键,整库替换走 `replace_db.sh`(自动探活+回滚)。 +- **db 层不在 start_all 编排**:systemd 的 neo4j/qdrant 在安装期定路径,之后 start_all 不动它们。 + +## 8. 陷阱速查(全部实测) + +1. **rsync --delete 删本地产物**:必须 exclude venv/sdk/data/.env;prod.env 传输后从备份恢复。 +2. **start_all 不杀在跑的 BFF**:新 uvicorn 端口被占静默退出,自检看到的是旧进程——先 `kill $(lsof -ti tcp:8090 -sTCP:LISTEN)`。 +3. **lsof 不带 LISTEN 过滤**:kill 多行 PID(含已建立连接进程)失败,旧进程存活、新进程绑定失败静默退出。 +4. **start_all 缺 disown**:bash 尾部隐式 wait BFF 永不返回(已修,勿回退)。 +5. **生信 TAB 消失 = 8098 掉进程**:bioflow_service 独立树,start_all 现会自拉;排查先 curl `/api/bioflow/health`。 +6. **figures 双键 + registry**(r4):`PLANTAI_FIGURES_MINERU_ROOT/REGISTRY` 缺一即静默降级纯 PMC;registry 文件需单独传输。 +7. **cython .so 验证必须 runtime import**:`strings` 探不到 env 键,会误判旧代码。 +8. **vstore 数据完整性**:health 计数异常先查进程 environ(VSTORE_* 键),再怀疑数据。 +9. **MinerU 缺 accelerate**:启动期 `ValueError: requires accelerate`,目标机需 `pip install accelerate`。 +10. **QA LLM 截断重试**:`LLM output was truncated by the token limit` 会重试 4 次(每 ~9.5s),最终仍出答案,非部署故障。 + +## 9. 提示词示例(直接复制给 agent) + +**全量部署到 176(默认形态)**: +``` +按 plantai-deploy skill 部署:175 仓库最新代码打包部署到 176,含生信,部署后跑完整质检并汇报。 +``` + +**部署到新机器 + 不含生信 + 自定义库路径**: +``` +按 plantai-deploy skill 部署到一台新机器(192.168.0.177,ssh 端口 26518,部署根 /srv/plantai)。 +要求:不含生信部分(不部署 bioflow 树、不搬运镜像、sdk/.env 不开 BIOFLOW_ENABLED); +Neo4j 与 Qdrant 的数据目录放在 /data/qa-db(即 QA_DB_ROOT=/data/qa-db); +基础设施按 DEPLOY_FLOW §5.1 从零准备,数据库数据从 176 的 /srv/plantai/qa-db 同步; +完成后跑质检(生信项按无生信预期)并汇报。 +``` + +**纯前端快速部署**: +``` +按 plantai-deploy skill 把 175 最新前端 dist 部署到 176(纯前端,不重编),并验证 nginx 80 已服务新资产。 +``` + +**换库部署(以水产库为例)**: +``` +按 plantai-deploy skill 换库部署:用水产库(kb-libraries/aqua)替换 176 当前植物库。 +换库是纯配置:NORMALIZED_RELEASE_ID 与 V15_QDRANT_COLLECTION 换成 aqua 值, +Neo4j/Qdrant 数据目录指向 aqua 库位置,replace_db.sh 整库替换; +植物库保留原位可回滚;部署后跑金标问答质检并汇报。 +``` +