diff --git a/PROGRESS.md b/PROGRESS.md index d0a6a43..bc25550 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-06-01(update.sh 加自更新重跑守卫修"改源仍报旧错";默认源改腾讯/避开阿里滞后卡 litellm;build 跳过改 --skip-build;进度可见) +最后更新:2026-06-01(update.sh 加自更新重跑守卫修"改源仍报旧错";默认源改腾讯/避开阿里滞后卡 litellm;build 跳过改 --skip-build;pip 不静默,build 默认 TTY UI) --- @@ -24,7 +24,7 @@ ### 2026-06-01 - **`deploy/update.sh` 加自更新重跑守卫(修"改了源仍报旧错"根因)**:脚本 `git pull` 会改自己 —— 变量默认值在 pull 前已求值、bash 又按字节偏移边读边跑,所以**首次拉到"改 update.sh"的提交那一轮,跑的还是旧脚本的过期行为**(默认源还是阿里 → litellm 仍报缺版本)。改法:pull 后 `git diff --quiet OLD NEW -- deploy/update.sh` 检出本脚本有变更,就 `exec env ZCBOT_UPDATE_REEXEC=1 bash $0 "${ORIG_ARGS[@]}"` 用新版本从头重跑(原始参数原样回传,标记防死循环;pull 幂等,重跑里 pull 变 no-op)。**纯运维脚本,DESIGN 不动**;`RUN.md` §部署 SOP 加一条要点。 -- **`deploy/update.sh` 默认源改腾讯 + build 跳过改 `--skip-build` + 进度可见**:部署 build 报 `Could not find a version that satisfies the requirement litellm>=1.83.0`。**根因 = 阿里 PyPI 镜像同步滞后(只到 litellm 1.82.6),而 `requirements.txt` 钉 `>=1.83.0`(zai/GLM provider 要)**;腾讯 / 清华源已到 1.88。三处改:① 默认镜像源(APT/PIP/NPM)由阿里改腾讯(`mirrors.cloud.tencent.com`),并修 step 2 host venv pip —— 经 `sudo -u` 后 `PIP_INDEX_URL` env 被洗掉,改为脚本显式拼 `--index-url`,不再靠 host pip.conf(否则 host 仍撞阿里缺版本);② 跳过 sandbox build 从 env `ZCBOT_SKIP_SANDBOX_BUILD=1` 改为 CLI flag `--skip-build`(开发期不留 env 别名兼容),顶部 `while/case` 解析参数;③ 进度可见 —— step 2 pip 去掉 `-q`、step 4 `docker build --progress=plain`(默认 BuildKit TTY UI 多层并行折叠刷新,看着像非串行且管道下缓冲),部署时能逐行看实时输出。**纯运维脚本,DESIGN 不动**;`RUN.md` §部署 SOP 三条要点改写 + 故障表加 litellm 版本找不到一行 + 最后更新日期刷新。 +- **`deploy/update.sh` 默认源改腾讯 + build 跳过改 `--skip-build` + 进度可见**:部署 build 报 `Could not find a version that satisfies the requirement litellm>=1.83.0`。**根因 = 阿里 PyPI 镜像同步滞后(只到 litellm 1.82.6),而 `requirements.txt` 钉 `>=1.83.0`(zai/GLM provider 要)**;腾讯 / 清华源已到 1.88。三处改:① 默认镜像源(APT/PIP/NPM)由阿里改腾讯(`mirrors.cloud.tencent.com`),并修 step 2 host venv pip —— 经 `sudo -u` 后 `PIP_INDEX_URL` env 被洗掉,改为脚本显式拼 `--index-url`,不再靠 host pip.conf(否则 host 仍撞阿里缺版本);② 跳过 sandbox build 从 env `ZCBOT_SKIP_SANDBOX_BUILD=1` 改为 CLI flag `--skip-build`(开发期不留 env 别名兼容),顶部 `while/case` 解析参数;③ 进度可见 —— step 2 pip 去掉 `-q` 让装包进度可见(step 4 docker build 保留默认 TTY 进度 UI,分层折叠刷新更直观)。**纯运维脚本,DESIGN 不动**;`RUN.md` §部署 SOP 三条要点改写 + 故障表加 litellm 版本找不到一行 + 最后更新日期刷新。 - **修 MP host 工具的全量下载(IP 被封根因)**:`mp_search_summary` 之前不给 `summary.search` 传分页参数 → mp-api 默认 `chunk_size=1000` 且 `list(docs)` 自动翻完所有页,`limit` 只在客户端切片,等于每次搜索都整库级下载 → MP 判 abusive traffic 封 host IP/ASN(403 "blocked")。改为 `search(num_chunks=1, chunk_size=limit, ...)`,服务端单页限量。`mp_get_entries` 的 `limit` 同样是"只裁剪保存、不减网络流量"的假参数,但 `get_entries_in_chemsys` 天然全量(相图用途),改不了,只在 description 里点明"拉整个 chemsys、元素越多越重、别反复调"。测试加断言锁定 `num_chunks/chunk_size` 已传。**注:宿主 IP `49.232.14.174` 当前仍被 MP 临时封(无公开时限、不确认自动解除),需发邮件 support@materialsproject.org 人工解封后才能联网复测。** - **加一键部署脚本 `deploy/update.sh`(Ubuntu / systemd)**:把日常部署固化成一把梭 —— `git pull --ff-only` → `pip install -r` → `db upgrade head` → `docker build` sandbox 镜像 → `systemctl restart zcbot` → `curl /healthz` 验活。**两处必须钉死的顺序 / 步骤**:① migration 不能漏(`db/migrations/env.py` 直读 `os.environ['ZCBOT_DB_URL']` 不读 .env,脚本从 .env 抠出来 `env ZCBOT_DB_URL=...` 喂进去);② **build 必须在 restart 之前** —— sandbox 容器 per-user 长驻复用、`tools/` 是 build 进镜像(非 mount),restart 时 `pool.shutdown_all` 清旧容器、下次 `ensure()` 才用新 `zcbot-sandbox:latest` 重建,顺序反了新 tools/ 要等下次重启才生效。**sandbox 每次都 build 无所谓**:重活(pip ~1G / chromium / 字体 / mermaid)都在 Dockerfile `COPY tools/` 之上,layer cache 让改代码部署秒过、只有 `requirements.txt` 变了才整体重建(~5-10min)。镜像源默认阿里(`${VAR-default}` 不带冒号,显式置空可回落官方源)。前置守卫:非 root / 非 git 仓库 / 工作区脏(已跟踪文件)/ 缺 .env 中止;healthz 15s 不 ok → dump journalctl 非零退出。`ZCBOT_SKIP_SANDBOX_BUILD=1` 跳过 build(host backend 机)。一次性 bootstrap(useradd / 写 unit / enable)不进脚本,留 RUN.md。git 可执行位已置(100755)。**纯运维脚本,DESIGN 不动**;`RUN.md` §部署 SOP 重写为指向脚本 + 手动逐条 fallback。 - **sandbox 镜像加中文字体,修 matplotlib / mermaid 出图中文方块**:用户报绘图(mermaid + matplotlib)出的 PNG 里中文全是豆腐块 □。**根因 = `deploy/sandbox/Dockerfile` 从 `python:3.12-slim` 起一个 CJK 字体都没装**:matplotlib `skills/plot_pub/style.py::_find_chinese_font()` 扫候选无果退回 Arial/DejaVu;mermaid 经 mmdc→chromium 渲染,chromium 经 fontconfig 也找不到中文字形;`skills/ppt/scripts/render_icon.py` 引用的 `wqy-microhei.ttc` / `NotoSansCJK-Regular.ttc` 路径根本不存在。三处同一病根。**改法**:① Dockerfile chromium 块后加一层 `apt-get install fonts-noto-cjk fonts-wqy-microhei fontconfig && fc-cache -f`(Noto 出版级 +~330MB,wqy 兜底 +~5MB 且匹配 style.py 现有候选 / render_icon 引用路径);② `style.py` 候选清单首位加 `"Noto Sans CJK SC"` 让 matplotlib 优先用 Noto。fontconfig 刷缓存供 chromium 选字;matplotlib 走自家 font_manager 扫 `/usr/share/fonts` 运行时首用自动建缓存,无需额外处理。**否决**仅装 wqy(体积小但黑体不如 Noto 精致,出版图略糙)/ 仅装 Noto(render_icon 第一候选 wqy.ttc 落空走 fallback OK 但不够干净)。**纯镜像 + 配置改,DESIGN 不动**(无架构 / 取舍 / schema 变化);`RUN.md` 故障表加一行(中文方块 → 重 build 镜像 + 清旧容器 + `fc-list :lang=zh` 验证)。**生效**:改了 Dockerfile 必须 `docker build` 重建 + `docker rm -f` 清旧容器 + restart web,旧容器仍跑老镜像不会自动更新。 diff --git a/RUN.md b/RUN.md index 2b1bfae..2cf294f 100644 --- a/RUN.md +++ b/RUN.md @@ -2,7 +2,7 @@ > 怎么把 zcbot 跑起来。env / 常用命令 / 故障兜底。设计看 `DESIGN.md`,进度看 `PROGRESS.md`。 -最后更新:2026-06-01(update.sh 加自更新重跑守卫;默认源改腾讯/阿里滞后卡 litellm;build 跳过改 --skip-build;pip 不静默 + build --progress=plain) +最后更新:2026-06-01(update.sh 加自更新重跑守卫;默认源改腾讯/阿里滞后卡 litellm;build 跳过改 --skip-build;pip 不静默,build 走默认 TTY UI) --- @@ -264,7 +264,7 @@ sudo bash /opt/zcbot/deploy/update.sh - **build 必须在 restart 之前**:sandbox 容器 per-user 长驻 + 复用,`tools/` 是 build 进镜像的(非 mount)。restart 时 `shutdown_all` 清旧容器,下次 `ensure()` 才用新 `zcbot-sandbox:latest` 重建 —— 顺序反了新 tools/ 要等下次重启才生效。 - **sandbox build 每次都跑没关系**:layer cache 让重活(pip ~1G / chromium / 字体 / mermaid,都在 `COPY tools/` 之上)在改代码部署时秒过;只有 `requirements.txt` 变了才整体重建(~5-10min,正好也是该重建的时候)。host backend 机器 / 临时不想动 docker:`sudo bash deploy/update.sh --skip-build`。 - **镜像源默认腾讯**(`APT_MIRROR=mirrors.cloud.tencent.com` / `PIP_INDEX_URL=mirrors.cloud.tencent.com/pypi/simple/` / `NPM_REGISTRY=mirrors.cloud.tencent.com/npm/`,境内快且新包同步及时)。**阿里 PyPI 镜像同步滞后**(litellm 一度只到 1.82.6,卡死 `requirements.txt` 的 `>=1.83.0`),故默认避开阿里。要命中 docker cache 就别两组源来回换(换源从 pip 层炸开全重跑)。想用官方源:`PIP_INDEX_URL= sudo -E bash deploy/update.sh`(置空即回落 Dockerfile 官方默认)。host venv 的 step 2 pip 也吃这个源(脚本显式 `--index-url`,不靠 host pip.conf)。 -- **进度可见**:step 2 pip 不带 `-q`、step 4 `docker build --progress=plain`,部署时能逐行看到装包 / 各 build 层的实时输出(默认 BuildKit TTY UI 会折叠刷新、看着像非串行)。 +- **进度可见**:step 2 pip 不带 `-q`,部署时能看到装包进度;step 4 docker build 走默认 TTY 进度 UI(分层折叠刷新,直观)。 - **脚本会自更新重跑**:`git pull` 若动了 `deploy/update.sh` 本身,脚本会 `exec` 新版本从头重跑(旧脚本的变量默认值在 pull 前就求值了、bash 又按字节偏移边读边跑,不重跑会跑出过期行为 —— 这是首次拉到改 update.sh 的提交时"改了源还报旧错"的根因)。日志出现「update.sh 自身有更新 —— 用新版本重跑」即正常;`ZCBOT_UPDATE_REEXEC=1` 防死循环。 - **migration 取 DB URL**:`db/migrations/env.py` 直接读 `os.environ['ZCBOT_DB_URL']`(不读 .env),脚本从 `.env` 抠出来显式 `env ZCBOT_DB_URL=... ` 喂进 `main.py db upgrade`。 - **前置守卫**:非 root / 不是 git 仓库 / 工作区脏(已跟踪文件有未提交改动)/ 缺 .env → 直接中止。`/healthz` 15s 内不返回 `ok` → dump `journalctl -n 50` 并以非零退出。 diff --git a/deploy/update.sh b/deploy/update.sh index 6c289d5..d74af40 100755 --- a/deploy/update.sh +++ b/deploy/update.sh @@ -137,11 +137,9 @@ else [ -n "${PIP_TRUSTED_HOST:-}" ] && build_args+=(--build-arg "PIP_TRUSTED_HOST=${PIP_TRUSTED_HOST}") [ -n "${NPM_REGISTRY:-}" ] && build_args+=(--build-arg "NPM_REGISTRY=${NPM_REGISTRY}") - # --progress=plain:逐行流式输出(默认 TTY 进度 UI 多层并行折叠刷新,看着像非串行 - # 且非交互管道下会缓冲);部署时要能持续看到每层在干啥,故强制 plain。 + # 进度走 docker 默认(TTY 下是分层折叠刷新的 UI,直观);不强制 plain。 log "docker build $IMAGE(改代码秒过 / requirements 变了 ~5-10min)..." asuser docker build \ - --progress=plain \ -f "$APP_DIR/deploy/sandbox/Dockerfile" \ "${build_args[@]}" \ -t "$IMAGE" \