Multi-Agent-Zusammenarbeit in der Praxis: Leitfaden zu 4 Architekturmustern
Laut Anthropic-Forschung liefern Multi-Agent-Systeme 90,2 % bessere Leistung als Single-Agent-Lösungen. Ein einzelner Agent hat drei kritische Schwachstellen: Kontextlimits (ab ca. 200k Token beginnt die Ausgabe zu driften), verstreute Fähigkeiten (zu viele Skills machen ihn zum „Alleskönner“) und schwieriges Debugging (wenn ein Agent ausfällt, ist die Fehlerquelle kaum zu finden). Multi-Agent-Systeme sind die Microservices-Architektur der KI-Welt: Jeder Agent erledigt genau eine Aufgabe und arbeitet über klare Nachrichtenübergabe zusammen.
Vier Kern-Architekturmustern decken unterschiedliche Szenarien ab: Subagents (zentrale Orchestrierung) für parallele, unabhängige Domänen, Skills (On-Demand-Laden) für einphasige Mehrstufen-Workflows, Handoffs (zustandsgetrieben) für mehrstufige Dialoge und Router (parallele Verteilung) für Abfragen über mehrere Datenquellen. Dieser Artikel führt Sie von der Auswahllogik über Production-Fallstricke bis zu LangGraph-Code – damit Sie entscheiden können, ob Subagents oder Skills passen und wie Sie den Zustand zwischen Agents verwalten.
Warum Multi-Agent-Systeme?
Ehrlich gesagt ist das größte Problem eines Single-Agent nicht „ob er funktioniert“, sondern „wie lange er zuverlässig bleibt“.
Kennen Sie das? Ein Agent schreibt anfangs sauberen Code – und plötzlich liefert er wirres Zeug. Sie fragen nach A, er redet über B, dann C und am Ende noch Z. Das ist keine „Dummheit“ des Agents, sondern ein überfülltes Kontextfenster.
Ein Single-Agent hat drei kritische Schwachstellen.
Kontextlimit. So leistungsfähig ein Agent auch ist – 200k Token Kontext reichen irgendwann. Lassen Sie ihn gleichzeitig Code reviewen, Sicherheit prüfen und Performance optimieren, behält er bestenfalls die Hälfte im Kopf. Ich habe einen Agent erlebt, der in Runde 20 noch über Python sprach und in Runde 21 JavaScript ausgab – er hatte vergessen, wofür er da war.
Verstreute Fähigkeiten. Je mehr Skills Sie einem Agent geben, desto mehr wird er zum „Alleskönner“ – ein bisschen von allem, nichts richtig gut. Soll er Code reviewen, schreibt er vielleicht Unit-Tests; soll er Dokumentation schreiben, refaktoriert er nebenbei den Code. Orientierung? Fehlanzeige.
Schwieriges Debugging. Fällt ein Agent aus, wissen Sie nicht, wo es hakt. Prompt zu lang? Tool-Aufruf fehlgeschlagen? Kontext kontaminiert? Die Fehlersuche ist wie die Nadel im Heuhaufen.
Multi-Agent-Systeme sind im Grunde die Microservices-Architektur der KI: Jeder Agent macht eine Sache und macht sie gut. Sie kooperieren über klare Nachrichten – statt alles in einen „Super-Agent“ zu stopfen.
Google, LangChain und Anthropic setzen auf diesen Ansatz. Laut O’Reilly-Bericht stieg die Zahl Agent-bezogener Papers 2025 von 820 Anfang des Jahres auf über 2.500 – mehr als verdreifacht. Warum? Weil klar wurde: Die Ära „ein Agent regiert alles“ ist vorbei.
Vier Kern-Architekturmustern
LangChain und Google haben mehrere etablierte Multi-Agent-Architekturen zusammengefasst. In eigenen Projekten habe ich gelernt: Jedes Muster hat seinen Einsatzbereich – falsch gewählt heißt Kanonen auf Spatzen oder Essen mit Stäbchen aus der Suppe.
Subagents (Unter-Agenten) – zentrale Orchestrierung
Das intuitivste Muster: Ein „Haupt-Agent“ als Kommandeur mit mehreren „Unter-Agenten“. Unter-Agenten sind Tools des Haupt-Agenten; er entscheidet, wann wen er aufruft.
Nutzeranfrage → Haupt-Agent (Koordinator) → Verteilung an Unter-Agent A/B/C → Ergebnisse zusammenführen → Antwort
Wann einsetzen? Wenn die Aufgabe mehrere unabhängige Domänen betrifft. Beispiel Kundenservice: ein Unter-Agent für Bestellabfragen, einer für Rückerstattungen, einer für Beschwerden – jede Domäne mit eigener Wissensbasis und Tools; der Haupt-Agent routet nur.
Code-Beispiel (LangGraph):
from langgraph.prebuilt import create_react_agent
# Unter-Agenten definieren
order_agent = create_react_agent(
model="claude-3-5-sonnet-20241022",
tools=[query_order, update_order],
prompt="Du bist Bestellexperte und bearbeitest nur Bestellfragen."
)
refund_agent = create_react_agent(
model="claude-3-5-sonnet-20241022",
tools=[check_refund_policy, process_refund],
prompt="Du bist Rückerstattungsexperte und bearbeitest nur Rückerstattungen."
)
# Haupt-Agent hält Unter-Agenten als Tools
main_agent = create_react_agent(
model="claude-3-5-sonnet-20241022",
tools=[order_agent, refund_agent], # Unter-Agenten als Tools
prompt="Du bist Service-Leitung und leitest Anfragen an passende Experten weiter."
)
Vorteile: Saubere Kontextisolation – jeder Unter-Agent sieht nur Sein. Hohe Effizienz bei paralleler Ausführung.
Nachteile: Jeder Unter-Agent ist ein eigener LLM-Aufruf – hoher Token-Verbrauch. Geteilter Zustand zwischen Unter-Agenten erfordert Umwege.
Skills – On-Demand-Laden
Ein Agent, mehrere „Persönlichkeiten“. Skills sind dynamisch geladene Prompt-Vorlagen. Der Agent wechselt je nach Aufgabe die Rolle – bleibt aber derselbe Agent.
Nutzeranfrage → ein Agent → Skill „Code-Review“ laden → ausführen → Skill „Dokumentation“ laden → ausführen
Wann einsetzen? Einphasige Verarbeitung mit unterschiedlichem Fachwissen pro Phase. Beispiel Coding-Assistent: „Entwickler“-Modus beim Schreiben, „Technical Writer“-Modus bei der Dokumentation.
Code-Beispiel:
# Skills-Verzeichnisstruktur
skills/
├── code_review.md # Prompt für Code-Review
├── doc_writer.md # Prompt für Dokumentation
└── security_audit.md # Prompt für Security-Audit
# Skill dynamisch laden
def load_skill(skill_name: str) -> str:
with open(f"skills/{skill_name}.md") as f:
return f.read()
# Verwendung
agent = create_react_agent(
model="claude-3-5-sonnet-20241022",
tools=[...],
prompt=load_skill("code_review") # zur Laufzeit wechseln
)
Vorteile: Leichtgewichtig, kein zusätzlicher Koordinations-Overhead. Geringerer Token-Verbrauch als Subagents.
Nachteile: Kontext akkumuliert. Nach zehn Skill-Wechseln liegen neun frühere Skills noch im Kontext – wird unübersichtlich.
Handoffs (Übergabe) – zustandsgetrieben
Agents übergeben Aufgaben wie beim Staffellauf. Agent A beendet seinen Teil und „wirft“ den Zustand an Agent B weiter.
Nutzeranfrage → Agent A (Infos sammeln) → Übergabe → Agent B (analysieren) → Übergabe → Agent C (Lösung)
Wann einsetzen? Mehrstufige Dialoge. Beispiel Support: Problem erfassen → diagnostizieren → Lösung vorschlagen → Abschluss bestätigen – jede Phase braucht anderes Fachwissen.
Code-Beispiel:
from langchain_core.tools import tool
# Übergabe-Tools definieren
@tool
def handoff_to_diagnosis(issue_summary: str) -> str:
"""Problem an Diagnose-Experten übergeben."""
return f"Problem übernommen: {issue_summary}, Diagnose startet..."
@tool
def handoff_to_solution(diagnosis_result: str) -> str:
"""Diagnoseergebnis an Lösungsexperten übergeben."""
return f"Auf Basis der Diagnose: {diagnosis_result}, Lösung wird erarbeitet..."
# Agent-Kette
triage_agent = create_react_agent(
tools=[handoff_to_diagnosis],
prompt="Du sortierst Anfragen ein und übergibst an Diagnose-Experten."
)
diagnosis_agent = create_react_agent(
tools=[handoff_to_solution],
prompt="Du analysierst Ursachen und übergibst an Lösungsexperten."
)
Vorteile: Natürlicher Dialogfluss, intuitiv wie menschliche Zusammenarbeit. Jeder Agent fokussiert die aktuelle Phase.
Nachteile: Komplexes State-Management. Agent A muss an B exakt das richtige Format liefern – sonst bricht die Kette.
Router – parallele Verteilung
Ein Router-Agent klassifiziert die Anfrage, ruft parallel mehrere Spezialisten auf und führt die Ergebnisse zusammen.
Nutzeranfrage → Router (Klassifikation) → parallel Agent A/B/C → Synthese → Antwort
Wann einsetzen? Eine Anfrage braucht mehrere Datenquellen. Beispiel Unternehmens-Wissensbasis: Router erkennt Fragetyp, parallel Abfrage interner Docs, externer APIs und Datenbank – dann Gesamtantwort.
Code-Beispiel:
from langgraph.graph import StateGraph
# Parallele Knoten
async def query_internal_docs(state):
# Interne Dokumente abfragen
return {"internal_results": [...]}
async def query_external_api(state):
# Externe API abfragen
return {"external_results": [...]}
async def query_database(state):
# Datenbank abfragen
return {"db_results": [...]}
async def synthesize(state):
# Alle Ergebnisse zusammenführen
all_results = state["internal_results"] + state["external_results"] + state["db_results"]
return {"final_answer": summarize(all_results)}
# Parallelen Graphen bauen
graph = StateGraph(State)
graph.add_node("internal", query_internal_docs)
graph.add_node("external", query_external_api)
graph.add_node("database", query_database)
graph.add_node("synthesize", synthesize)
# Parallel ausführen
graph.add_edge("router", ["internal", "external", "database"])
graph.add_edge(["internal", "external", "database"], "synthesize")
Vorteile: Parallel – am schnellsten. Zustandslos, jede Abfrage unabhängig.
Nachteile: Kein Mehr-Runden-Dialog. Jede Anfrage ist neu – der Agent erinnert sich nicht an die vorherige Runde.
Entscheidungsrahmen für die Architekturwahl
Theorie reicht nicht – welches Muster passt? Ein einfacher Entscheidungsfluss:
Was brauchen Sie?
│
├─→ Mehrere unabhängige Domänen parallel?
│ │
│ └─→ Subagents (zentrale Orchestrierung)
│
├─→ Ein Agent, mehrere Skill-Phasen?
│ │
│ └─→ Skills (On-Demand)
│
├─→ Sequenzieller Workflow, Staffelstab?
│ │
│ └─→ Handoffs (zustandsgetrieben)
│
└─→ Mehrere Datenquellen, Antwort synthetisieren?
│
└─→ Router (parallel)
Zur Orientierung eine Vergleichstabelle:
| Muster | Verteilte Entwicklung | Parallelisierung | Mehr-Runden-Dialog | Direkte Nutzerinteraktion | Token-Verbrauch |
|---|---|---|---|---|---|
| Subagents | hoch | hoch | hoch | niedrig | hoch |
| Skills | hoch | mittel | hoch | hoch | niedrig |
| Handoffs | nein | nein | hoch | hoch | mittel |
| Router | mittel | hoch | nein | mittel | hoch |
So lesen Sie die Tabelle:
- Verteilte Entwicklung: Entwickelt Ihr Team Module getrennt? Dann passen Subagents und Skills – jede Person einen Unter-Agent oder Skill.
- Parallelisierung: Brauchen Sie Geschwindigkeit? Router und Subagents parallelisieren am besten.
- Mehr-Runden-Dialog: Braucht der Nutzer mehrere Runden? Handoffs und Skills unterstützen Dialogfluss natürlich.
- Direkte Nutzerinteraktion: Spricht der Nutzer direkt mit Unter-Agenten? Skills und Handoffs ja, Router nein.
- Token-Verbrauch: Kosten sensibel? Skills spart am meisten, Router und Subagents verbrauchen am meisten.
Meine Erfahrung: Einfach anfangen. MVP mit Skills oder Handoffs – bei Engpässen auf Subagents oder Router upgraden. Nicht sofort Distributed Architecture – Over-Engineering kenne ich aus eigener Erfahrung.
Production-Implementierung
Vom Demo zur Production liegt ein Ozean dazwischen. Diese Fallstricke habe ich alle selbst erlebt.
State-Management
Geteilter Zustand zwischen Agents – klassisches Problem: Race Conditions. Zwei Agents schreiben dieselbe Variable – wer gewinnt?
LangGraphs Antwort: output_key – jeder Agent schreibt nur in seinen eigenen Schlüssel.
from langgraph.graph import StateGraph, MessagesState
class GraphState(MessagesState):
security_result: str = "" # exklusiv für Security-Agent
style_result: str = "" # exklusiv für Style-Agent
perf_result: str = "" # exklusiv für Performance-Agent
# Security-Agent schreibt nur security_result
async def security_agent(state: GraphState):
result = await analyze_security(state["messages"])
return {"security_result": result} # nur dieser Schlüssel
# Style-Agent schreibt nur style_result
async def style_agent(state: GraphState):
result = await analyze_style(state["messages"])
return {"style_result": result}
Parallel oder seriell – jeder Agent bleibt in seinem Bereich, ohne sich gegenseitig zu stören.
Kontext-Kontamination: Agent B liest Ausgabe von A, braucht sie aber nicht. Mein Ansatz: Feld relevant_keys im State – jeder Agent liest nur die nötigen Schlüssel.
Performance-Optimierung
Token-Verbrauch bei Multi-Agent-Systemen ist ein Fass ohne Boden. Ein paar Spar-Tricks:
1. Subagents sparen 67 % Token gegenüber Skills (Multi-Domain-Szenarien)
LangChain-Testdaten: Bei drei unabhängigen Domänen verbraucht Subagents ein Drittel der Tokens von Skills. Warum? Kontextisolation – jeder Unter-Agent sieht nur seine Domäne. Bei Skills stapeln sich alle Skill-Kontexte.
2. Stateful-Modus spart 40–50 % wiederholte Aufrufe
Bei vielen wiederholten Abfragen (dieselbe Frage zehnmal) merkt sich ein stateful Handoffs-Agent frühere Antworten. LangChain: Stateful vs. stateless – fast halb so viele LLM-Aufrufe.
3. Reflexions-Modus: Iterationen begrenzen
Reflexion – Agent prüft Output, findet Fehler, generiert neu – ist gut, kann aber endlos laufen. Ich setze max_iterations=2 oder 3, danach harter Exit.
from langgraph.checkpoint.memory import MemorySaver
# Iterations-Obergrenze
graph = create_react_agent(
model="claude-3-5-sonnet-20241022",
tools=[...],
checkpointer=MemorySaver(),
config={"configurable": {"max_iterations": 3}} # max. 3 Reflexions-Runden
)
Typische Fallstricke
Endlosschleife: Agent ruft sich selbst auf – immer wieder. Lösung: max_iterations und klare Exit-Bedingungen.
def should_continue(state):
if state["iteration_count"] >= 3:
return "end"
if "done" in state["messages"][-1].content:
return "end"
return "continue"
Kontext-Inflation: Agent wird „dümmer“, Ausgaben kürzer – meist zu voller Kontext. Lösung: Blackboard-Muster (gemeinsame Tafel), nur nötigen Kontext behalten, regelmäßig aufräumen.
Koordinations-Overhead: Mehr Agents, exponentiell mehr Kommunikation. Mein Test: von 3 auf 10 Agents stieg die Antwortzeit von 2 auf 15 Sekunden. Lösung: ähnliche Rollen zusammenlegen, unter 5 Agents bleiben.
Vollständiges Implementierungsbeispiel
Genug Theorie – praxisnah. Ich habe ein Code-Review-Multi-Agent-System mit Router + ParallelAgent aufgebaut.
Architektur: Router erkennt Sprache und Typ → parallel Security-Audit, Style-Check, Performance-Analyse → Synthese als Report.
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langchain_anthropic import ChatAnthropic
# Zustand definieren
class CodeReviewState(TypedDict):
code: str
language: str
security_issues: list
style_issues: list
perf_issues: list
final_report: str
# LLM initialisieren
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
# Router: Sprache erkennen
async def route_code(state: CodeReviewState) -> dict:
code = state["code"]
# Vereinfacht – in Production LLM-Klassifikation
if "def " in code or "import " in code:
language = "python"
elif "function" in code or "const " in code:
language = "javascript"
else:
language = "unknown"
return {"language": language}
# Security-Audit-Agent
async def security_audit(state: CodeReviewState) -> dict:
code = state["code"]
prompt = f"""Du bist Security-Audit-Experte. Prüfe den Code auf:
- SQL-Injection-Risiken
- XSS-Schwachstellen
- Leak sensibler Daten
- Unsichere Abhängigkeiten
Code:
{code}
Ausgabe als JSON-Liste: line, severity, description pro Eintrag.
"""
response = await llm.ainvoke(prompt)
# Ergebnis parsen...
return {"security_issues": []}
# Style-Check-Agent
async def style_check(state: CodeReviewState) -> dict:
code = state["code"]
language = state["language"]
prompt = f"""Du bist Style-Experte. Prüfe {language}-Code auf:
- Namenskonventionen
- Formatierung
- Vollständigkeit der Kommentare
Code:
{code}
Ausgabe als JSON-Liste.
"""
response = await llm.ainvoke(prompt)
return {"style_issues": []}
# Performance-Analyse-Agent
async def perf_analysis(state: CodeReviewState) -> dict:
code = state["code"]
prompt = f"""Du bist Performance-Experte. Prüfe den Code auf:
- Hohe Zeitkomplexität
- Unnötige Schleifen
- Speicherleck-Risiken
Code:
{code}
Ausgabe als JSON-Liste.
"""
response = await llm.ainvoke(prompt)
return {"perf_issues": []}
# Gesamtbericht
async def generate_report(state: CodeReviewState) -> dict:
security = state.get("security_issues", [])
style = state.get("style_issues", [])
perf = state.get("perf_issues", [])
total_issues = len(security) + len(style) + len(perf)
report = f"""# Code-Review-Bericht
## Überblick
- Sprache: {state['language']}
- Gesamtprobleme: {total_issues}
## Sicherheit ({len(security)})
{format_issues(security)}
## Stil ({len(style)})
{format_issues(style)}
## Performance ({len(perf)})
{format_issues(perf)}
## Empfehlung
Priorität auf Sicherheitsprobleme...
"""
return {"final_report": report}
# Graph bauen
graph = StateGraph(CodeReviewState)
graph.add_node("router", route_code)
graph.add_node("security", security_audit)
graph.add_node("style", style_check)
graph.add_node("perf", perf_analysis)
graph.add_node("report", generate_report)
# Ablauf: Router → drei parallele Checks → Report
graph.set_entry_point("router")
graph.add_edge("router", "security")
graph.add_edge("router", "style")
graph.add_edge("router", "perf")
graph.add_edge("security", "report")
graph.add_edge("style", "report")
graph.add_edge("perf", "report")
graph.add_edge("report", END)
# Kompilieren
app = graph.compile()
# Nutzung
async def review_code(code: str):
result = await app.ainvoke({"code": code})
return result["final_report"]
Bei ~100 Zeilen Code liefern drei parallele Agents Ergebnisse in 3–5 Sekunden; seriell dauert es mindestens 10 Sekunden.
Das ist die Basisversion. In Production kommen noch Cache (gleicher Code nicht doppelt prüfen), inkrementelles Review (nur geänderte Teile) und Nutzer-Feedback (False Positives markieren) – alles Erweiterungen auf dieser Architektur.
Fazit
Kurz zusammengefasst:
Grundlogik: Die Musterwahl zählt mehr als das Framework. LangGraph, AutoGen, CrewAI – gute Tools. Router für ein Handoffs-Problem? Kein Framework rettet das.
Mittlere Strategie: Einfach starten, schrittweise skalieren. MVP mit Skills oder Handoffs – Engpass? Dann Subagents oder Router. Over-Engineering ist der größte Fallstrich – ich bin reingetappt, Sie müssen nicht.
Production: State-Management, Performance, Kosten. Token-Verbrauch, Endlosschleifen, Kontext-Kontamination – diese drei Themen gelöst, läuft Ihr Multi-Agent-System stabil.
Nächster Schritt: LangGraph-Dokumentation öffnen, ein Muster wählen, in 50 Zeilen das einfachste Multi-Agent-System bauen. Nicht zu lange nachdenken – erst laufen lassen.
Multi-Agent-Zusammenarbeitssystem aufbauen
Von null ein Code-Review-Multi-Agent-System implementieren
- 1
Step 1: Architekturmuster wählen
Passendes Muster nach Aufgabencharakteristik wählen - 2
Step 2: Zustandsstruktur definieren
Gemeinsamen Multi-Agent-Zustand mit TypedDict definieren - 3
Step 3: Agent-Knoten erstellen
Pro Agent eine eigene Knotenfunktion anlegen - 4
Step 4: Ausführungsgraph bauen
Ablauf mit LangGraph StateGraph modellieren - 5
Step 5: State-Management ergänzen
output_key nutzen, um Race Conditions zu vermeiden
FAQ
Was ist der Unterschied zwischen Subagents und Skills?
Wann sollte ich Handoffs nutzen?
Wie vermeide ich Race Conditions in Multi-Agent-Systemen?
Wie kontrolliere ich den Token-Verbrauch?
Für welche Szenarien eignet sich Router?
Wie verhindere ich Endlosschleifen?
11 Min. Lesezeit · Veröffentlicht am: 25. März 2026 · Aktualisiert am: 9. Juli 2026
AI Agent Engineering Guide
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
Computer-Use Agent: KI steuert Ihren Computer
Claude Computer Use im Detail – von der Technik bis zur Praxis: Docker-Deployment, Codebeispiele, Wettbewerbsvergleich und Sicherheits-Best-Practices für KI-Desktop-Automatisierung
Teil 6 von 16
Nächster
KI-Agent-Toolchain-Design: Leitfaden vom einzelnen Tool zum Tool-Ökosystem
KI-Agent-Toolchain-Design im Detail: vom MCP-Protokoll bis zur Framework-Auswahl – LangChain, CrewAI und AutoGen im Vergleich, mit Enterprise-Praxis für ein skalierbares Tool-Ökosystem.
Teil 8 von 16
Ähnliche Beiträge
Agent Sandbox aufbauen: Vollständiger Leitfaden für sichere KI-Codeausführung

Agent Sandbox aufbauen: Vollständiger Leitfaden für sichere KI-Codeausführung
KI-Agent-Entwicklung in der Praxis: Architekturdesign und Implementierungsleitfaden


Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen