Files
JARVIS/development-doc/plan/agent-update/phase-10-advanced-orchestration.md
WIN-JHFT4D3SIVT\caoxiaozhu a3fe4d24fc feat(agents): Phase 7-10 hook system, plugins, skills, orchestration
Phase 7: Built-in Hooks (audit_log, dangerous_confirmation, security_scan)
Phase 8: Plugin system (PluginManager, PluginSandbox, PluginManifest)
Phase 9: Skills registry (SkillRegistry, local/plugin/MCP loaders)
Phase 10: TeamLeader, RemoteTransport, BackgroundTaskManager
2026-04-04 22:56:27 +08:00

17 KiB
Raw Blame History

Phase 10高级编排Advanced Orchestration

日期2026-04-04 状态:待开始 前置依赖Phase 6-9工具系统、Hook、插件、Skills Demo参考claw-code-main — assistant/, cli/, structuredIO.ts, remoteIO.ts


1. 阶段目标

实现高级 Agent 编排能力,包括:

  • Team 多 Agent 协作
  • 远程/结构化传输
  • 高级会话管理
  • 后台任务系统

这是 claw-code 与 Jarvis 架构差距最大的地方,也是最复杂的功能。


2. Team 多 Agent 协作

2.1 TeamLeader

# backend/app/agents/team/leader.py

@dataclass
class TeamMember:
    """团队成员"""
    agent_id: str
    role: str
    capabilities: list[str]
    status: AgentStatus
    current_task: str | None = None

@dataclass
class TeamTask:
    """团队任务"""
    task_id: str
    description: str
    parent_id: str | None = None
    assignee: str | None = None
    status: TaskStatus
    dependencies: list[str] = field(default_factory=list)
    result: Any = None

class TeamLeader:
    """
    团队领导者
    
    负责协调多个 Agent 的协作
    """
    
    def __init__(
        self,
        team_id: str,
        tool_registry: ToolRegistry,
        hook_manager: HookManager
    ):
        self.team_id = team_id
        self.tool_registry = tool_registry
        self.hook_manager = hook_manager
        
        self.members: dict[str, TeamMember] = {}
        self.tasks: dict[str, TeamTask] = {}
        self.task_queue: asyncio.Queue = asyncio.Queue()
    
    async def create_team(
        self,
        config: TeamConfig
    ) -> str:
        """创建团队"""
        self.team_id = config.team_id
        
        # 创建团队成员
        for member_config in config.members:
            member = TeamMember(
                agent_id=member_config.agent_id,
                role=member_config.role,
                capabilities=member_config.capabilities,
                status=AgentStatus.IDLE
            )
            self.members[member.agent_id] = member
        
        return self.team_id
    
    async def assign_task(
        self,
        task: TeamTask
    ) -> str:
        """分配任务"""
        self.tasks[task.task_id] = task
        
        # 找到最合适的成员
        assignee = await self._find_assignee(task)
        
        if assignee:
            task.assignee = assignee.agent_id
            assignee.current_task = task.task_id
            assignee.status = AgentStatus.WORKING
        
        return task.task_id
    
    async def _find_assignee(
        self,
        task: TeamTask
    ) -> TeamMember | None:
        """找到最适合执行任务的成员"""
        # 过滤掉忙碌的成员
        available = [
            m for m in self.members.values()
            if m.status == AgentStatus.IDLE
        ]
        
        if not available:
            return None
        
        # 按能力匹配
        for cap in task.required_capabilities:
            matches = [m for m in available if cap in m.capabilities]
            if matches:
                return matches[0]
        
        return available[0] if available else None
    
    async def broadcast_task(
        self,
        description: str,
        required_capabilities: list[str]
    ) -> list[str]:
        """广播任务给所有符合条件的成员"""
        task_ids = []
        
        for member in self.members.values():
            if member.status != AgentStatus.IDLE:
                continue
            
            # 检查能力匹配
            if not any(cap in member.capabilities for cap in required_capabilities):
                continue
            
            # 创建任务
            task = TeamTask(
                task_id=generate_id(),
                description=description,
                assignee=member.agent_id,
                status=TaskStatus.PENDING
            )
            
            await self.assign_task(task)
            task_ids.append(task.task_id)
        
        return task_ids
    
    async def collect_results(
        self,
        task_ids: list[str],
        timeout: float = 300
    ) -> dict[str, Any]:
        """收集任务结果"""
        results = {}
        start_time = time.time()
        
        while len(results) < len(task_ids):
            if time.time() - start_time > timeout:
                break
            
            for task_id in task_ids:
                if task_id in results:
                    continue
                
                task = self.tasks.get(task_id)
                if task and task.status == TaskStatus.COMPLETED:
                    results[task_id] = task.result
            
            await asyncio.sleep(0.1)
        
        return results
    
    async def get_team_status(self) -> TeamStatus:
        """获取团队状态"""
        return TeamStatus(
            team_id=self.team_id,
            members={
                agent_id: {
                    "role": m.role,
                    "status": m.status.value,
                    "current_task": m.current_task
                }
                for agent_id, m in self.members.items()
            },
            active_tasks=sum(1 for t in self.tasks.values() if t.status == TaskStatus.PENDING),
            completed_tasks=sum(1 for t in self.tasks.values() if t.status == TaskStatus.COMPLETED)
        )

3. 远程传输层

3.1 StructuredIO

# backend/app/agents/transport/structured_io.py

class StructuredIO:
    """
    结构化 IO
    
    支持结构化的输入输出格式
    """
    
    async def send_response(
        self,
        channel: str,
        data: dict
    ):
        """发送结构化响应"""
        message = {
            "channel": channel,
            "type": "structured",
            "data": data,
            "timestamp": datetime.now().isoformat()
        }
        await self.transport.send(message)
    
    async def send_event(
        self,
        event_type: str,
        payload: dict
    ):
        """发送事件"""
        message = {
            "type": "event",
            "event": event_type,
            "payload": payload,
            "timestamp": datetime.now().isoformat()
        }
        await self.transport.send(message)
    
    async def send_tool_call(
        self,
        tool_name: str,
        arguments: dict,
        call_id: str
    ):
        """发送工具调用"""
        message = {
            "type": "tool_call",
            "tool": tool_name,
            "args": arguments,
            "call_id": call_id,
            "timestamp": datetime.now().isoformat()
        }
        await self.transport.send(message)
    
    async def receive(self) -> dict:
        """接收消息"""
        raw = await self.transport.receive()
        return self._parse(raw)
    
    def _parse(self, raw: bytes) -> dict:
        """解析消息"""
        # 支持 JSON 和流式格式
        pass

3.2 RemoteTransport

# backend/app/agents/transport/remote.py

class RemoteTransport:
    """
    远程传输
    
    支持远程 Agent 通信
    """
    
    def __init__(
        self,
        endpoint: str,
        auth_token: str
    ):
        self.endpoint = endpoint
        self.auth_token = auth_token
        self.websocket: WebSocket | None = None
    
    async def connect(self):
        """建立连接"""
        self.websocket = await websockets.connect(
            self.endpoint,
            extra_headers={"Authorization": f"Bearer {self.auth_token}"}
        )
    
    async def send(self, message: dict):
        """发送消息"""
        if not self.websocket:
            await self.connect()
        
        await self.websocket.send(json.dumps(message))
    
    async def receive(self) -> dict:
        """接收消息"""
        if not self.websocket:
            await self.connect()
        
        raw = await self.websocket.recv()
        return json.loads(raw)
    
    async def close(self):
        """关闭连接"""
        if self.websocket:
            await self.websocket.close()

4. 高级会话管理

4.1 AgentSession

# backend/app/agents/session/manager.py

@dataclass
class SessionConfig:
    """会话配置"""
    session_id: str
    user_id: str
    parent_session_id: str | None = None
    
    max_rounds: int = 50
    max_tokens: int = 100000
    timeout: float = 3600
    
    isolation_mode: IsolationMode = IsolationMode.NONE
    
    capabilities: list[str] = field(default_factory=list)
    permissions: list[str] = field(default_factory=list)

class AgentSession:
    """
    Agent 会话
    
    管理会话的生命周期和状态
    """
    
    def __init__(
        self,
        config: SessionConfig,
        agent_runtime: AgentRuntime
    ):
        self.config = config
        self.agent_runtime = agent_runtime
        
        self.state: SessionState = SessionState.INITIALIZING
        self.round_count: int = 0
        self.token_count: int = 0
        
        self.messages: list[Message] = []
        self.tool_calls: list[ToolCall] = []
        self.events: list[SessionEvent] = []
    
    async def initialize(self) -> str:
        """初始化会话"""
        # 创建会话记录
        await self._create_session_record()
        
        # 初始化隔离环境
        if self.config.isolation_mode != IsolationMode.NONE:
            await self._initialize_isolation()
        
        self.state = SessionState.ACTIVE
        return self.config.session_id
    
    async def process_message(
        self,
        message: str
    ) -> Response:
        """处理消息"""
        if self.state != SessionState.ACTIVE:
            raise SessionStateError(f"Session not active: {self.state}")
        
        # 检查轮次限制
        self.round_count += 1
        if self.round_count > self.config.max_rounds:
            raise SessionLimitError("Max rounds exceeded")
        
        # 处理消息
        response = await self.agent_runtime.process(
            message,
            context=self._get_context()
        )
        
        # 记录
        self.messages.append(Message(role="user", content=message))
        self.messages.append(Message(role="assistant", content=response.content))
        
        # 更新 token 计数
        self.token_count += response.usage.total_tokens
        
        return response
    
    async def spawn_child_session(
        self,
        config: SessionConfig
    ) -> "AgentSession":
        """创建子会话"""
        child_config = SessionConfig(
            **{
                **asdict(config),
                "parent_session_id": self.config.session_id
            }
        )
        
        child_session = AgentSession(
            config=child_config,
            agent_runtime=self.agent_runtime
        )
        
        await child_session.initialize()
        
        return child_session
    
    async def get_session_summary(self) -> SessionSummary:
        """获取会话摘要"""
        return SessionSummary(
            session_id=self.config.session_id,
            user_id=self.config.user_id,
            round_count=self.round_count,
            token_count=self.token_count,
            message_count=len(self.messages),
            tool_call_count=len(self.tool_calls),
            duration_seconds=(datetime.now() - self.start_time).total_seconds(),
            state=self.state.value
        )
    
    async def persist(self):
        """持久化会话"""
        await self.session_service.save(SessionRecord(
            session_id=self.config.session_id,
            user_id=self.config.user_id,
            state=self.state.value,
            round_count=self.round_count,
            token_count=self.token_count,
            messages=self.messages,
            tool_calls=self.tool_calls,
            events=self.events
        ))

5. 后台任务系统

5.1 BackgroundTaskManager

# backend/app/agents/background/manager.py

@dataclass
class BackgroundTask:
    """后台任务"""
    task_id: str
    description: str
    agent_config: dict
    schedule: str | None = None  # cron expression
    
    status: BackgroundTaskStatus
    created_at: datetime
    started_at: datetime | None = None
    completed_at: datetime | None = None
    
    result: Any = None
    error: str | None = None

class BackgroundTaskManager:
    """
    后台任务管理器
    
    管理长期运行的 Agent 任务
    """
    
    def __init__(
        self,
        task_store: TaskStore,
        agent_factory: AgentFactory
    ):
        self.task_store = task_store
        self.agent_factory = agent_factory
        
        self._running_tasks: dict[str, asyncio.Task] = {}
        self._scheduler = AsyncIOScheduler()
    
    async def submit_task(
        self,
        task: BackgroundTask
    ) -> str:
        """提交后台任务"""
        # 保存任务记录
        await self.task_store.save(task)
        
        # 如果有定时计划,调度任务
        if task.schedule:
            self._scheduler.add_job(
                self._execute_task,
                CronTrigger.from_crontab(task.schedule),
                args=[task.task_id]
            )
        else:
            # 立即执行
            asyncio.create_task(self._execute_task(task.task_id))
        
        return task.task_id
    
    async def _execute_task(self, task_id: str):
        """执行任务"""
        task = await self.task_store.get(task_id)
        if not task:
            return
        
        self._running_tasks[task_id] = asyncio.current_task()
        
        task.status = BackgroundTaskStatus.RUNNING
        task.started_at = datetime.now()
        await self.task_store.save(task)
        
        try:
            # 创建 Agent
            agent = await self.agent_factory.create(task.agent_config)
            
            # 执行
            result = await agent.run()
            
            task.status = BackgroundTaskStatus.COMPLETED
            task.result = result
            
        except Exception as e:
            task.status = BackgroundTaskStatus.FAILED
            task.error = str(e)
        
        finally:
            task.completed_at = datetime.now()
            await self.task_store.save(task)
            
            if task_id in self._running_tasks:
                del self._running_tasks[task_id]
    
    async def cancel_task(self, task_id: str) -> bool:
        """取消任务"""
        if task_id in self._running_tasks:
            self._running_tasks[task_id].cancel()
            del self._running_tasks[task_id]
        
        task = await self.task_store.get(task_id)
        if task:
            task.status = BackgroundTaskStatus.CANCELLED
            await self.task_store.save(task)
        
        return True
    
    async def get_task_status(self, task_id: str) -> BackgroundTask | None:
        """获取任务状态"""
        return await self.task_store.get(task_id)
    
    async def list_tasks(
        self,
        user_id: str,
        status: BackgroundTaskStatus | None = None
    ) -> list[BackgroundTask]:
        """列出任务"""
        return await self.task_store.list(user_id, status)

6. 文件结构

backend/app/agents/
├── team/                  # Team 协作
│   ├── __init__.py
│   ├── leader.py          # 团队领导
│   ├── member.py         # 团队成员
│   └── task.py            # 团队任务
│
├── transport/             # 传输层
│   ├── __init__.py
│   ├── structured_io.py  # 结构化 IO
│   ├── remote.py         # 远程传输
│   └── websocket.py      # WebSocket 传输
│
├── session/              # 会话管理
│   ├── __init__.py
│   ├── manager.py        # 会话管理器
│   ├── context.py        # 会话上下文
│   └── persistence.py    # 会话持久化
│
├── background/          # 后台任务
│   ├── __init__.py
│   ├── manager.py       # 后台任务管理器
│   ├── scheduler.py     # 任务调度
│   └── executor.py      # 任务执行器
│
└── coordinator.py       # 协调整合(现有)

7. 验收标准

检查点 标准
Team 创建 可以创建和管理 Agent 团队
Team 任务分配 任务能正确分配给合适的成员
Team 结果收集 能收集和聚合多成员的结果
结构化 IO 支持结构化的输入输出格式
远程传输 支持远程 Agent 通信
会话管理 支持复杂的会话层级和状态管理
后台任务 支持定时和异步后台任务
子会话 支持从父会话创建子会话

8. Demo 借鉴

claw-code Jarvis 对应
src/assistant/sessionHistory.ts session/manager.py
src/cli/structuredIO.ts transport/structured_io.py
src/cli/remoteIO.ts transport/remote.py
src/cli/transports/* transport/
Team/* tools team/leader.py
Background tasks background/manager.py