--- date: 2026-08-26 updated: 2026-08-26 type: runbook status: active tags: [书影音, Curator, Pi-Agent, Telegram, HomeLab] aliases: [Curator 部署手册, 书影音 Pi Agent 部署] --- # Curator 书影音 Pi Agent 部署与运维 > [!summary] Summary > 本文是 Curator 在 `192.168.50.145` 上的生产部署手册,记录当前实际运行方式、依赖、配置、验证、备份和故障处理。架构目标与后续规划见 [[Curator 书影音管理中枢]]。 > 本文不保存真实 Token、API Key 或密码。生产密钥只放在权限为 `0600` 的本机配置文件中。 ## 1. 当前生产基线 截至 2026-08-26,生产服务如下: | 项目 | 当前值 | | --- | --- | | 主机 | `192.168.50.145` | | LAN Web | `http://192.168.50.145:8766/` | | 进程管理 | `systemd --user` | | 服务 | `curator.service` | | 维护定时器 | `curator-maintenance.timer` | | Python 入口 | `/usr/bin/python3 -m curator serve` | | Pi CLI | `@earendil-works/pi-coding-agent@0.84.3` | | 主模型 | `zenmux/openai/gpt-5.6-luna`,`high` thinking | | 回退模型 | `zenmux/x-ai/grok-4.6` | | 单次 Pi 超时 | 120 秒 | | SQLite | `/home/claw/.local/share/curator/curator.sqlite3` | | Pi 会话 | `/home/claw/.local/share/pi-curator/sessions` | | Pi workspace | `/home/claw/pi-workspaces/curator` | | 书库 | `/mnt/truenas/multimedia/books` | | 暂存 | `/mnt/truenas/multimedia/curator/staging/books` | | 备份 | `/mnt/truenas/multimedia/curator/backup` | 当前已经接通 Telegram、Radarr、Radarr 4K、Sonarr 和 Sonarr 4K。Plex 音乐查询和 Tavily 是可选配置,当前健康检查中尚未启用;书籍评价仍可使用公开页面和 DuckDuckGo 回退。音乐自动获取、EPUB 自动翻译、Z-Library 自动下载均未接入 Curator。 生产环境直接从项目源码运行于专用 LLM VPS,Pi 作为 `systemd --user` 服务的子进程跑在 host 上,不做容器化。VPS 专用于 LLM,`systemd` 沙箱(`ProtectSystem=strict`、`ProtectHome=read-only`、`NoNewPrivileges` 等)已是有意为之的隔离上限。 ## 2. 运行架构与责任边界 ```text Telegram / LAN Web | v Curator Python API |-- 确定性预分类、权限、计划、执行、核验和审计 |-- Pi Agent:理解意图、消歧、评价和组织答复 | +-- SQLite:电子书权威目录、候选、任务和控制账本 +-- Radarr/Sonarr:影视目录、版本和获取 +-- Plex:音乐目录、管理和播放(配置后启用) +-- 微信正文服务:微信文章正文提取 +-- 公共网页:书籍元数据与评价证据 | v TrueNAS / unRaid 文件存储 ``` Pi Agent 使用独立 workspace 和持久会话,但启动参数为 `--approve --no-tools`。模型只输出结构化意图或自然语言答复,不直接调用 shell、修改文件、访问 SQLite 或写入 `*Arr`;所有事实查询和副作用都由 Curator 的确定性适配器完成。 影视默认优先查询和收集 4K 版本。SQLite 只作为电子书权威目录及跨后端审计账本,不复制 `*Arr` 和 Plex 已有的完整媒体目录。 ## 3. 前置条件 主机需要: - Debian/Linux 用户 `claw`,支持 `systemd --user`; - Python 3.13 或兼容版本; - Node.js 22、npm; - 可访问 ZenMux、Telegram、书籍评价网页和局域网后端; - TrueNAS NFS 已挂载到 `/mnt/truenas/multimedia`,并对 `claw` 可写; - Radarr/Sonarr API Key;需要音乐查询时再配置 Plex Token; - 独立 Telegram Bot Token 和允许访问的 Telegram user ID。 先检查挂载和写权限: ```bash findmnt -T /mnt/truenas/multimedia touch /mnt/truenas/multimedia/curator/.curator-write-test rm /mnt/truenas/multimedia/curator/.curator-write-test ``` 如果 `findmnt` 显示为只读,先修复宿主机 NFS 挂载。Codex 沙盒里看到的只读视图不能代替宿主机检查。 ## 4. 目录初始化 在 `claw` 用户下执行: ```bash install -d -m 700 ~/.config/curator install -d -m 700 ~/.local/share/curator install -d -m 700 ~/.local/share/pi-curator/sessions install -d -m 700 ~/pi-workspaces/curator/.pi/skills/curator-media install -d -m 775 /mnt/truenas/multimedia/books install -d -m 775 /mnt/truenas/multimedia/curator/staging/books install -d -m 775 /mnt/truenas/multimedia/curator/backup ``` 敏感的配置、SQLite 和 Pi 会话目录建议保持 `0700`;共享媒体目录根据 NFS 身份映射维持可写权限。 ## 5. 安装并配置 Pi CLI 安装当前验证版本: ```bash npm install -g @earendil-works/pi-coding-agent@0.84.3 pi --version ``` Pi 的 ZenMux 自定义 provider 位于 `~/.pi/agent/models.json`。以下是最小结构示意,真实 API Key 只写在本机: ```json { "providers": { "zenmux": { "name": "ZenMux", "baseUrl": "https://zenmux.ai/api/v1", "api": "openai-responses", "apiKey": "", "authHeader": true, "models": [ { "id": "openai/gpt-5.6-luna", "name": "GPT-5.6 Luna", "reasoning": true, "input": ["text", "image"], "contextWindow": 1050000, "thinkingLevelMap": { "minimal": "minimal", "low": "low", "medium": "medium", "high": "high", "xhigh": "xhigh" } } ] } } } ``` ```bash chmod 600 ~/.pi/agent/models.json ``` 部署 Curator 专用 workspace。仓库文件是权威源,生产目录只是运行副本(工作区由 pi-agent-config 的 `scripts/deploy-scenario.sh` 从 `scenarios/curator/workspace/` 部署, 不再是本仓库内的文件): 分别验证主模型和回退模型: ```bash pi --mode text --print --provider zenmux --model openai/gpt-5.6-luna \ --thinking high --no-tools --no-session '只输出 OK' pi --mode text --print --provider zenmux --model x-ai/grok-4.6 \ --thinking high --no-tools --no-session '只输出 OK' ``` 回退模型如果不在 `models.json` 中,Pi 可能提示 `Model not found ... Using custom model id`;只要随后正常输出 `OK`,该提示本身不是故障。 ## 6. 配置 Curator 从模板创建生产环境文件: ```bash cd /home/claw/pi-workspaces/curator install -m 600 config/curator.env.example ~/.config/curator/curator.env ``` 编辑 `~/.config/curator/curator.env`,至少填写: ```dotenv CURATOR_DATA_ROOT=/home/claw/.local/share/curator CURATOR_LIBRARY_ROOT=/mnt/truenas/multimedia/books CURATOR_STAGING_ROOT=/mnt/truenas/multimedia/curator/staging/books CURATOR_BACKUP_ROOT=/mnt/truenas/multimedia/curator/backup CURATOR_HOST=0.0.0.0 CURATOR_PORT=8766 CURATOR_MAX_UPLOAD_BYTES=268435456 CURATOR_TELEGRAM_BOT_TOKEN= CURATOR_TELEGRAM_ALLOWED_USERS= CURATOR_RADARR_URL=http://192.168.50.10:7878 CURATOR_RADARR_API_KEY= CURATOR_RADARR_4K_URL=http://192.168.50.100:7878 CURATOR_RADARR_4K_API_KEY= CURATOR_SONARR_URL=http://192.168.50.10:8989 CURATOR_SONARR_API_KEY= CURATOR_SONARR_4K_URL=http://192.168.50.100:8989 CURATOR_SONARR_4K_API_KEY= CURATOR_RADARR_ROOT_FOLDER=/mnt/truenas/multimedia/movies CURATOR_RADARR_QUALITY_PROFILE_ID=4 CURATOR_RADARR_4K_ROOT_FOLDER=/mnt/unRaid/movie4k CURATOR_RADARR_4K_QUALITY_PROFILE_ID=5 CURATOR_SONARR_ROOT_FOLDER=/mnt/truenas/multimedia/tv CURATOR_SONARR_QUALITY_PROFILE_ID=4 CURATOR_SONARR_4K_ROOT_FOLDER=/mnt/unRaid/tv4k CURATOR_SONARR_4K_QUALITY_PROFILE_ID=7 CURATOR_ZLIB_SEARCH_URL_TEMPLATE=https://zlib.li/s/{query} ``` 可选能力: ```dotenv # Plex 是音乐目录、管理和播放的权威源。 CURATOR_PLEX_URL=http://192.168.50.100:32400 CURATOR_PLEX_TOKEN= CURATOR_PLEX_MUSIC_SECTION_ID= # 配置后增加书评网络证据;留空时使用零 Key 回退。 CURATOR_TAVILY_API_KEY= CURATOR_BOOK_WEB_REVIEW_MAX_RESULTS=6 ``` 检查权限,且不要把该文件提交到 Git: ```bash chmod 600 ~/.config/curator/curator.env stat -c '%a %U:%G %n' ~/.config/curator/curator.env ``` 微信链接依赖本机正文服务。当前 systemd unit 使用: ```text CURATOR_WECHAT_ARTICLE_BASE_URL=http://192.168.50.145:8091 ``` 微信正文服务不可用时,普通文字、普通网页、电子书和本地目录查询仍可工作,只有微信文章提取会失败。 ## 7. 部署 systemd 用户服务 ```bash install -d -m 700 ~/.config/systemd/user cd /home/claw/pi-workspaces/curator install -m 600 systemd/curator.service ~/.config/systemd/user/curator.service install -m 600 systemd/curator-maintenance.service \ ~/.config/systemd/user/curator-maintenance.service install -m 600 systemd/curator-maintenance.timer \ ~/.config/systemd/user/curator-maintenance.timer systemctl --user daemon-reload systemctl --user enable --now curator.service curator-maintenance.timer ``` 为确保用户退出 SSH 后服务仍运行,由 root 一次性执行: ```bash sudo loginctl enable-linger claw ``` 常用命令: ```bash systemctl --user status curator.service systemctl --user restart curator.service systemctl --user stop curator.service systemctl --user status curator-maintenance.timer journalctl --user -u curator.service -f journalctl --user -u curator-maintenance.service -n 100 --no-pager ``` ## 8. 上线验收 ### 8.1 服务与存储 ```bash cd /home/claw/pi-workspaces/curator PYTHONPATH=. python3 -m curator health curl -fsS http://127.0.0.1:8766/api/health | jq curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8766/ systemctl --user is-active curator.service systemctl --user is-enabled curator.service curator-maintenance.timer ``` 健康结果至少应满足: - `status=ok`; - `library_writable=true`、`staging_writable=true`; - Telegram 为 `true`; - 四个 `*Arr` catalog 为 `true`; - `pi_model` 与 systemd unit 一致; - Web 根页面返回 HTTP `200`。 ### 8.2 Telegram 功能 依次测试: 1. `/status`:确认服务有响应。 2. `权力的游戏,库里有什么版本`:应查询 Sonarr/Sonarr 4K 后自然语言答复,不应要求用户先选媒体类型。 3. 发送一部不存在的电影并明确说“加入”:应优先加入 Radarr 4K 并触发搜索;若已经存在则报告现有状态。 4. 发送一篇普通网页或微信文章:应先提取文章中的书、电影、剧集或音乐,再逐项查重和评价,不能评价文章本身。 5. 发送 EPUB/PDF:应建立独立导入任务,校验文件并在 `/library` 可见。 6. 发送 `再试一次`:应重跑当前聊天最近一次来源。 ### 8.3 LAN Web 检查以下页面: - `/candidates`:待决策作品与评价证据; - `/wanted`:已决定获取的书籍和手动 Z-Library 搜索链接; - `/library`:已验证的电子书及后端已入库媒体; - `/sources`:原始来源与提取结果; - `/activity`:导入、分析和执行任务; - `/upload`:批量上传 EPUB/PDF。 ## 9. 数据、会话与备份 ### 9.1 权威数据 - SQLite:电子书 Work/Edition/Asset、候选、wanted、来源、任务、意图、计划、命令和事件。 - Radarr/Sonarr:影视目录、监控、质量和下载状态。 - Plex:音乐目录与播放状态,配置后生效。 - TrueNAS:实际电子书、暂存文件和数据库备份。 - Pi session:Telegram 对话连续性;不是媒体事实库。 ### 9.2 当前自动维护策略 `curator-maintenance.timer` 每天 `03:15` 运行,另有最多 10 分钟随机延迟。维护任务: - 使用 SQLite 在线备份接口生成一致备份; - 执行完整性检查; - 为备份写入 `.sha256`; - 保留最近 14 天的日备份; - 删除超过 7 天的 staging 文件。 当前代码尚未实现架构文档中设想的周备份和月备份。TrueNAS 快照、媒体文件备份以及 `curator.env`、Pi provider 配置和 Pi session 备份,也不属于当前 timer 的职责,应由宿主机/存储层另行承担。 立即执行一次维护并检查结果: ```bash systemctl --user start curator-maintenance.service systemctl --user status curator-maintenance.service find /mnt/truenas/multimedia/curator/backup -type f \ \( -name '*.sqlite3' -o -name '*.sha256' \) -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort ``` ### 9.3 SQLite 恢复 先停服务并保留当前数据库,再恢复指定备份: ```bash systemctl --user stop curator.service cd /mnt/truenas/multimedia/curator/backup/database/daily sha256sum -c .sha256 cp /home/claw/.local/share/curator/curator.sqlite3 \ /home/claw/.local/share/curator/curator.sqlite3.before-restore install -m 600 \ /home/claw/.local/share/curator/curator.sqlite3.restore python3 -c "import sqlite3; p='/home/claw/.local/share/curator/curator.sqlite3.restore'; print(sqlite3.connect(p).execute('PRAGMA integrity_check').fetchone()[0])" mv /home/claw/.local/share/curator/curator.sqlite3.restore \ /home/claw/.local/share/curator/curator.sqlite3 systemctl --user start curator.service curl -fsS http://127.0.0.1:8766/api/health | jq ``` 只有完整性检查输出 `ok` 才继续替换。恢复 SQLite 不会自动回滚 `*Arr`、Plex 或文件系统中已经执行的外部动作。 ## 10. 更新与回滚 更新前: ```bash systemctl --user start curator-maintenance.service systemctl --user status curator-maintenance.service ``` 更新源码后执行测试并重启: ```bash cd /home/claw/pi-workspaces/curator PYTHONPATH=. python3 -m unittest discover -s tests -v systemctl --user restart curator.service curl -fsS http://127.0.0.1:8766/api/health | jq ``` 如果 systemd 文件有变化,先重新安装 unit 并执行 `systemctl --user daemon-reload`。代码回滚后若数据库 schema 不兼容,再按上一节恢复更新前备份;不要只恢复数据库而保留不匹配的代码版本。 ## 11. 常见故障 ### Web 无法打开或 8766 未监听 ```bash systemctl --user status curator.service journalctl --user -u curator.service -n 200 --no-pager ss -ltnp | grep ':8766' ``` 重点检查 Python 异常、端口冲突、环境文件路径和 NFS 可写性。 ### Telegram 不回复 检查: - Bot Token 是否正确; - user ID 是否在 `CURATOR_TELEGRAM_ALLOWED_USERS`; - ZenMux 主模型是否可调用; - `journalctl` 是否持续出现 Telegram 网络错误。 Telegram 偶发 `SSL EOF`、读超时或 `502` 时,gateway 会记录错误、等待 5 秒并继续轮询。短暂出现无需重启;持续数分钟再检查网络、代理和 Telegram API。 ### Pi 请求超时或模型异常 手动运行第 5 节的两个模型探针。主模型超过 120 秒后 Curator 会尝试 Grok 4.6 回退。主、备都失败时,检查 `~/.pi/agent/models.json`、ZenMux 配额和 `journalctl`;不要把 provider API Key 写进 systemd unit 或仓库。 ### 微信文章提取失败 确认 `192.168.50.145:8091` 的正文服务仍在运行且登录态有效。微信风控、扫码态过期或正文服务不可用都可能导致失败;普通 URL 和手工粘贴作品名仍可使用。 ### NFS 出现 `Stale file handle` 确认 TrueNAS export 仍存在,然后在没有写任务时重新挂载对应 NFS。恢复后重新执行写探针和 `/api/health`。避免在 NFS 失效期间反复启动导入或维护任务。 ### 封面返回 404 通常表示候选项没有可用本地封面,不代表作品、数据库或导入任务失败。先看候选详情中的元数据和评价状态,再判断是否需要刷新。 ### 数据库报错 ```bash python3 -c "import sqlite3; p='/home/claw/.local/share/curator/curator.sqlite3'; print(sqlite3.connect(p).execute('PRAGMA integrity_check').fetchone()[0])" ``` 输出不是 `ok` 时先停服务,保留故障数据库,再从最近通过校验的备份恢复。 ## 12. 外部调用与当前限制 Curator LAN Web/API 只用于 LAN 或 tailnet,当前不设计公网暴露。删除、覆盖和批量清理没有开放给 Telegram Agent。 书籍候选页提供 `zlib.li` 手动搜索。独立下载器位于 `/home/claw/pi-workspaces/zlib-fetcher/`,支持持久登录态、匿名额度识别和普通 HTTP/SOCKS 代理,但尚未接入 Curator wanted 队列。调用方式见 `/home/claw/pi-workspaces/zlib-fetcher/docs/`。 音乐查询必须配置 Plex;gamdl 只应由未来的 Curator Downloader 封装为下载执行器,不能代替 Plex 目录。当前没有自动音乐下载。 ## 13. 部署文件索引 | 文件 | 用途 | | --- | --- | | `README.md` | 功能与开发入口 | | `config/curator.env.example` | 无密钥环境变量模板 | | `systemd/curator.service` | 生产 Web、Telegram、Pi 服务 | | `systemd/curator-maintenance.*` | 备份和清理任务 | | `curator/pi_agent.py` | Pi 调用、模型回退和结构化提示 | | `curator/telegram.py` | Telegram gateway 与交互流程 | | `curator/maintenance.py` | SQLite 备份与 retention | | `docs/obsidian/Curator 书影音管理中枢.md` | 总体架构、边界与路线图 |