Files
MediaCrawler/mac-agent-os-main/03_knowledge/99_system/architecture/federation-operations-architecture.md
T
butubb 2112c1a870
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
移植自 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 带网关原话 / 正常返回)。
2026-10-10 17:12:25 +08:00

325 lines
15 KiB
Markdown

---
type: concept
domain: system
nature: architecture
tags: [agentos, v3.0, federated, multi-machine, operations, orchestration]
status: draft
created: 2026-06-16
updated: 2026-06-16
version: 1.0.0
supersedes: []
---
# AgentOS 联邦指挥台 — 操作架构设计 v1.0
> 版本: 1.0.0-draft | 2026-06-16
> 设计目标: 创建世界级的多机智能体编排系统,可扩展为大规模计算机军团
---
## 一、设计哲学
### 核心原则
1. **指挥台只负责聚合和分发,不直接执行** — 所有操作在目标机器上运行
2. **每台机器是自治的智能体** — 离线也能独立运行,在线时接受指挥台调度
3. **操作即状态机** — 每个操作都有明确的声明周期,可追踪、可重试、可审计
4. **先检后动** — 操作前检查资源状态,保证不会破坏正在运行的任务
5. **双模交互** — Dashboard(图形)和 CLI(命令行)完全对等,同一套底层
### 参考架构
| 来源 | 借鉴点 |
|:-----|:-------|
| Selenium Grid Hub-Node | 中央调度 + 分布式执行节点 |
| Kubernetes Job/Pod | 声明式任务 + 状态机 + 日志聚合 |
| Apache Airflow DAG | 操作依赖管理 + 重试 + 告警 |
| Erlang/Elixir Actor | 每台机器 = 一个 Actor,通过消息通信 |
| Unix Pipeline | 每个操作 = 一个进程,stdin/stdout/stderr |
---
## 二、系统架构:三层模型
```
┌──────────────────────────────────────────────────────────────────┐
│ Layer 1: Command Center │
│ (Dashboard Web UI + CLI) │
│ │
│ 功能: 聚合展示 + 命令输入 + 日志查看 + 状态监控 │
│ 位置: chengzigedeAir (master) │
│ 也支持: 任何机器浏览器打开看板,或本地 CLI 直接执行 │
└──────────────────────┬───────────────────────────────────────────┘
│ HTTP / WebSocket / SSE
┌──────────────────────┴───────────────────────────────────────────┐
│ Layer 2: Orchestration Bus │
│ │
│ - federation API (REST): /api/federation/* │
│ - event stream (SSE): /api/events │
│ - remote exec (SSH): /api/federation/exec │
│ - log aggregation: 每台机器推送日志到中心存储 │
└──────────────────────┬───────────────────────────────────────────┘
│ SSH / HTTP / Tailscale
┌────────────────┼────────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Machine A │ │ Machine B │ │ Machine C │
│ chengzige │ │ 5kecheng │ │ 7kecheng │
├────────────┤ ├────────────┤ ├────────────┤
│ Layer 3a │ │ Layer 3a │ │ Layer 3a │
│ Agent Daemon│ │ Agent D. │ │ Agent D. │
│ (guardd) │ │ (guardd) │ │ (guardd) │
├────────────┤ ├────────────┤ ├────────────┤
│ Layer 3b │ │ Layer 3b │ │ Layer 3b │
│ Camoufox │ │ Camoufox │ │ Camoufox │
│ Browser │ │ Browser │ │ Browser │
└────────────┘ └────────────┘ └────────────┘
```
### 每台机器上的 Agent Daemon (guardd)
每台机器运行一个常驻后台进程 `guardd`,职责:
| 职责 | 说明 |
|:-----|:-----|
| 心跳上报 | 每 300s 写一次 heartbeat.json,含 CPU/内存/磁盘/任务状态 |
| 操作队列 | 接收指挥台下发的操作,排队执行 |
| 资源锁 | 管理浏览器实例/账号的使用状态,防止冲突 |
| 日志推送 | 操作日志实时推送到中心日志存储 |
| 状态归零 | 操作完成后清理浏览器进程、还原环境 |
---
## 三、操作状态机
### 所有操作的通用生命周期
```
┌──────────┐
│ pending │ ← 用户下发操作,等待调度
└────┬─────┘
↓
┌──────────┐
┌──────→│ checking │ ← 检查目标机器状态、资源可用性
│ └────┬─────┘
│ ↓
│ ┌──────────┐
│ │preparing │ ← 关闭旧浏览器、清理缓存、锁资源
│ └────┬─────┘
│ ↓
│ ┌──────────┐
│ ┌─→│ running │ ← 操作执行中(浏览器打开/脚本运行)
│ │ └────┬─────┘
│ │ ↓
│ │ ┌──────────┐ ┌──────────┐
│ │ │completed │ 或 │ failed │ ← 成功完成或出错
│ │ └────┬─────┘ └────┬─────┘
│ │ ↓ ↓
│ │ ┌──────────┐ ┌──────────┐
│ │ │ cleaning │ │ cleaning │ ← 清理资源、释放锁
│ │ └────┬─────┘ └────┬─────┘
│ │ ↓ ↓
│ │ ┌──────────┐ ┌──────────┐
│ └──│ done │ │ error │
│ └──────────┘ └──────────┘
│
└── 任何阶段都可被"取消"或"超时"
超时后进入 cleaning → error
```
### 状态转换规则
| 转换 | 触发条件 | 动作 |
|:-----|:---------|:-----|
| pending → checking | 调度器获取执行权 | 读取目标机器心跳、检查是否有其他任务在跑 |
| checking → preparing | 资源检查通过 | 发送 prepare 命令到目标机器 |
| checking → pending | 资源忙 | 重新排队,等待重试 |
| checking → failed | 目标机器离线 | 标记失败,通知用户 |
| preparing → running | 准备完成 | 执行具体操作 |
| running → completed | 正常结束 | 收集结果 |
| running → failed | 异常退出 | 收集错误信息 |
| * → cleaning | 任何非 done 状态的完成 | 执行清理脚本 |
| cleaning → done | 清理完成 | 更新最终状态 |
| * → failed | 超时(默认 30min) | 强行终止,清理 |
---
## 四、资源管理
### 资源类型
| 资源 | 粒度 | 冲突规则 |
|:-----|:-----|:---------|
| 浏览器实例 | 每机器 1 个 Camoufox | 全局互斥——同一台机器不能开两个浏览器 |
| 账号登录态 | 每个 account_id | 同一账号不能同时被两个操作使用 |
| 身份指纹 | 每个 identity_dir | 同一身份不能同时被两个浏览器使用 |
| 键盘/鼠标 | 每机器独占 | 远程操作时锁定本地输入(可选) |
### 资源锁实现
```python
# 每台机器上的 guardd 维护的锁表
locks = {
"browser": {"held_by": "task_001", "acquired_at": "2026-06-16T18:00:00"},
"account:douyin_01": {"held_by": "task_001", "acquired_at": "..."},
"identity:douyin_01_camo": {"held_by": "task_001", "acquired_at": "..."},
}
```
### 状态归零 (Pre-flight Reset)
每个操作执行前,目标机器必须执行:
1. **检查是否有残留浏览器进程** — `pkill -f camoufox` (如果有, kill)
2. **检查是否有残留的 Playwright 进程** — `pkill -f playwright`
3. **检查账号登录锁** — 清除该账号的锁
4. **清理临时文件** — 删除上次操作的临时缓存
5. **重置代理状态** — 恢复默认代理配置
6. **确认资源可用** — 返回"已就绪"状态
---
## 五、操作类型全表
| 操作 | 类型 | 机器 | 状态管理 | 并发 | 超时 |
|:-----|:-----|:-----|:---------|:----|:-----|
| 账号登录 | A 本机浏览器 | assigned_machine | 锁 browser + 锁 account | 1 账号/次 | 120s |
| 养号执行 | A 本机浏览器 | assigned_machine | 锁 browser + 锁 identity | 1 身份/次 | 60min |
| 信息采集 | B 远程脚本 | 任意在线机器 | 只读,无需锁 | 并发 | 60s |
| 内容发布 | A 本机浏览器 | assigned_machine | 锁 browser + 锁 account | 1 账号/次 | 300s |
| 环境同步 | B 远程脚本 | 指定机器 | 互斥(同一机器不能同时同步) | 1 台/次 | 120s |
| 对账检查 | B 远程脚本 | 指定机器 | 只读,无需锁 | 并发 | 60s |
| 远程Shell | B 远程脚本 | 指定机器 | 无锁 | 并发 | 30s |
| 状态监控 | C 聚合 | 所有机器 | 只读 | 并发 | 10s |
---
## 六、日志与审计
### 日志结构
每个操作产生一条结构化日志:
```json
{
"operation_id": "op_20260616_001",
"type": "account_login",
"target_machine": "5kechengdeAir",
"target_account": "douyin_01",
"status": "completed",
"states": [
{"state": "pending", "time": "18:00:00"},
{"state": "checking", "time": "18:00:01"},
{"state": "preparing", "time": "18:00:02"},
{"state": "running", "time": "18:00:05"},
{"state": "completed","time": "18:01:15"},
{"state": "cleaning", "time": "18:01:16"},
{"state": "done", "time": "18:01:17"}
],
"output": "login successful, cookie saved",
"error": null,
"triggered_by": "dashboard_user",
"duration_sec": 77
}
```
### 日志聚合
- 每台机器的 guardd 实时推送日志到中心 `/api/logs/push`
- Dashboard 提供日志查看器: 按机器/操作/时间/状态过滤
- 日志保留 30 天,自动归档
---
## 七、并发与互斥策略
| 场景 | 策略 |
|:-----|:-----|
| 用户点「养号」时机器已在养号 | 拒绝,提示"5kecheng 正在养号中,是否停止当前任务?" |
| 用户点「登录」时浏览器已打开 | 先关闭浏览器,再重新打开 |
| 两台机器同时给同一账号发命令 | 不可能——账号只属于一台机器(ORACLE.yaml) |
| 用户从 Dashboard 和 CLI 同时操作 | 共享同一资源锁表,后到者等待或拒绝 |
| 机器离线时下发操作 | 缓存到队列,机器上线后自动执行(可选) |
---
## 八、安全与锁定
### 远程操作时的机器锁定
当通过 Dashboard 远程控制 5kechengdeAir 执行浏览器操作时:
| 安全措施 | 实现 |
|:---------|:-----|
| 键盘锁定 | 操作开始时,5kecheng 本地键盘暂时屏蔽(防止误触) |
| 屏幕提示 | 5kecheng 显示器显示"正在被远程控制"的提示 |
| 强制停止 | 任何时候按 Ctrl+C 或点击「停止」终止操作 |
| 超时自动释放 | 30min 无活动自动关闭浏览器并释放锁 |
### 注意
键盘锁定是进阶功能。初期先实现资源锁+状态机,锁定后续再做。
---
## 九、Dashboard 落地计划
### Phase 1: 状态感知 (优先级最高)
- [x] 三台机器心跳检测 (guardd 已有)
- [ ] 机器状态条: 每个视图顶部显示三台机器在线/离线/忙碌
- [ ] 账号级别的忙碌状态 (是否正在被操作)
### Phase 2: 操作路由 (当前)
- [ ] `accountLogin()` 加 owner_machine 判断 + 远程执行
- [ ] `clearCookies()` 加 owner_machine 判断
- [ ] `deleteAccount()` 加 owner_machine 判断
- [ ] 按钮状态: 远程账号显示"需在 XX 机器操作"或"远程执行"
### Phase 3: 状态机引擎
- [ ] 统一的操作队列: `pending → checking → running → done`
- [ ] 资源锁: 账号级别和浏览器级别
- [ ] 操作前的 state reset (清理旧进程)
- [ ] 操作日志存储 + 查看器
### Phase 4: 高级功能
- [ ] 键盘锁定 / 屏幕提示
- [ ] 离线队列 / 上线自动执行
- [ ] 操作 DAG (先后依赖)
- [ ] 多用户协作
---
## 附录: 参考的原始架构文档
本文设计参考了以下原有系统文档中的思想:
| 文档 | 关键借鉴 |
|:-----|:---------|
| `architecture/federated-multi-machine-architecture.md` | 7大协同子系统(心跳/事件/任务/加密/知识/升级/传输)、guardd 7模块、三层数据架构 |
| `archive/CORE-ARCHITECTURE.md` | 目录职责边界、agent-local/agent-sync 分离原则、软链接映射、技能分类 |
| `dashboard-v4-design.md` | cross_machine/data/ WPRA 写入规范、9个内置插件规范、机器感知设计、24h TTL 过期策略 |
| `COMMAND-CENTER-PLAN.md` (99_system/) | 命名空间分层(agentos matrix/ave/crawl/fleet/serve) |
| `cross_machine/ARCHITECTURE-v2.md` (04_memory/) | WPRA 写分区·读聚合模型、Git 冲突消除方案 |
### 本次设计新增的概念
| 概念 | 来源 | 说明 |
|:-----|:-----|:------|
| 操作状态机 | 新建 | pending→checking→preparing→running→completed→cleaning→done 完整生命周期 |
| 资源锁 | 新建 | 浏览器级/账号级/身份级互斥,防止冲突操作 |
| 状态归零 | 新建 | 操作前自动清理残留进程、释放锁、重置环境 |
| 操作路由 | 新建 | 根据 owner_machine 将操作路由到对应机器执行 |
| 双模对等 | 新建 | Dashboard 和 CLI 共享同一套底层 API |
---
## 十一、关键设计决策记录
| 决策 | 选项 | 选择 | 理由 |
|:-----|:-----|:-----|:------|
| 操作同步还是异步? | 同步等待 / 异步队列 | **混合**: 短操作(<10s)同步,长操作异步 | 登录等短操作需要实时反馈 |
| 远程执行通道 | SSH / HTTP / WebSocket | **SSH** (现有) + **HTTP API** (未来) | SSH 已打通,HTTP 需要额外服务 |
| 状态存储 | Redis / SQLite / 文件 | **文件** (现有 heartbeats/目录) | 零依赖,随 Git 同步 |
| 浏览器管理 | 每机器 1 个 / 多实例 | **1 个 Camoufox,轮流使用** | 指纹一致性,避免被检测 |
| CLI 与 Dashboard 关系 | 主从 / 对等 | **对等**—同一套底层 API | CLI 无网络时也能用 |