|
| 1 | +# `PlannerGeneratorEvaluator` |
| 2 | + |
| 3 | +The `PlannerGeneratorEvaluator` is a domain-agnostic three-agent orchestration harness inspired by the GAN-style architecture described in [Anthropic's harness design research](https://www.anthropic.com/engineering/harness-design-long-running-apps). It coordinates long-running autonomous tasks from a short natural-language prompt, using an iterative generate-evaluate feedback loop to converge on high-quality output across any domain. |
| 4 | + |
| 5 | +All three agents communicate through a single shared file on disk. |
| 6 | + |
| 7 | +```mermaid |
| 8 | +graph TD |
| 9 | + A[User Prompt] --> B[Planner] |
| 10 | + B --> C[Plan + Evaluation Criteria] |
| 11 | + C --> D{For Each Step} |
| 12 | + D --> E[Generator Proposes Contract] |
| 13 | + E --> F[Evaluator Reviews Contract] |
| 14 | + F --> G[Generator Executes Step] |
| 15 | + G --> H[Generator Self-Assessment] |
| 16 | + H --> I[Evaluator Scores Output] |
| 17 | + I --> J{All Criteria Pass?} |
| 18 | + J -->|Yes| D |
| 19 | + J -->|No| K{Retries Left?} |
| 20 | + K -->|Yes + Scores Improving| L[REFINE: Fix Issues] |
| 21 | + K -->|Yes + Scores Declining| M[PIVOT: New Approach] |
| 22 | + L --> G |
| 23 | + M --> G |
| 24 | + K -->|No| D |
| 25 | + D -->|Done| N[Final Output + Shared State File] |
| 26 | +``` |
| 27 | + |
| 28 | +The harness follows this workflow: |
| 29 | + |
| 30 | +1. **Planning**: Planner expands a short prompt into an ambitious plan with steps and evaluation criteria |
| 31 | +2. **Contract Negotiation**: Generator proposes what "done" looks like for each step; Evaluator reviews |
| 32 | +3. **Execution**: Generator produces concrete output and self-assesses before handoff |
| 33 | +4. **Evaluation**: Evaluator scores output per-criterion with hard thresholds — any criterion below its threshold fails the step |
| 34 | +5. **Feedback Loop**: On failure, Generator receives scores + trajectory signal (refine or pivot) and retries |
| 35 | +6. **All state on disk**: The shared state file is the single append-only record of the entire run |
| 36 | + |
| 37 | + |
| 38 | +## Key Features |
| 39 | + |
| 40 | +| Feature | Description | |
| 41 | +|---------|-------------| |
| 42 | +| **GAN-Style Separation** | Distinct Generator and Evaluator agents prevent self-evaluation bias | |
| 43 | +| **Step Contracts** | Generator and Evaluator agree on success criteria before execution | |
| 44 | +| **Hard Threshold Enforcement** | Any single criterion below its threshold fails the step | |
| 45 | +| **Score Trajectory** | Tracks score trends across retries — signals Generator to refine or pivot | |
| 46 | +| **Self-Assessment** | Generator self-evaluates before Evaluator handoff | |
| 47 | +| **Shared State File** | Single append-only `.md` file for all inter-agent communication | |
| 48 | +| **Domain-Agnostic** | Planner defines evaluation criteria tailored to the task domain | |
| 49 | +| **Custom Agents** | Pass pre-configured agents with tools, MCP, or any Agent settings | |
| 50 | +| **Configurable Thresholds** | Default thresholds plus Planner-defined per-criterion thresholds | |
| 51 | + |
| 52 | + |
| 53 | +## Constructor |
| 54 | + |
| 55 | +### `PlannerGeneratorEvaluator.__init__()` |
| 56 | + |
| 57 | +| Parameter | Type | Default | Required | Description | |
| 58 | +|-----------|------|---------|----------|-------------| |
| 59 | +| `model_name` | `str` | `"gpt-4.1"` | No | Model identifier for all three agents | |
| 60 | +| `planner_model_name` | `str` | `None` | No | Override model for the Planner | |
| 61 | +| `generator_model_name` | `str` | `None` | No | Override model for the Generator | |
| 62 | +| `evaluator_model_name` | `str` | `None` | No | Override model for the Evaluator | |
| 63 | +| `max_steps` | `int` | `10` | No | Upper bound on plan steps to execute | |
| 64 | +| `max_retries_per_step` | `int` | `3` | No | Max evaluation failures before advancing | |
| 65 | +| `working_directory` | `str` | `os.getcwd()` | No | Directory where output is produced | |
| 66 | +| `shared_state_path` | `str` | `None` | No | Path for the shared state file (auto-generated if None) | |
| 67 | +| `default_thresholds` | `Dict[str, float]` | `{}` | No | Fallback score thresholds by criterion name | |
| 68 | +| `output_type` | `OutputType` | `"dict"` | No | Format for output (dict, str, list, final, json, yaml) | |
| 69 | +| `verbose` | `bool` | `False` | No | Enable verbose logging | |
| 70 | +| `planner_agent` | `Agent` | `None` | No | Pre-configured Agent for planning | |
| 71 | +| `generator_agent` | `Agent` | `None` | No | Pre-configured Agent for generation (e.g., with file/code tools) | |
| 72 | +| `evaluator_agent` | `Agent` | `None` | No | Pre-configured Agent for evaluation (e.g., with Playwright MCP) | |
| 73 | + |
| 74 | +#### Raises |
| 75 | + |
| 76 | +| Exception | Condition | |
| 77 | +|-----------|-----------| |
| 78 | +| `ValueError` | If `max_steps < 1`, `max_retries_per_step < 0`, or `model_name` is empty | |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +## Core Methods |
| 83 | + |
| 84 | +### `run()` |
| 85 | + |
| 86 | +Execute the full PGE harness pipeline from a short prompt to completed output. |
| 87 | + |
| 88 | +| Parameter | Type | Default | Required | Description | |
| 89 | +|-----------|------|---------|----------|-------------| |
| 90 | +| `task` | `str` | — | **Yes** | A short natural-language description of the desired task | |
| 91 | + |
| 92 | +#### Returns |
| 93 | + |
| 94 | +| Type | Description | |
| 95 | +|------|-------------| |
| 96 | +| `Any` | Formatted conversation history according to `output_type` | |
| 97 | + |
| 98 | +After `run()` completes, access `harness.last_result` for structured metadata: |
| 99 | + |
| 100 | +| Field | Type | Description | |
| 101 | +|-------|------|-------------| |
| 102 | +| `output_path` | `str` | Path to the shared state file | |
| 103 | +| `plan` | `str` | The generated plan text | |
| 104 | +| `step_logs` | `List[Dict]` | Per-step metadata (contract, scores, retries) | |
| 105 | +| `total_duration` | `float` | Wall-clock time in seconds | |
| 106 | +| `total_steps_completed` | `int` | Number of steps that passed evaluation | |
| 107 | +| `total_retries` | `int` | Total retry attempts across all steps | |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +### `batched_run()` |
| 112 | + |
| 113 | +Run the harness on multiple tasks sequentially. |
| 114 | + |
| 115 | +| Parameter | Type | Default | Required | Description | |
| 116 | +|-----------|------|---------|----------|-------------| |
| 117 | +| `tasks` | `List[str]` | — | **Yes** | List of task prompts to process | |
| 118 | + |
| 119 | +#### Returns |
| 120 | + |
| 121 | +| Type | Description | |
| 122 | +|------|-------------| |
| 123 | +| `List[Any]` | List of results, one per task | |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## Usage Examples |
| 128 | + |
| 129 | +### Basic Usage |
| 130 | + |
| 131 | +```python |
| 132 | +from swarms import PlannerGeneratorEvaluator |
| 133 | + |
| 134 | +harness = PlannerGeneratorEvaluator( |
| 135 | + model_name="gpt-4.1", |
| 136 | + max_steps=3, |
| 137 | + max_retries_per_step=2, |
| 138 | + output_type="final", |
| 139 | + verbose=True, |
| 140 | +) |
| 141 | + |
| 142 | +result = harness.run( |
| 143 | + "Write a comprehensive guide on the benefits and risks of intermittent fasting" |
| 144 | +) |
| 145 | + |
| 146 | +print(result) |
| 147 | +print(f"Steps completed: {harness.last_result.total_steps_completed}") |
| 148 | +print(f"Duration: {harness.last_result.total_duration:.1f}s") |
| 149 | +``` |
| 150 | + |
| 151 | +### Custom Agents with Tools |
| 152 | + |
| 153 | +Pass pre-configured agents with tools so the Generator can write files and the Evaluator can verify them on disk: |
| 154 | + |
| 155 | +```python |
| 156 | +from swarms import Agent, PlannerGeneratorEvaluator |
| 157 | + |
| 158 | + |
| 159 | +def write_file(filename: str, content: str) -> str: |
| 160 | + """Write content to a file.""" |
| 161 | + with open(filename, "w") as f: |
| 162 | + f.write(content) |
| 163 | + return f"Written: {filename}" |
| 164 | + |
| 165 | + |
| 166 | +def read_file(filename: str) -> str: |
| 167 | + """Read content from a file.""" |
| 168 | + with open(filename, "r") as f: |
| 169 | + return f.read() |
| 170 | + |
| 171 | + |
| 172 | +generator = Agent( |
| 173 | + agent_name="PGE-Generator", |
| 174 | + model_name="gpt-4.1", |
| 175 | + max_loops=1, |
| 176 | + tools=[write_file], |
| 177 | +) |
| 178 | + |
| 179 | +evaluator = Agent( |
| 180 | + agent_name="PGE-Evaluator", |
| 181 | + model_name="gpt-4.1", |
| 182 | + max_loops=1, |
| 183 | + tools=[read_file], |
| 184 | +) |
| 185 | + |
| 186 | +harness = PlannerGeneratorEvaluator( |
| 187 | + model_name="gpt-4.1", |
| 188 | + generator_agent=generator, |
| 189 | + evaluator_agent=evaluator, |
| 190 | + max_steps=3, |
| 191 | +) |
| 192 | + |
| 193 | +result = harness.run("Create a Python module for string manipulation utilities") |
| 194 | +``` |
| 195 | + |
| 196 | +### Evaluator with Playwright MCP (Web App Testing) |
| 197 | + |
| 198 | +For web application development, give the Evaluator browser automation via Playwright MCP so it can test the running app like a real user: |
| 199 | + |
| 200 | +```python |
| 201 | +from swarms import Agent, PlannerGeneratorEvaluator |
| 202 | + |
| 203 | +evaluator = Agent( |
| 204 | + agent_name="PGE-Evaluator", |
| 205 | + model_name="gpt-4.1", |
| 206 | + max_loops=1, |
| 207 | + mcp_config={"url": "http://localhost:3000/playwright"}, |
| 208 | +) |
| 209 | + |
| 210 | +harness = PlannerGeneratorEvaluator( |
| 211 | + model_name="gpt-4.1", |
| 212 | + evaluator_agent=evaluator, |
| 213 | + max_steps=5, |
| 214 | + max_retries_per_step=3, |
| 215 | +) |
| 216 | + |
| 217 | +result = harness.run("Build a todo app with React frontend and FastAPI backend") |
| 218 | +``` |
| 219 | + |
| 220 | +### Custom Thresholds |
| 221 | + |
| 222 | +Provide default score thresholds that apply when the Planner doesn't define them: |
| 223 | + |
| 224 | +```python |
| 225 | +from swarms import PlannerGeneratorEvaluator |
| 226 | + |
| 227 | +harness = PlannerGeneratorEvaluator( |
| 228 | + model_name="gpt-4.1", |
| 229 | + default_thresholds={ |
| 230 | + "accuracy": 8.0, |
| 231 | + "clarity": 7.0, |
| 232 | + "completeness": 7.0, |
| 233 | + }, |
| 234 | + max_retries_per_step=4, |
| 235 | +) |
| 236 | + |
| 237 | +result = harness.run("Write a technical specification for a rate-limiting middleware") |
| 238 | +``` |
| 239 | + |
| 240 | +--- |
| 241 | + |
| 242 | +## Architecture Details |
| 243 | + |
| 244 | +### Shared State File |
| 245 | + |
| 246 | +All inter-agent communication flows through a single append-only markdown file. Each section is timestamped and labeled: |
| 247 | + |
| 248 | +``` |
| 249 | +# PGE Harness Shared State |
| 250 | +
|
| 251 | +## User Prompt |
| 252 | +[original prompt] |
| 253 | +
|
| 254 | +--- |
| 255 | +### [PLANNER OUTPUT] (2026-03-25 10:30:00) |
| 256 | +[plan with steps and evaluation criteria] |
| 257 | +
|
| 258 | +--- |
| 259 | +### [STEP 1 CONTRACT PROPOSAL] (2026-03-25 10:30:15) |
| 260 | +[Generator's proposed contract] |
| 261 | +
|
| 262 | +--- |
| 263 | +### [STEP 1 CONTRACT REVIEW] (2026-03-25 10:30:25) |
| 264 | +[Evaluator's review — APPROVED or AMENDMENTS REQUIRED] |
| 265 | +
|
| 266 | +--- |
| 267 | +### [STEP 1 WORK LOG] (2026-03-25 10:30:45) |
| 268 | +[Generator's output + self-assessment] |
| 269 | +
|
| 270 | +--- |
| 271 | +### [STEP 1 EVALUATION] (2026-03-25 10:31:00) |
| 272 | +[Evaluator's per-criterion scores, findings, and feedback] |
| 273 | +``` |
| 274 | + |
| 275 | +### Refine vs. Pivot |
| 276 | + |
| 277 | +When a step fails evaluation, the harness computes a score trajectory across retries: |
| 278 | + |
| 279 | +- **Scores improving** → REFINE: keep the current direction, fix specific issues |
| 280 | +- **Scores declining or stagnant** → PIVOT: take a fundamentally different approach |
| 281 | + |
| 282 | +This signal is passed to the Generator alongside the Evaluator's feedback. |
| 283 | + |
| 284 | +### Evaluation Criteria |
| 285 | + |
| 286 | +The Planner defines domain-appropriate criteria as part of the plan. Each criterion has: |
| 287 | + |
| 288 | +| Field | Description | |
| 289 | +|-------|-------------| |
| 290 | +| **Name** | Short label (e.g., "accuracy", "clarity") | |
| 291 | +| **Weight** | Relative importance (high, standard, low) | |
| 292 | +| **Description** | What it measures and what good/bad looks like | |
| 293 | +| **Threshold** | Minimum passing score (1-10). Any criterion below threshold = step fails | |
0 commit comments