+210 XP

Multi-Agent-Orchestrierung: Handoffs und parallele Agents

# Multi-Agent-Orchestrierung: Handoffs und parallele Agents

Ein Agent, vollgepackt mit zwölf Tools und einem System-Prompt von 2.000 Wörtern, ist ein Wartungsalbtraum, und er argumentiert meist schlechter als drei fokussierte Agents, die jeweils eine Sache gut machen. Echte Workflows zerfallen in Spezialisten, die entweder aneinander übergeben oder nebeneinander laufen. Diese Lektion geht in die Tiefe, wie Sie das im OpenAI Agents SDK bauen: Handoffs, paralleles Fan-out sowie die Guardrails und das Tracing, die ein Multi-Agent-System davor bewahren, ein unnachvollziehbares Durcheinander zu werden.

Warum einen Agent in mehrere aufteilen

Ein einzelner Agent verschlechtert sich auf vorhersehbare Weise, wenn Sie ihm immer mehr Verantwortung aufladen. Der System-Prompt wächst, bis sich Anweisungen widersprechen. Die Tool-Liste wird so lang, dass das Modell das falsche Tool wählt. Evaluation wird unmöglich, weil jede Prompt-Änderung alle Aufgaben gleichzeitig betrifft.

Die Aufteilung löst das, indem jeder Agent einen engen Anweisungssatz und eine kurze Tool-Liste erhält. Ein Billing-Agent weiß nur über Rechnungen und Rückerstattungen Bescheid. Ein Tech-Support-Agent kennt nur Diagnosen und Reset-Abläufe. Jeder ist leichter zu prompten, zu testen und auszutauschen.

Die zwei Kernmuster:

  • Handoff: Ein Agent entscheidet, dass ein anderer Agent besser geeignet ist, und delegiert die ganze Konversation an ihn. Sequenziell, wie eine Telefonweiterleitung.
  • Parallel: Sie lassen mehrere Agents gleichzeitig an unabhängigen Teilaufgaben arbeiten und führen die Ergebnisse dann zusammen. Fan-out, als würden Sie drei Rechercheure in drei Bibliotheken schicken.

Handoffs: Delegation als First-Class-Primitive

Im Agents SDK ist ein Handoff ein spezielles Tool, das das Modell aufrufen kann, um die Kontrolle an einen anderen Agent zu übergeben. Sie schreiben keine Routing-Logik von Hand. Sie geben einem Agent eine Liste möglicher Handoff-Ziele, und das Modell entscheidet anhand der Konversation, wann übergeben wird.

Die kanonische Form ist ein Triage-Agent: ein leichtgewichtiger Router, dessen einzige Aufgabe darin besteht, die Anfrage des Nutzers zu lesen und an den richtigen Spezialisten zu übergeben. Er hat selbst keine Domänen-Tools.

python
from agents import Agent, Runner

billing_agent = Agent(
    name="Billing Agent",
    handoff_description="Handles invoices, charges, and refunds.",
    instructions=(
        "You resolve billing issues. Look up the customer's latest "
        "invoice and explain charges or process a refund. If the "
        "problem is technical, say so clearly."
    ),
    tools=[lookup_invoice, issue_refund],
)

tech_agent = Agent(
    name="Tech Support Agent",
    handoff_description="Handles login, errors, and device issues.",
    instructions=(
        "You diagnose technical problems. Walk the user through "
        "resets and known fixes. If the issue is about money, "
        "say so clearly."
    ),
    tools=[run_diagnostic, send_reset_link],
)

triage_agent = Agent(
    name="Triage Agent",
    instructions=(
        "Route the user to the right specialist. Do not answer "
        "billing or technical questions yourself. Hand off."
    ),
    handoffs=[billing_agent, tech_agent],
)

result = Runner.run_sync(
    triage_agent,
    "I was charged twice for my subscription this month.",
)
print(result.final_output)

Zwei Dinge lassen das funktionieren. Die handoff_description ist der Text, den das Routing-Modell liest, um zu entscheiden, wohin die Anfrage geht, schreiben Sie sie also wie eine Stellenanzeige, nicht wie einen Kommentar. Und die handoffs-Liste macht jeden Spezialisten zu einem aufrufbaren Ziel für den Triage-Agent.

Was tatsächlich über die Grenze geht

Standardmäßig wandert die komplette Konversationshistorie mit dem Handoff, der Billing-Agent sieht die ursprüngliche Beschwerde also, ohne dass Sie sie erneut übergeben müssen. Das ist meist gewollt. Wenn nicht (etwa wenn der Spezialist eine frühere sensible Nachricht nicht sehen soll), können Sie den Handoff anpassen, um den Input zu filtern oder zusätzlichen Kontext einzuspeisen. Die Handoffs-Dokumentation behandelt Input-Filter und on_handoff-Callbacks für Logging oder das Vorabladen von Daten im Moment der Übergabe.

Ein feiner Punkt: Nach einem Handoff kehrt die Kontrolle nicht automatisch zum Triage-Agent zurück. Die Konversation gehört jetzt dem Spezialisten. Wenn Sie ein Hub-and-Spoke-Muster wollen, in dem Spezialisten zur Triage zurückspringen, geben Sie jedem Spezialisten einen Handoff zurück zum Triage-Agent. Entwerfen Sie die Topologie bewusst.

Parallele Agents: Fan-out, dann einsammeln

Handoffs sind sequenziell. Manchmal wollen Sie Arbeit gleichzeitig erledigen, weil die Teilaufgaben nicht voneinander abhängen. Klassische Fälle: drei Antwortkandidaten entwerfen und den besten wählen, oder Rechnungshistorie und technische Logs gleichzeitig einsammeln, bevor ein Spezialist über beides nachdenkt.

Das SDK läuft auf asyncio, Parallelität heißt also einfach, mehrere Agents mit asyncio.gather laufen zu lassen und die Ausgaben zu kombinieren. Hier ein Fan-out, das zwei unabhängige Entwürfe erzeugt und dann einen dritten Agent zur Synthese nutzt:

python
import asyncio
from agents import Agent, Runner

drafter = Agent(
    name="Drafter",
    instructions="Write one concise support reply to the user.",
)

synthesizer = Agent(
    name="Synthesizer",
    instructions=(
        "You are given two candidate replies. Merge their best "
        "parts into one final reply. Remove redundancy."
    ),
)

async def main(user_msg: str) -> str:
    draft_a, draft_b = await asyncio.gather(
        Runner.run(drafter, user_msg),
        Runner.run(drafter, user_msg),
    )
    merged = await Runner.run(
        synthesizer,
        f"Reply A:\n{draft_a.final_output}\n\nReply B:\n{draft_b.final_output}",
    )
    return merged.final_output

print(asyncio.run(main("How do I export my data?")))

Parallele Arbeit bringt Ihnen Latenz (zwei Dinge passieren gleichzeitig) oder Qualität (mehrfach sampeln und auswählen). Sie kostet Tokens: den Drafter zweimal laufen zu lassen, verdoppelt die Ausgaben für diesen Schritt annähernd. Machen Sie Fan-out nur dort, wo sich die Parallelität rechnet.

Ein verwandtes Muster ist Agents als Tools. Statt zu übergeben (Kontrolle abtreten), kann ein übergeordneter Agent einen anderen Agent über agent.as_tool(...) wie eine Funktion aufrufen, das Ergebnis zurückerhalten und die Kontrolle behalten. So bauen Sie einen Top-Level-Orchestrator, der parallel an Sub-Agents verteilt und für die endgültige Antwort zuständig bleibt. Handoffs geben die Verantwortung ab; Agents-as-Tools behalten sie.

Guardrails: schlechten Input und Output früh abfangen

Mehr Agents heißt mehr Angriffsfläche für Fehler. Guardrails sind Prüfungen, die parallel zu Ihren Agents laufen, um Input oder Output zu validieren, und sie können einen tripwire auslösen, der die Ausführung stoppt, bevor Sie Tokens verbrennen oder etwas nach außen dringt.

Ein Input-Guardrail läuft auf der eingehenden Nachricht des Triage-Agents. Ein günstiges, schnelles Modell kann themenfremde oder missbräuchliche Anfragen aussortieren, bevor ein teurer Spezialist überhaupt startet.

python
from agents import (
    Agent, Runner, GuardrailFunctionOutput, input_guardrail,
)
from pydantic import BaseModel

class Relevance(BaseModel):
    is_support_request: bool

screener = Agent(
    name="Screener",
    instructions="Is this a customer support request? Answer strictly.",
    output_type=Relevance,
)

@input_guardrail
async def on_topic(ctx, agent, user_input):
    result = await Runner.run(screener, user_input, context=ctx.context)
    flagged = not result.final_output.is_support_request
    return GuardrailFunctionOutput(
        output_info=result.final_output,
        tripwire_triggered=flagged,
    )

triage_agent = Agent(
    name="Triage Agent",
    instructions="Route to the right specialist.",
    handoffs=[billing_agent, tech_agent],
    input_guardrails=[on_topic],
)

Output-Guardrails funktionieren genauso auf der endgültigen Antwort, nützlich, um zu prüfen, dass ein Billing-Agent nie eine Rückerstattung verspricht, die er nicht gewähren darf. Beachten Sie oben die Nutzung von output_type mit einem Pydantic-Modell: Das sind Structured Outputs, die die Durchsetzung übernehmen, der Screener liefert also einen typisierten Boolean statt Prosa, die Sie parsen müssten. Der Guardrails-Guide beschreibt den Ablauf der Tripwire-Exception.

Wissenscheck

1. Warum verbessert es laut Lektion typischerweise die Ergebnisse, einen großen Agent in mehrere fokussierte Agents aufzuteilen?

2. Was unterscheidet ein Handoff am besten von einem parallelen Muster in der Multi-Agent-Orchestrierung?

3. Wie führt ein Agent im Agents SDK tatsächlich ein Handoff an einen anderen Agent aus?

MEHRFACHAUSWAHL

4. Wählen Sie ALLE Arten, auf die sich ein einzelner überladener Agent laut Lektion verschlechtert, wenn sich Verantwortlichkeiten häufen.

Wählen Sie alle richtigen Antworten aus.

MEHRFACHAUSWAHL

5. Wählen Sie ALLE Aussagen, die einen Triage-Agent so beschreiben, wie er in der Lektion dargestellt wird.

Wählen Sie alle richtigen Antworten aus.

Tracing: sehen, was Ihre Agents wirklich getan haben

Sobald Sie drei Agents, Handoffs, parallele Zweige und Guardrails haben, lässt sich „es hat eine seltsame Antwort gegeben" nicht mehr durch das Lesen eines einzelnen Transkripts debuggen. Sie müssen den gesamten Run als Baum sehen.

Das Agents SDK hat Tracing eingebaut und standardmäßig aktiviert. Jeder Run erzeugt einen Trace mit Spans für jeden Agent-Aufruf, jeden Tool-Call, jeden Handoff und jeden Guardrail. Sie sehen sie im Traces-Dashboard auf der OpenAI-Plattform. Das ist der größte Einzelgrund, das SDK zu nutzen statt eine eigene Orchestrierungs-Loop zusammenzuschustern: Sie bekommen die Observability gratis.

Gruppieren Sie zusammengehörige Runs unter einem Trace, damit eine komplette Kundensitzung als ein Baum erscheint:

python
from agents import Runner, trace

async def handle_session(msg: str):
    with trace("support-session"):
        result = await Runner.run(triage_agent, msg)
        return result.final_output

Im Dashboard sehen Sie genau, wohin die Triage die Anfrage geschickt hat, wie lange das Rechnungs-Lookup gedauert hat und ob ein Guardrail ausgelöst wurde. Wenn ein Handoff beim falschen Spezialisten landet, zeigt der Trace die Routing-Entscheidung, sodass Sie die handoff_description korrigieren können statt zu raten.

Building Multi-Agent Systems with the OpenAI Agents SDK

Watch on YouTube

Wann Multi-Agent besser ist als Single-Agent, und was es kostet

Greifen Sie zu mehreren Agents, wenn:

  • Verantwortlichkeiten wirklich unterschiedlich sind und jede andere Tools oder Anweisungen braucht (Triage vs. Billing vs. Tech).
  • Sie unabhängige Evaluation wollen: Sie können den Billing-Agent isoliert testen.
  • Teilaufgaben unabhängig sind und Parallelität Latenz senkt oder die Qualität durch Sampling verbessert.

Bleiben Sie bei einem Agent, wenn:

  • Die Aufgabe ein einziger zusammenhängender Ablauf ist, bei dem jeder Schritt den vollen Kontext braucht.
  • Latenz und Kosten wichtiger sind als Modularität. Jeder Handoff und jeder Guardrail ist ein zusätzlicher Modellaufruf, und paralleles Fan-out vervielfacht die Token-Ausgaben.
  • Sie noch prototypisieren. Starten Sie mit einem Agent, teilen Sie erst, wenn eine klare Naht sichtbar wird.

Die echten Kosten eines Multi-Agent-Designs sind Koordinationskomplexität: Routing kann fehlschlagen, Kontext kann bei einem schlecht konfigurierten Handoff verloren gehen, und eine geschwätzige Topologie kann zwischen Agents hin- und herspringen und Tokens verbrennen. Tracing und Guardrails existieren genau dafür, diese Komplexität handhabbar zu machen, nicht um sie zu beseitigen. Fügen Sie Agents hinzu, wenn die Naht offensichtlich ist, und lassen Sie Traces Ihnen sagen, ob eine Aufteilung hilft oder schadet.

Wichtigste Erkenntnisse

  • Teilen Sie nach Verantwortung, nicht aus Eitelkeit. Nutzen Sie einen leichtgewichtigen Triage-Agent zum Routing und geben Sie jedem Spezialisten einen engen Anweisungssatz und eine kurze Tool-Liste. Schreiben Sie die handoff_description wie eine Stellenanzeige; der Router liest sie zur Entscheidung.
  • Handoffs geben die Kontrolle ab; Agents-as-Tools behalten sie. Nutzen Sie Handoffs zur Delegation (Telefonweiterleitung) und agent.as_tool(), wenn ein Orchestrator das Teilergebnis zurückbraucht und die Verantwortung behält.
  • Fan-out nur dort, wo es sich rechnet. Parallele Agents über asyncio.gather senken Latenz oder erhöhen Qualität durch Sampling, aber sie vervielfachen die Token-Kosten. Reservieren Sie sie für unabhängige Teilaufgaben.
  • Guardrails gehören an die Ränder. Screenen Sie Input mit einem günstigen Modell, bevor teure Spezialisten laufen, und validieren Sie Output, bevor er beim Nutzer ankommt. Nutzen Sie output_type mit Pydantic, damit Prüfungen typisierte Werte zurückgeben.
  • Tracing ist im Maßstab nicht optional. Kapseln Sie Sitzungen in trace(...) und lesen Sie das Traces-Dashboard, um Routing zu debuggen und zu messen, ob jede Aufteilung tatsächlich hilft.

Was Sie aus dieser Lektion umsetzen

Diese Maßnahmen sind im Playbook der Rolle zusammengefasst.

  • Systeme als kleine Spezialisten-Agents mit Handoffs und Guardrails auf günstigen Modellen modellieren
Vollständiges Action Playbook ansehen