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
17 KiB
17 KiB
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 |