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 带网关原话 / 正常返回)。
This commit is contained in:
+324
@@ -0,0 +1,324 @@
|
||||
---
|
||||
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 无网络时也能用 |
|
||||
Reference in New Issue
Block a user