Skip to content

RFC: Meta Agent Orchestration #391

@Fodesu

Description

@Fodesu

背景

Memoh 是一个多用户 AI Agent 平台——用户创建 Bot,Bot 通过进程内 Agent Runtime + workspace/container 能力处理来自 Telegram、Slack 等聊天平台的请求。每个 Bot 拥有持久化的文件系统、记忆、技能和身份。

当前架构更准确地说是 一个进程内 Agent Runtime + 多个 Session 上下文 + 一个 Bot Workspace 容器。Bot 可以通过 spawn 并行创建 subagent session,但这些 subagent 复用同一个 Agent Runtime,默认也复用同一个 Bot 的 workspace container。它们是 session 级并行,不是独立的 worker runtime。

这在处理简单请求时足够。但有一类任务正在变得越来越重要:

  • Deep Research:需要多轮搜索 → 阅读 → 综合 → 验证,单次 LLM 循环放不下
  • 复杂代码生成:需要规划 → 编码 → 测试 → 修复的迭代,且不同步骤需要不同工具环境
  • 设备操控(Autofish):需要长时间运行、观察-行动-验证的循环,中间可能需要人类介入
  • 多步骤自动化:跨系统操作(查数据 → 生成报告 → 发邮件),每步有外部副作用

这类任务的共同特征是:需要任务级分解、隔离执行环境、结构化协作、持续验证和可恢复的控制流。 当前的 spawn 模型无法满足——它没有任务图、没有独立 worker 生命周期、没有共享状态层、没有验证环节。现有实现已具备 watchdog、超时和重试等单子任务保护,但还没有任务级的错误恢复、重规划和编排控制。

Memoh 已有 Agent Runtime、Tool Loop 和 workspace/container 基础设施。缺的是面向复杂任务的编排层:任务模型、worker 模型、调度器、共享状态和事件流。


目标

核心目标

在 Memoh 现有 User Bot 架构之外,引入一个 task-oriented orchestration subsystem,将复杂任务动态分解为 DAG,调度多个 task-scoped worker 在隔离环境中执行,并在执行过程中持续验证和自适应调整。

具体而言:

  1. 动态编排:Orchestrator 接收 prompt,通过迭代式规划(Plan → Execute → Observe → Re-plan)将任务分解为 DAG,根据任务特征标签选择编排模式,根据执行反馈动态调整计划。
  2. 独立 Worker Runtime:每个 Worker 是 task-scoped 的运行单元,拥有自己的 task context、生命周期和事件流;执行环境可绑定独立容器、sandbox 或设备能力。
  3. 结构化协作:通过 NATS 消息总线 + 分层 Blackboard(NATS KV Store)实现通信和状态共享,Worker 只读前驱和全局上下文、只写自己的结果。

约束

  • 作为 tool 暴露:编排能力以异步 tool 调用的形式提供给 User Bot,不改变现有 Bot 的交互模型
  • Worker 与 User Bot 分离:被编排的 Worker 是面向任务的运行单元,不承载面向用户的功能(身份、聊天平台接入、用户侧记忆与社交动作);User Bot 不参与调度
  • Human-in-the-Loop:编排任务可在关键决策点暂停等待用户输入,支持超时默认策略和状态快照
  • 可恢复的错误处理:Worker 自分类错误(retryable / env_mismatch / fatal),指数退避重试,不可恢复的失败可控传播到上层

非目标

  • 通用的 multi-agent framework
  • 跨用户的 agent 协作
  • agent 自主发现和自注册

方案

总体架构

graph TB
    subgraph 用户侧
        U[用户] -->|聊天/命令| UB[User Bot]
    end

    subgraph Server 侧
        UB -->|消息流| AR[Agent Runtime]
        AR -->|orchestrate tool 调用| OE[Orchestrator Engine]
        OE -->|管理| NATS[NATS 消息总线]
        OE -->|读写| BB[Blackboard]
        OE -->|创建/销毁| DK[Worker Runtime Manager]
        NATS --- BB
    end

    subgraph Worker Runtime / 执行环境
        DK -->|分配任务 + 绑定 env| W1[Worker: Researcher]
        DK -->|分配任务 + 绑定 env| W2[Worker: Coder]
        DK -->|分配任务 + 绑定 env| W3[Worker: Verifier]
        DK -->|分配任务 + 绑定 env| W4[Worker: Phone Operator]
    end

    W1 -->|pub/sub| NATS
    W2 -->|pub/sub| NATS
    W3 -->|pub/sub| NATS
    W4 -->|pub/sub| NATS
    OE -->|结果回传| UB
Loading

编排以 异步 tool 暴露给 User Bot。User Bot 所在的 Agent Runtime 调用 orchestrate(prompt | status | cancel) 后异步返回 task_id,Orchestrator 在后台完成分解、调度、执行、验证,最终将结果回传。

任务图模型

任务图在任一时刻为 DAG。 逻辑上的迭代(Maker-Checker 循环、Debate 等)通过 Orchestrator Re-plan 动态追加节点实现,图内不存在环。这保证调度只需拓扑排序,无死锁风险。

    A ───→ C ───→ E
   ↗        ↘
Root          → F (join: 依赖 C + D)
   ↘        ↗
    B ───→ D

调度规则:入度为 0 的节点并行执行,完成后减少后继入度,新的入度为 0 的节点继续执行。

分层 Blackboard

每个任务节点拥有独立的 Blackboard(NATS KV bucket bb_{task_id}):

bb_root: goal, constraints, budget, deadline, global_context
bb_a:    sub_goal, status, result, artifacts
bb_b:    sub_goal, status, result, artifacts
bb_c:    sub_goal, status, result (读取 bb_a + bb_b)

访问规则:

角色 可读 可写
Worker X 自己的 bb + 所有前驱 bb + Root bb 只写自己的 bb
Orchestrator 所有 bb 所有 bb
Verifier 被验证节点 bb + 其前驱 bb 验证结果写到被验证节点 bb

任务生命周期

Orchestrator 采用迭代式规划(Plan → Execute → Observe → Re-plan),拆为四个独立模块:

模块 1 — 规划(Planner)

flowchart LR
    A[接收 prompt / 任务节点] --> B[LLM 标注任务特征]
    B --> C{需要分解?}
    C -->|是| D[生成子节点 + 依赖关系 → 构建子 DAG]
    C -->|否| E[标记为叶子节点 → 进入调度]
    D --> E
Loading

输入:一个任务节点。输出:叶子节点(可直接执行)或子 DAG。任何层级的节点都可能触发规划,包括 Worker 运行中 request_decompose。

模块 2 — 调度(Scheduler)

flowchart LR
    A[接收 DAG] --> B[计算各节点入度]
    B --> C[入度=0 的节点 → 并行分发]
    C --> D[匹配 Worker 类型 → 分配 Runtime / Env]
    D --> E[Worker 开始执行]
    E --> F[节点完成 → 后继入度 -1]
    F --> G{新的入度=0 节点?}
    G -->|是| C
    G -->|否 + 仍有运行中| H[等待]
    G -->|否 + 全部完成| I[DAG 完成]
Loading

核心是拓扑排序驱动的事件循环。每个节点完成是一个事件,触发后继的入度更新和可能的新调度。

模块 3 — 执行(Worker)

flowchart LR
    A[Worker 接收任务] --> B[读取 Blackboard: 自己 + 前驱 + Root]
    B --> C[执行]
    C --> D{结果}
    D -->|完成| E[写结果到自己的 Blackboard]
    D -->|需要再分解| F[request_decompose → 回到 Planner]
    D -->|env 不匹配| G[上报 → Orchestrator 换 Worker]
Loading

Worker 是 task-scoped runtime。运行时上下文从任务定义和 Blackboard 读取,所有产出写回 Blackboard,并通过事件流上报状态。

模块 4 — 验证与错误处理(Verifier)

flowchart LR
    A[节点执行完成] --> B{验证方式}
    B -->|叶子节点| C[Verifier Worker 验证]
    B -->|中间节点| D[Orchestrator 聚合子结果验证]
    C & D --> E{通过?}
    E -->|是| F[标记完成 → 通知 Scheduler]
    E -->|否 + 可重试| G[指数退避重试 → 回到 Worker]
    E -->|否 + 需重写| H[Re-plan → 回到 Planner]
    E -->|否 + 不可恢复| I[标记失败 → 所有可达后继标记 blocked]
Loading

失败处理三级:当前节点重试 → 当前节点 Re-plan → 失败传播(标记后继 blocked,由上层决定是否整体 Re-plan)。

模块间关系:

Planner ──生成 DAG──→ Scheduler ──分发──→ Worker
                         ↑                    │
                         │ 完成/失败事件        │ 结果
                         │                    ▼
                      Scheduler ←──验证──  Verifier
                         │
                         ↓ (Re-plan)
                      Planner

任务标签系统

Orchestrator 分解任务后为每个子任务标注特征标签,用于 Worker 匹配和调度策略:

标签 取值 影响
idempotent true/false 是否可安全重试
has_side_effect true/false 是否有外部状态变更
complexity low/medium/high 是否需要进一步分解
latency realtime/async 是否走 warm pool
env web/code/device/... 匹配 Worker capabilities
depends_on [task_ids] 调度依赖
interruptible true/false 是否可暂停等待 HITL

通信:NATS + Blackboard

flowchart LR
    subgraph Orchestrator
        OE[编排引擎]
    end

    subgraph NATS Topics
        T1[task.assign.*]
        T2[task.result.*]
        T3[task.status.*]
        T4[bb.update.*]
        T5[hitl.request/response]
        T6[worker.error.*]
    end

    subgraph Workers
        W1[Worker A]
        W2[Worker B]
        W3[Verifier]
    end

    subgraph Blackboard
        BB[(共享状态)]
    end

    OE -->|分配| T1 --> W1 & W2
    W1 & W2 -->|结果| T2 --> OE
    W1 & W2 -->|状态| T3 --> OE
    W1 & W2 -->|写| T4 --> BB
    BB -->|变更通知| T4 --> W1 & W2
    W1 & W2 -->|错误| T6 --> OE
    OE -->|验证请求| T1 --> W3
    W3 -->|验证结果| T2 --> OE
Loading

Human-in-the-Loop

sequenceDiagram
    participant W as Worker
    participant O as Orchestrator
    participant UB as User Bot
    participant U as 用户

    W->>O: hitl.request (需要人类决策)
    O->>O: 保存轻量快照
    O->>UB: 推送通知
    UB->>U: "任务 X 需要你确认: ..."

    alt 用户在超时前回复
        U->>UB: 回复
        UB->>O: hitl.response
        O->>W: 恢复执行
    else 超时
        O->>O: 执行 on_timeout 策略
        Note over O: conservative: 最安全选项<br/>skip: 跳过子任务<br/>fail: 标记失败
    end
Loading

Metadata

Metadata

Assignees

No one assigned

    Labels

    featNew feature or requestsize-xl

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions