Spezialisierte Agents statt eines Generalisten
Jeder Agent in einer Multi-Agent-Architektur hat eine Rolle und einen begrenzten Kontext. Der Planner-Agent erzeugt Task-Graphen, schreibt aber keinen Produktionscode. Der Implementer-Agent arbeitet nur innerhalb eines Moduls. Der Tester-Agent schreibt und fixiert Tests, ohne Feature-Code zu ändern. Der Reviewer-Agent prüft Diff gegen Security- und Architektur-Policies.
Diese Trennung reduziert Halluzinations-Korrelation: Wenn der Implementer einen Fehler macht, fängt der Tester oder Reviewer ihn ab – weil sie mit frischem Kontext und anderem Prompt-Ziel arbeiten.
Agenticode definiert Agent-Rollen als versionierte Konfiguration – nicht als Ad-hoc-Prompts. So sind Multi-Agent-Runs reproduzierbar und in CI integrierbar.
agents:
planner:
model: claude-sonnet
tools: ["read_file", "grep", "architecture_map"]
implementer:
model: cursor-agent
allowed_paths: ["src/Billing/**"]
tools: ["edit_file", "run_terminal_cmd"]
tester:
model: claude-sonnet
allowed_paths: ["tests/Billing/**"]
tools: ["edit_file", "run_phpunit"]
reviewer:
model: claude-opus
tools: ["read_file", "security_scan", "diff_stat"]
human_gate: true
handoff_protocol: json_task_graph_v2
Handoffs und Task-Graphen
Handoffs sind strukturierte Übergaben zwischen Agents – kein freier Chat-Verlauf. Ein Planner liefert einen Task-Graphen: Knoten sind Tasks, Kanten sind Abhängigkeiten. Der Orchestrator führt topologisch sortierte Tasks aus und weist jeden an den passenden Agent.
Jeder Handoff enthält: task_id, intent, input_artifacts (Dateipfade, vorherige Test-Results), constraints und expected_outputs. Der empfangende Agent bestätigt mit einem strukturierten ACK oder REJECT mit Begründung.
Bei REJECT eskaliert der Orchestrator: Task neu planen, anderen Agent zuweisen, oder Human-in-the-Loop. So bleiben Failure Domains klein – ein gescheiterter Implementer-Run korrumpiert nicht den gesamten Refactoring-Plan.
<?php
declare(strict_types=1);
namespace App\Agentic\Orchestration;
final class TaskGraphOrchestrator
{
/** @param array<string, array{depends_on: string[], agent: string}> $graph */
public function executeNextReadyTask(array $graph, array $completed): ?string
{
foreach ($graph as $taskId => $task) {
if (in_array($taskId, $completed, true)) {
continue;
}
$depsMet = empty(array_diff($task['depends_on'], $completed));
if ($depsMet) {
return $taskId;
}
}
return null;
}
public function buildHandoff(string $taskId, array $task, array $artifacts): array
{
return [
'handoff_version' => 2,
'task_id' => $taskId,
'agent' => $task['agent'],
'intent' => $task['intent'],
'input_artifacts' => $artifacts,
'constraints' => $task['constraints'] ?? [],
'timestamp' => (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM),
];
}
}
Failure Domains und Recovery
Eine Failure Domain ist der maximale Blast Radius eines fehlgeschlagenen Agent-Runs. Bei Agenticode isolieren wir Domains pro Modul, pro Agent-Rolle und pro Git-Branch. Ein fehlgeschlagener Tester-Run rollt nur Tests zurück, nicht den Implementer-Output – es sei denn, die Tests beweisen einen Implementierungsfehler.
Recovery-Strategien: Retry mit gleichem Agent (max. 2x), Retry mit anderem Model, Task-Splitting, Human-Eskalation. Jede Strategie ist im Orchestrator codiert – nicht improvisiert.
Observability über alle Agents hinweg: zentrales Log mit trace_id, Metriken pro Agent-Rolle (Erfolgsrate, Iterationen bis Done, Token-Verbrauch). So optimieren wir Orchestrierungen datengetrieben – ein Service, den Agenticode Kunden in Köln langfristig begleitet.
{
"trace_id": "refactor-billing-7f3a",
"failure_domain": "module:Billing",
"failed_task": "implement_vat_calculator",
"agent": "implementer",
"error_signature": "PHPStan: undefined method calculateVat()",
"recovery_plan": [
{ "strategy": "retry_same_agent", "attempt": 1, "max": 2 },
{ "strategy": "handoff_to_planner", "reason": "missing_domain_method" },
{ "strategy": "human_escalation", "if": "recovery_exhausted" }
],
"isolated_rollback": "git checkout HEAD -- src/Billing/VatCalculator.php"
}