Files
Agentswarm/orchestrator/master_agent.py
T
Songhaoz666andClaude Opus 4.8 54cb327348 Agent Swarm v6:基准 v2.1、主控 Agent、实质性对等回复、客户端指南
- 基准标准 v2.1:SwarmMetrics(15 字段)、τ/η/P_decision/reward 公式、对称 G_E,c(修正 C_base=1.0 退化)、Σλ=1.0 校验;新增基线对比与运行记录 schema;指标覆盖缺口分析;参考系数暂留为元数据(待量化)。
- 主控 Agent 实体(分解 / 评审决策 / 汇总);事件契约修正(timeline.title、budget.threshold_pct、handoff 角色、task.released)+ 契约校验脚本。
- 实质性 LLM 对等回复(含降级回退);集成契约(runtime / event / usage / audit / frontend / capability / security);CLIENT_GUIDE 客户端指南;CI 工作流;治理与交付文档。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 16:21:18 +08:00

70 lines
3.0 KiB
Python

"""Master Agent — the decision-making entity of a swarm run.
This makes the "master" a first-class entity rather than scattered orchestrator functions.
The master agent owns the *cognitive* loop:
- plan() : decompose the objective into specialist subtasks
- review_and_decide(): judge whether the combined result is good enough, and which tasks to redo
- synthesize() : compose the specialists' outputs into one user-facing answer
It uses an LLM as its brain (via `planner`, with deterministic fallbacks). The orchestrator
remains the "hands": it executes the master's decisions (dispatch, reopen tasks, persist state,
emit events). This separation keeps decisions in one named entity while leaving runtime
mechanics (and the Manager contract) in the orchestrator.
NOTE: agent→task dispatch is still capability-matched in the orchestrator loop; `select_agent`
below is the seam where the master can later own assignment (LLM-driven), without changing the
loop's contract today.
"""
from __future__ import annotations
import logging
from typing import Any, Dict, List, Optional
from .planner import planner
logger = logging.getLogger(__name__)
class MasterAgent:
"""The master agent: decompose → decide → synthesize for a swarm run."""
def __init__(self, brain=planner):
# `brain` is the LLM-backed planner (build_plan / review / synthesize), swappable for tests.
self.brain = brain
async def plan(self, run_id: str, objective: str) -> List[Dict[str, Any]]:
"""Decompose the user objective into specialist subtasks."""
subtasks = await self.brain.build_plan(run_id, objective)
logger.info(f"[master] planned {len(subtasks)} subtask(s) for run {run_id}")
return subtasks
async def review_and_decide(self, objective: str, tasks: List[Dict[str, Any]],
results: Dict[str, Any]) -> Dict[str, Any]:
"""Decide whether the combined result is good enough.
Returns the master's verdict: {accepted: bool, summary: str, retry_tasks: [task_id,...]}.
The orchestrator acts on it (reopen retry_tasks or finalize).
"""
verdict = await self.brain.review(objective, tasks, results)
logger.info(
f"[master] review decision: accepted={verdict.get('accepted')} "
f"retry={verdict.get('retry_tasks')}"
)
return verdict
async def synthesize(self, objective: str, results: Dict[str, Any]) -> str:
"""Compose the specialists' outputs into one user-facing answer."""
return await self.brain.synthesize(objective, results)
def select_agent(self, task, candidates: List[Any]) -> Optional[Any]:
"""Choose which agent runs a task. Seam for future LLM-driven assignment.
Default: first capability-eligible candidate (capability matching is enforced upstream
by task_queue.get_ready_pending_task), preserving current dispatch behavior.
"""
return candidates[0] if candidates else None
# Singleton master agent for the runtime.
master_agent = MasterAgent()