移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。
**目前能用的(真环境实测,非推断)**:
profile/other : 200, 7075 字节 —— 博主主页指标(粉丝/获赞/作品数/昵称)
aweme/detail : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)
**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
挑中的恰好是「批量拉作品列表」这个最敏感的动作。
2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
代价,过几小时要重测)。
所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。
**排查中控住变量后得到的两条事实**(都写进注释了):
· `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
(我先前猜的 sec-ch-ua 不是关键。)
· 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
从 CDP 取齐 cookie + UA + hints,而不是各自写死。
「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。
测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
13 KiB
13 KiB
type, domain, nature, tags, status, created, updated, version, supersedes
| type | domain | nature | tags | status | created | updated | version | supersedes | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| concept | system | plan |
|
active | 2026-06-16 | 2026-06-16 | 1.0.0 |
AgentOS 联邦指挥台 — 实施计划 v1.0
基于
federation-operations-architecture.md设计文档 参考:federated-multi-machine-architecture.md/dashboard-v4-design.md/CORE-ARCHITECTURE.md总体估计: ≈ 20 小时
一、优先级总览
P0 ─── 感知层: 让指挥台"看到"所有机器状态
├─ 机器状态条(在线/离线/忙碌)
├─ 账号级忙碌状态
└─ 操作前的资源检查
P1 ─── 路由层: 让指挥台"指挥"远程机器
├─ owner_machine 操作路由
├─ 远程执行通道完善
└─ 按钮状态智能化(灰掉/提示/远程执行)
P2 ─── 引擎层: 操作生命周期管理
├─ 统一操作队列(状态机)
├─ 资源锁系统
├─ 状态归零(pre-flight reset)
└─ 日志聚合
P3 ─── 生态层: 高级功能和系统完备
├─ 文件级 WPRA 写入规范
├─ guardd 模块补全
├─ 9 插件体系完善
└─ 键盘锁定/离线队列/DAG
二、依赖关系拓扑
P0-1 机器状态条
└── 依赖: guardd 心跳已实现 ✅
└── 阻塞: P1-1 (操作路由需要知道机器是否在线)
P0-2 账号忙碌状态
└── 依赖: 本地资源锁文件
└── 阻塞: P2-2 (资源锁系统)
P1-1 操作路由 (owner_machine 判断)
└── 依赖: P0-1 (机器在线状态)
└── 阻塞: P1-2 (远程执行通道)
P1-2 远程执行通道
└── 依赖: federation API 已部分实现 ✅
└── 前置: 完善 /api/federation/exec 支持所有操作类型
P2-1 状态机队列
└── 依赖: P1-1, P1-2
└── 前置: cross_machine/tasks/ 目录
P2-2 资源锁系统
└── 依赖: 本地文件锁 + guardd 锁管理
└── 前置: guardd 锁模块
P3-1 WPRA 写入规范
└── 依赖: cross_machine/data/ 目录结构已存在 ✅
└── 前置: 插件改写为文件级写入
三、Phase 0: 立即修复 (之前审计发现的问题)
| # | 任务 | 文件 | 估计 | 优先级 |
|---|---|---|---|---|
| 0.1 | 账号管理跨机显示(已做) | index.html | ✅ 已完成 | P0 |
| 0.2 | 修复 matrix-mgmt 路由 | app.py | ✅ 已完成 | P0 |
| 0.3 | 修复 cross-machines API | app.py | ✅ 已完成 | P0 |
| 0.4 | 修复 loadSmsAccounts 数据格式 | index.html | ✅ 已完成 | P0 |
| 0.5 | SMS API 加 owner_machine | sms_proxy_api.py | ✅ 已完成 | P0 |
| 0.6 | 前端代理/调度/任务路径错配 | index.html | ≈ 20min | P0 |
| 0.7 | 语料库缺失API补充 | routes/matrix.py | ≈ 30min | P0 |
四、Phase 1: 感知层 — 让指挥台"看见" (≈ 3h)
1.1 机器状态条 (≈ 1h)
在每个视图顶部增加机器状态条:
┌─────────────────────────────────────────────────────┐
│ 🟢 chengzigedeAir 🟢 5kechengdeAir ⚪ 7kecheng │
│ 账号: 5在线/5总 账号: 0在线/5总 离线30分钟 │
└─────────────────────────────────────────────────────┘
文件: index.html + core.js (添加全局状态条组件)
实现:
- 每 30s 轮询
/api/federation/health获取三台机器在线状态 - 状态条渲染为全局组件,所有视图共用
- 绿/黄/灰三色: 在线 / 忙碌(有任务运行) / 离线(>5min无心跳)
1.2 账号级忙碌状态 (≈ 1h)
douyin_01 🟢 在线 ✅ 可操作
douyin_02 🔴 忙碌 ⏳ 正在养号中 (剩余23分钟)
douyin_03 ⚪ 离线 ❌ 机器5kecheng当前离线
文件: sms_proxy_api.py (加忙碌字段) + index.html (展示)
实现:
- guardd 维护一个
locks.json,记录当前哪个账号正在被操作 - SMS API 响应中加
busy: true/false,busy_since: timestamp - 忙碌的账号按钮灰掉,显示"正在操作中"
1.3 前端路径错配修复 (≈ 20min)
| 前端调用 | 改为 | 文件 |
|---|---|---|
/api/matrix/proxy/list |
/api/matrix/proxies |
index.html |
/api/matrix/schedule/list |
/api/matrix/schedules |
index.html |
/api/matrix/task/comment |
/api/matrix/task/run (POST+type=comment) |
index.html |
五、Phase 2: 路由层 — 让指挥台"指挥" (≈ 5h)
2.1 操作路由 — 本地 vs 远程 (≈ 2h)
核心逻辑 (所有操作按钮的通用函数):
async function executeOperation(accountId, operationType, params) {
// 1. 查账号所属机器
const account = findAccount(accountId);
const targetMachine = account.owner_machine;
// 2. 查机器是否在线
const machineStatus = await getMachineStatus(targetMachine);
if (machineStatus === 'offline') {
showError(`${targetMachine} 当前离线,无法操作`);
return;
}
// 3. 如果是本机 → 本地API
if (targetMachine === currentMachine) {
return localExecute(operationType, params);
}
// 4. 如果是远程机器 → 联邦 exec
return remoteExecute(targetMachine, operationType, params);
}
文件: 新建 static/modules/operation-router.js
改动:
accountLogin()→ 通过路由执行clearCookies()→ 通过路由执行deleteAccount()→ 通过路由执行batchExecute()→ 支持跨机批量
2.2 远程执行通道完善 (≈ 2h)
文件: services/remote_exec.py
新增能力:
- 支持登录命令:
ssh {machine} "cd agent-sync && agentos matrix login {account}" - 支持养号命令:
ssh {machine} "cd agent-sync && agentos matrix run --blueprint {bp} --rounds {n}" - 支持采集命令:
ssh {machine} "cd agent-sync && agentos matrix collect {phone}" - 统一返回格式:
{status, output, error, duration_sec}
2.3 新建前端模块目录 (≈ 30min)
static/modules/
├── core.js # 框架核心 ✅ 现有
├── operation-router.js # 操作路由 (新建)
├── machine-bar.js # 机器状态条 (新建)
├── operation-queue.js # 操作队列 (Phase 3)
├── resource-lock.js # 资源锁 (Phase 3)
└── ... # 现有其他模块
文件: index.html — 加入新的 script 加载顺序
2.4 按钮状态智能化 (≈ 30min)
| 账号状态 | 登录按钮 | 养号按钮 | 采集按钮 |
|---|---|---|---|
| 本机·在线·空闲 | 🟢 可用 | 🟢 可用 | 🟢 可用 |
| 本机·在线·忙碌 | 🔴 灰掉"正在养号中" | 🔴 灰掉 | 🟢 可用 |
| 远程·在线·空闲 | 🟢 "远程执行" | 🟢 "远程执行" | 🟢 "远程执行" |
| 远程·离线 | ⚪ 灰掉"XX机离线" | ⚪ 灰掉 | ⚪ 灰掉 |
六、Phase 3: 引擎层 — 操作生命周期管理 (≈ 7h)
3.1 统一操作队列 + 状态机 (≈ 3h)
文件:
guardd/modules/operation_queue.py(新建)static/modules/operation-queue.js(新建)
后端:
# guardd/modules/operation_queue.py
class OperationQueue:
"""操作队列 — 管理本机所有操作的生命周期"""
def submit(self, op_type, params) -> str:
"""提交操作,返回 operation_id"""
# 写 cross_machine/tasks/pending/{op_id}.json
def check(self, op_id) -> dict:
"""查询操作状态"""
def cancel(self, op_id) -> bool:
"""取消正在运行的操作"""
def cleanup(self, op_id):
"""操作完成后清理"""
前端: 操作日志面板,按机器/时间/类型过滤
3.2 资源锁系统 (≈ 2h)
文件:
guardd/modules/resource_lock.py(新建)static/modules/resource-lock.js(新建)
锁表:
locks = {
"browser": {"held_by": "op_001", "acquired_at": "...", "ttl": 3600},
"account:douyin_01": {"held_by": "op_001", ...},
"identity:douyin_01_camo": {"held_by": "op_001", ...},
}
规则:
- 锁自动过期 (TTL)
- 锁可被强制释放 (管理员)
- 锁冲突时: 拒绝新操作,提示"资源被 XX 操作占用"
3.3 状态归零 Pre-flight Reset (≈ 1h)
文件: guardd/modules/preflight.py (新建)
每次操作前自动执行:
1. pkill -f camoufox # 杀残留浏览器
2. pkill -f playwright # 杀残留驱动
3. rm -rf /tmp/camoufox_* # 清临时文件
4. check_locks() # 检查并释放过期锁
5. check_disk_space() # 检查磁盘空间
6. return "ready" # 返回就绪状态
3.4 日志聚合 (≈ 1h)
文件:
app.py新增/api/logs/push端点guardd/modules/log_aggregator.py(新建)
日志格式:
{
"op_id": "op_20260616_001",
"machine": "5kechengdeAir",
"type": "nurture_run",
"status": "completed",
"states": [...],
"output": "...",
"duration_sec": 360,
"triggered_by": "dashboard"
}
七、Phase 4: 生态层 — 系统完备 (≈ 5h)
4.1 WPRA 写入规范落地 (≈ 2h)
参考 dashboard-v4-design.md 中的 cross_machine 数据规范:
# 每个插件写数据时遵循
CROSS_MACHINE / "data" / {plugin} / {uid}.json
# 内容包含
{"plugin": "...", "version": "...", "machine_uid": "...",
"hostname": "...", "timestamp": "...", "data": {...}}
文件:
plugins/base.py— 更新write_shared_data()plugins/matrix.py— 改写为文件级写入plugins/guardd.py— 改写为文件级写入
4.2 guardd 模块补全 (≈ 2h)
参考 federated-multi-machine-architecture.md:
| 模块 | 状态 | 任务 |
|---|---|---|
heartbeat |
✅ 已实现 | — |
task_worker |
⏳ 部分 | 扫描 cross_machine/tasks/ 执行 |
upgrade_checker |
❌ 缺失 | 版本比对+自动拉取 |
memory_triage |
❌ 缺失 | 记忆过滤→提交箱 |
knowledge_sync |
❌ 缺失 | 知识库变更通知 |
encrypted_channel |
❌ 缺失 | RSA 加密通信 |
cleanup |
❌ 缺失 | 清理30天以上旧数据 |
operation_queue |
❌ 缺失 | Phase 3 新建 |
resource_lock |
❌ 缺失 | Phase 3 新建 |
preflight |
❌ 缺失 | Phase 3 新建 |
4.3 9 插件体系完善 (≈ 1h)
检查现有插件 vs 设计:
| 插件 | dashboard-v4 设计 | 现状 |
|---|---|---|
| guardd | 🖥 联邦机器 | ✅ 已实现 |
| matrix | 📱 矩阵养号 | ✅ 已实现 |
| ave | 🎬 视频工厂 | ✅ 已实现 |
| collector | 📡 内容采集 | ⏳ crawl.py 新建 |
| skills | 🧩 技能树 | ❌ 缺失 |
| knowledge | 📚 知识库 | ✅ kb_api.py |
| automation | ⏰ 自动任务 | ⏳ scheduler.py 新建 |
| tools | 🔧 工具集 | ❌ 缺失 |
| system | ⚙️ 系统核心 | ⏳ system_plugins.py |
八、实施顺序总结
Week 1 (3天) Phase 1: 感知层
├── 1.1 机器状态条 ≈ 1h
├── 1.2 账号忙碌状态 ≈ 1h
└── 1.3 前端路径修复 ≈ 20min
Week 2 (3天) Phase 2: 路由层
├── 2.1 操作路由 ≈ 2h
├── 2.2 远程执行通道 ≈ 2h
├── 2.3 前端模块化 ≈ 30min
└── 2.4 按钮状态智能化 ≈ 30min
Week 3 (3天) Phase 3: 引擎层
├── 3.1 操作队列 ≈ 3h
├── 3.2 资源锁 ≈ 2h
├── 3.3 状态归零 ≈ 1h
└── 3.4 日志聚合 ≈ 1h
Week 4 (2天) Phase 4: 生态层
├── 4.1 WPRA 写入规范 ≈ 2h
├── 4.2 guardd 模块 ≈ 2h
└── 4.3 9插件体系 ≈ 1h
Phase 0 (已做) ✅ 6项审计修复完成
Phase 0 (待做) ❌ 0.6 前端路径错配 ≈ 20min
❌ 0.7 语料库API ≈ 30min
九、风险与缓解
| 风险 | 概率 | 影响 | 缓解 |
|---|---|---|---|
| SSH 远程执行权限不足 | 中 | 高 | 先实现本地操作,远程执行作为可选升级 |
| 资源锁导致操作阻塞 | 低 | 中 | 锁设 TTL,管理员可强制释放 |
| guardd 模块太多难维护 | 中 | 中 | 模块化设计,每个模块独立文件,可单独启用/禁用 |
| 前端模块化导致加载顺序问题 | 低 | 高 | 使用串行加载器,明确依赖顺序 |
| 文件级 WPRA 写入增加 Git 冲突 | 低 | 中 | 按 machine_uid 隔离文件,不会冲突 |
十、验收标准
Phase 1 完成标志
- 每个视图顶部显示三台机器状态条
- 账号卡片显示忙碌状态
- 前端所有 fetch 路径正确,无 404
Phase 2 完成标志
- 远程账号按钮自动路由到对应机器
- 离线机器操作按钮灰掉并提示
- 可通过 Dashboard 远程登录/养号/采集
Phase 3 完成标志
- 每个操作有完整生命周期追踪
- 资源冲突时正确拒绝或排队
- 操作前自动清理残留进程
- 操作日志可查看、可过滤
Phase 4 完成标志
- 所有插件按 WPRA 规范写入
- guardd 10 模块正常运行
- 9 插件体系完整