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.
17 KiB
date, updated, type, status, tags, aliases
| date | updated | type | status | tags | aliases | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-08-26 | 2026-08-26 | runbook | active |
|
|
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. 运行架构与责任边界
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。
先检查挂载和写权限:
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 用户下执行:
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
安装当前验证版本:
npm install -g @earendil-works/pi-coding-agent@0.84.3
pi --version
Pi 的 ZenMux 自定义 provider 位于 ~/.pi/agent/models.json。以下是最小结构示意,真实 API Key 只写在本机:
{
"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"
}
}
]
}
}
}
chmod 600 ~/.pi/agent/models.json
部署 Curator 专用 workspace。仓库文件是权威源,生产目录只是运行副本(工作区由
pi-agent-config 的 scripts/deploy-scenario.sh 从 scenarios/curator/workspace/ 部署,
不再是本仓库内的文件):
分别验证主模型和回退模型:
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
从模板创建生产环境文件:
cd /home/claw/pi-workspaces/curator
install -m 600 config/curator.env.example ~/.config/curator/curator.env
编辑 ~/.config/curator/curator.env,至少填写:
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}
可选能力:
# 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:
chmod 600 ~/.config/curator/curator.env
stat -c '%a %U:%G %n' ~/.config/curator/curator.env
微信链接依赖本机正文服务。当前 systemd unit 使用:
CURATOR_WECHAT_ARTICLE_BASE_URL=http://192.168.50.145:8091
微信正文服务不可用时,普通文字、普通网页、电子书和本地目录查询仍可工作,只有微信文章提取会失败。
7. 部署 systemd 用户服务
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 一次性执行:
sudo loginctl enable-linger claw
常用命令:
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 服务与存储
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; - 四个
*Arrcatalog 为true; pi_model与 systemd unit 一致;- Web 根页面返回 HTTP
200。
8.2 Telegram 功能
依次测试:
/status:确认服务有响应。权力的游戏,库里有什么版本:应查询 Sonarr/Sonarr 4K 后自然语言答复,不应要求用户先选媒体类型。- 发送一部不存在的电影并明确说“加入”:应优先加入 Radarr 4K 并触发搜索;若已经存在则报告现有状态。
- 发送一篇普通网页或微信文章:应先提取文章中的书、电影、剧集或音乐,再逐项查重和评价,不能评价文章本身。
- 发送 EPUB/PDF:应建立独立导入任务,校验文件并在
/library可见。 - 发送
再试一次:应重跑当前聊天最近一次来源。
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 的职责,应由宿主机/存储层另行承担。
立即执行一次维护并检查结果:
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 恢复
先停服务并保留当前数据库,再恢复指定备份:
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. 更新与回滚
更新前:
systemctl --user start curator-maintenance.service
systemctl --user status curator-maintenance.service
更新源码后执行测试并重启:
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 未监听
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
通常表示候选项没有可用本地封面,不代表作品、数据库或导入任务失败。先看候选详情中的元数据和评价状态,再判断是否需要刷新。
数据库报错
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 |
总体架构、边界与路线图 |