The curator app (Python backend, tests, systemd units, config, scripts) now lives in this repo under scenarios/curator/backend, exported from the standalone checkout's tracked tree (.pi mirror, venv and caches excluded). 149 unit tests pass from the new location; _SHARED_LIB and eval GOLDEN_DIR resolve unchanged. History not preserved per decision. verify-no-secrets: the ASSIGN heuristic now requires the value to carry entropy (a digit or uppercase letter), so vendored Python kwargs like token=extraction_token no longer false-positive while real base64/hex/random secrets still trip it.
458 lines
17 KiB
Markdown
458 lines
17 KiB
Markdown
---
|
||
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": "<ZENMUX_API_KEY>",
|
||
"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=<TELEGRAM_BOT_TOKEN>
|
||
CURATOR_TELEGRAM_ALLOWED_USERS=<TELEGRAM_USER_ID>
|
||
|
||
CURATOR_RADARR_URL=http://192.168.50.10:7878
|
||
CURATOR_RADARR_API_KEY=<RADARR_API_KEY>
|
||
CURATOR_RADARR_4K_URL=http://192.168.50.100:7878
|
||
CURATOR_RADARR_4K_API_KEY=<RADARR_4K_API_KEY>
|
||
CURATOR_SONARR_URL=http://192.168.50.10:8989
|
||
CURATOR_SONARR_API_KEY=<SONARR_API_KEY>
|
||
CURATOR_SONARR_4K_URL=http://192.168.50.100:8989
|
||
CURATOR_SONARR_4K_API_KEY=<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=<PLEX_TOKEN>
|
||
CURATOR_PLEX_MUSIC_SECTION_ID=
|
||
|
||
# 配置后增加书评网络证据;留空时使用零 Key 回退。
|
||
CURATOR_TAVILY_API_KEY=<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 <BACKUP_FILE>.sha256
|
||
|
||
cp /home/claw/.local/share/curator/curator.sqlite3 \
|
||
/home/claw/.local/share/curator/curator.sqlite3.before-restore
|
||
install -m 600 <BACKUP_FILE> \
|
||
/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` | 总体架构、边界与路线图 |
|