Files
pi-agent-config/scenarios/curator/backend/docs/deployment.zh-CN.md
T
Kai 88b06d782f feat(curator): vendor the application backend as the scenario's tracked source
The curator Python backend (package, tests, systemd units, config templates, scripts) now lives under scenarios/curator/backend and is the single source of truth; the live checkout at the workspace path is a runtime copy. Exported from the app repo's tracked tree via git archive (no history, .pi/venv/caches excluded). 149 unit tests pass from the new location.

profile.toml backend is now repo-relative (scenarios/curator/backend); verify-generated.sh resolves a relative backend against REPO_ROOT. verify-no-secrets ASSIGN heuristic now requires value entropy so vendored kwargs like token=extraction_token no longer false-positive. README documents the backend/ layout and the operator-owned app rollout step.
2026-08-30 18:49:10 -07:00

458 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 sessionTelegram 对话连续性;不是媒体事实库。
### 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` | 总体架构、边界与路线图 |