# 移植到另一台电脑并独立运行 (v0.1, 2026-09-12) **给谁看**: 要把 `<安装目录>` 整个包搬到另一台机器(或另一个盘/目录)上跑起来的人。 **一句话结论**: **代码与配置是路径无关的(已实测),但 `.venv` 不能直接搬** —— 换机请拷包后**跑一次安装** (`install.bat` / `sh install.sh`, 离线), 之后即可独立运行, 不再需要联网、不需要开发机。 --- ## 一、三种情形, 分别能不能直接跑 | 情形 | 能不能直接跑 | 原因 / 要做什么 | |---|---|---| | **同一台机器, 换个目录** | ✅ 能 (代码全部相对路径) | 直接跑; 只有 `.venv\Scripts\*.exe` 那几个 shim 里存的绝对路径会失效 —— 用 `.venv\Scripts\python.exe` 跑脚本不受影响 (它靠同级的 `pyvenv.cfg` 找基础解释器) | | 换机, 但路径与基础 Python 完全相同 | ⚠ 通常能 | 例如目标机也把 Python 装在 `D:\Program Files\Python` 且包放在同一路径 | | **换机, 路径不同 / 没装 Python** | ❌ 直接跑不行 → **跑一次安装即可** | `.venv/pyvenv.cfg` 里 `home = D:\Program Files\Python` 指的是**基础解释器**; 目标机没有它, `.venv\Scripts\python.exe` 起不来。安装脚本会重建 `.venv`(可用包内便携运行时), 之后独立运行 | > 为什么不能"绿色版"直接搬 venv: Python 虚拟环境按设计就绑基础解释器(还带一批写死绝对路径的 `.exe` shim)。 > 包内因此备了**便携运行时**(`vendor/python/*.tar.gz`: Windows / Linux x86_64 / Linux aarch64)与**离线轮子**, > 目标机上重跑安装是**离线**的, 不需要开发机、不需要联网。 ## 二、移植步骤 ### Windows 目标机 ```bat :: ① 拷包 (建议排除本地痕迹, 见 §五): 整个目录复制到无空格、无中文的路径, 例如 D:\guanlan\app :: ② 安装 (离线; 自动选 Python → 建 .venv → 用包内轮子装依赖 → 写配置 → 自检) 双击 install.bat 或: powershell -ExecutionPolicy Bypass -File install.ps1 :: ③ 自检 → 启动 双击 check.bat :: 期望全 [OK] (模型那行 FAIL 只影响问答, 其余页面正常) 双击 start.bat :: 自动打开 http://127.0.0.1:28084/ ``` ### Linux / macOS 目标机 ```bash # ① 拷包到无空格无中文路径(如 /opt/guanlan) # ② 安装 (离线; 无合适系统 Python 时用包内便携运行时; 多版本机器: GUANLAN_PY=/usr/bin/python3.11 sh install.sh) sh install.sh # ③ 起停 .venv/bin/python guanlan.py check .venv/bin/python guanlan.py serve # 停止: .venv/bin/python guanlan.py stop ``` **离线边界(如实)**: Windows 侧的轮子在 `wheels/win_amd64/`(42 个, 与 `requirements.txt` 对得上) → **完全离线**; **Linux·macOS 侧包内没有轮子**, `install.sh` 找不到 `wheels/linux_`(或 `wheels/macos_arm64`)时会 **自动改成联网安装**。要在 Linux/macOS 上离线装, 先在**有网的同类机器**上 `pip download -r requirements.txt -d wheels/linux_x86_64`(注意 `--platform/--python-version`), 把目录放进包内再拷过去。 ## 三、端口与配置 - 真源是 `configs/serve.json`: `host` / `gateway` / `detail` / `cms` / `sim` / `sim_sys` / `viewer` / `ollama`, 以及 `python`(相对) · `raw_dir`(相对) · `release_dir` · `viewer_dir` · `sim_dir` —— **都是相对路径**。 - ⚠ **已知限制**: `scripts/guanlan_gateway.py` 的 `ROUTES` 表里**上游端口是写死的**, 只支持 `GUANLAN_OLLAMA_PORT` 环境变量覆盖 ollama; 要改 18033/18020/18791/18792/64292 得**同时改 `serve.json` 与 ROUTES**, 否则网关 探活/代理会对不上(网关启动时不会自动读 `serve.json` 的上游端口)。 - 服务只绑 `127.0.0.1`, 不对外开端口。 ## 四、拷过去之后怎么算"成了"(验收清单) ```bat scripts\check_portability.py :: 路径可移植门禁 (0 ERROR) scripts\check_transferable.py :: 移植性大扫描 (见 §六) guanlan.py check :: 依赖/产物/发布件/端口/模型 逐项 ``` | 检查 | 期望 | |---|---| | `guanlan.py serve` | `状态 degraded ... 模块 6/7 ok`, 只有 `/local-ai/` 可能 DOWN(本机模型未装) | | 页面 | `/` 门户 200 · `/detail/` 工作台 200 · `/cms/` 200 · `/sim/` `/sim/sys/` `/viewer/` 200 · `/ops` 运维控制台 200 | | 产物锚点 | 报警 39211 行 · 工单 5876 · 油样 404 · `temp_monthly` 19494 · 本体 9702 对象 | | 控制台 | `/ops` 按钮随真实状态启用; 点"执行重算"能跑完 12 步(退出码 0) | ## 五、交付/打包时建议清掉的本地痕迹 | 项 | 为什么 | |---|---| | `_products_off/` `_products_off_prev_*/` | 本机"清除产物"的暂存与存档(每份都是整份产物 ~220 MB); 目标机用不到 | | `logs/` `run/pids.json` | 本机运行日志与**旧 PID**; pids.json 到新机器上是无效引用(启动器会重写) | | `.git/` | 55 MB 仓库; 交付不需要(自己留版除外) | | `data/raw/`(视交付约定) | 30.9 GB 现场原始件; 按约定"原始件不随包分发"时不必带(缺它只影响"重算原始数据", 不影响页面) | | `release/viewer/*.json` 里的 `source_path` | 带着**开发机磁盘结构**(如 `/Volumes/T5 EVO/风电数据/…`); 不影响渲染, 但对外交付建议清掉(脱敏) | ## 六、`scripts/check_transferable.py` 查什么 比 `check_portability.py`(只看 `.py` 的路径写法)更宽 —— 因为"能不能独立运行"还取决于环境: 1. **所有文本类型**里的机器相关绝对路径(`.py/.bat/.sh/.ps1/.json/.md/.txt/.html/.yaml/.cfg`), 不只源码; 2. **虚拟环境**: `.venv/pyvenv.cfg` 的 `home` 指向哪个基础解释器(换机是否还在); 3. **离线依赖**: `wheels/<平台>` 有没有、与 `requirements.txt` 对不对得上; 4. **便携运行时**: `vendor/python/…` 在不在、`vendor/MANIFEST.json` 登记是否齐全; 5. **配置与端口**: `serve.json` 里有没有绝对路径、有多少地方提到端口。 > 现状(2026-09-12 实测): 文本里仍有 350 处机器相关路径, **但都不在运行路径上** —— 分布是 > `release/viewer/*`(三维单位的 `source_path` 出处注记, 186 处) · `outputs/**`(产物里记的历史路径/provenance, 95) · > `src/sop/farm_paths.py`(盘符映射表本体, 门禁具名登记) · `scripts/build_oem_lexicon.py`(开发机 OEM 资料盘) · > `_修复记录_20260911/fix_*.py`(一次性修复脚本留档) · 文档里的反面示例。**都不影响在别的机器上运行**。