Files
makemd/docs/04_Plugin/01_NodeAgent_Design.md
wurenzhi 15ee1758f5 refactor: 重构项目结构并优化类型定义
- 移除extension模块,将功能迁移至node-agent
- 修复类型导出问题,使用export type明确类型导出
- 统一数据库连接方式,从直接导入改为使用config/database
- 更新文档中的项目结构描述
- 添加多个服务的实用方法,如getForecast、getBalances等
- 修复类型错误和TS1205警告
- 优化RedisService调用方式
- 添加新的实体类型定义
- 更新审计日志格式,统一字段命名
2026-03-21 15:04:06 +08:00

7.4 KiB

Node Agent 设计文档

定位: Win Node Agent - 无 API 平台执行代理
更新日期: 2026-03-20
最高优先级参考: Business_ClosedLoops.md


1. 概述

1.1 背景

Extension (浏览器插件) 方案存在以下局限性:

  • Manifest V3 权限限制
  • 反检测能力不足
  • 无法多实例并发
  • 任务调度不可靠

Node Agent 基于 Playwright 构建,提供更强大的自动化能力。

1.2 核心能力

能力 说明
无 API 平台采集 TikTok Shop, Temu, 1688 等
自动化操作 刊登、订单处理、广告投放
反检测 指纹隔离、代理 IP、浏览器上下文隔离
多实例并发 支持多店铺同时运行

2. 技术栈

层级 技术 版本 用途
Runtime Node.js 18+ 运行环境
Automation Playwright 1.58+ 浏览器自动化
Language TypeScript 5.x 开发语言
Communication Axios - HTTP 通信

3. 架构设计

3.1 系统架构

┌─────────────────────────────────────────────────────────────┐
│                        Crawlful Hub                         │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐ │
│  │   Server     │     │     Hub      │     │  Dashboard   │ │
│  │  (业务逻辑)   │◄───►│  (任务调度)   │◄───►│   (控制台)    │ │
│  └──────────────┘     └──────┬───────┘     └──────────────┘ │
│                              │                              │
│                              ▼                              │
│                    ┌──────────────────┐                     │
│                    │   Node Agent     │                     │
│                    │   (Playwright)   │                     │
│                    └────────┬─────────┘                     │
│                             │                               │
│         ┌───────────────────┼───────────────────┐          │
│         ▼                   ▼                   ▼          │
│  ┌──────────────┐   ┌──────────────┐   ┌──────────────┐   │
│  │  Browser #1  │   │  Browser #2  │   │  Browser #N  │   │
│  │  (店铺A)      │   │  (店铺B)      │   │  (店铺N)      │   │
│  └──────────────┘   └──────────────┘   └──────────────┘   │
│                                                              │
└─────────────────────────────────────────────────────────────┘

3.2 核心类设计

export class NodeAgent {
  private hubUrl: string;
  private nodeId: string;
  private heartbeatInterval: number = 30000;
  private pollInterval: number = 10000;

  async start(): Promise<void>;
  async register(): Promise<void>;
  async heartbeat(): Promise<void>;
  async pollTasks(): Promise<void>;
  async executeTask(task: NodeTask): Promise<void>;
  async reportReceipt(receipt: any): Promise<void>;
}

3.3 任务类型

export enum TaskType {
  COLLECT_PRODUCT = 'COLLECT_PRODUCT',
  COLLECT_ORDER = 'COLLECT_ORDER',
  PUBLISH_PRODUCT = 'PUBLISH_PRODUCT',
  PROCESS_ORDER = 'PROCESS_ORDER',
  SYNC_INVENTORY = 'SYNC_INVENTORY',
  MANAGE_AD = 'MANAGE_AD',
}

4. 核心功能

4.1 节点注册

private async register() {
  await axios.post(`${this.hubUrl}/api/v1/nodes/register`, {
    nodeId: this.nodeId,
    version: '1.0.0',
    os: os.type(),
    hostname: os.hostname(),
    shops: []
  });
}

4.2 任务轮询

private async pollTasks() {
  const response = await axios.get(
    `${this.hubUrl}/api/v1/nodes/pull-task?nodeId=${this.nodeId}`
  );
  
  if (response.data?.task) {
    await this.executeTask(response.data.task);
  }
}

4.3 任务执行

private async executeTask(task: NodeTask) {
  try {
    const browser = await chromium.launch({
      headless: false,
      proxy: { server: task.proxyUrl }
    });
    
    const context = await browser.newContext({
      viewport: { width: 1920, height: 1080 }
    });
    
    const page = await context.newPage();
    
    // 执行具体任务...
    
    await browser.close();
    
    await this.reportReceipt({
      taskId: task.id,
      traceId: task.traceId,
      status: 'success',
      resultData: {}
    });
  } catch (err) {
    await this.reportReceipt({
      taskId: task.id,
      traceId: task.traceId,
      status: 'failed',
      errorMessage: err.message
    });
  }
}

5. 店铺隔离策略

5.1 一店一上下文

interface ShopContext {
  shopId: string;
  profileDir: string;
  proxy: ProxyConfig;
  fingerprintPolicy: FingerprintConfig;
}

5.2 同店任务串行

class TaskQueue {
  private queues: Map<string, TaskQueue> = new Map();
  
  async addTask(shopId: string, task: Task) {
    if (!this.queues.has(shopId)) {
      this.queues.set(shopId, new TaskQueue());
    }
    await this.queues.get(shopId).add(task);
  }
}

6. 反检测策略

策略 说明
指纹隔离 每个店铺独立浏览器指纹
代理 IP 每个店铺独立代理
行为模拟 随机延迟、鼠标轨迹
User-Agent 随机 UA 轮换

7. 目录结构

node-agent/
├── src/
│   ├── main.ts              # 入口
│   ├── index.ts             # NodeAgent 类
│   ├── tasks/               # 任务处理器
│   │   ├── collectProduct.ts
│   │   ├── publishProduct.ts
│   │   └── processOrder.ts
│   ├── platforms/           # 平台适配器
│   │   ├── tiktok.ts
│   │   ├── temu.ts
│   │   └── ali1688.ts
│   └── utils/               # 工具函数
│       ├── logger.ts
│       └── fingerprint.ts
├── package.json
└── tsconfig.json

8. 配置

interface AgentConfig {
  hubUrl: string;
  nodeId: string;
  heartbeatInterval: number;
  pollInterval: number;
  maxConcurrentBrowsers: number;
  proxyPool: ProxyConfig[];
}

9. 相关文档


本文档基于业务闭环设计,最后更新: 2026-03-20