Zum Hauptinhalt springen
Lektion 14 von 18 · Mistral Agents: Aufbau autonomer KI

Server- vs. Client-Ausführung

Lektion 14 von 18 Aktualisiert am 3. November 2026 Entwickler
Auf dieser Seite
  1. Zwei Wege zur Handoff-Behandlung
  2. Server-Modus, der Standard
  3. Client-Modus, wenn Sie Kontrolle wünschen
  4. Auswahl zwischen den beiden
  5. Kernaussagen

Lektion aktualisiert am 3. November 2026 basierend auf der mistralai SDK-Version 3.7.0 und der Mistral Handoffs-Dokumentation: Ein agent.handoff-Eintrag identifiziert das Zielagenten über next_agent_id (nicht to_agent), und conversations.append akzeptiert keinen agent_id-Parameter – älterer Code würde fehlschlagen. Die Wiederaufnahme des Zielagenten erfolgt hier über einen neuen Konversation, dem Sie den Kontext übergeben. Quellen: Handoffs · client-python.

Zwei Wege zur Handoff-Behandlung

Wenn ein Agent die Kontrolle an einen anderen Agenten übergibt, bietet die Mistral-API zwei Ausführungsmodi: server (automatisch) und client (manuell). Die Einstellung ist ein einzelnes Wort, bestimmt aber, wer den Workflow tatsächlich steuert. Im Server-Modus delegieren Sie die gesamte Choreografie an Mistral und erhalten das Ergebnis. Im Client-Modus übernehmen Sie die Kontrolle zwischen jedem Schritt. Alles andere – die Agenten, ihre Werkzeuge, ihre Handoff-Ziele – bleibt exakt gleich.

Server-Modus, der Standard

response = client.beta.conversations.start(
    agent_id=router_agent.id,
    inputs="Analyze and calculate market trends.",
    handoff_execution="server"  # Standard – kann weggelassen werden
)

Der Ablauf ist vollständig verwaltet: Der Router empfängt die Anfrage, entscheidet über die Übergabe an den Forschungsagenten, und Mistral führt die Übergabe aus; der Forschungsagent erledigt seine Arbeit und übergibt an den Rechenagenten, und Mistral führt auch diese Übergabe aus; der Rechenagent erzeugt das Ergebnis. Sie erhalten die endgültige Antwort, begleitet von allen Zwischenergebnissen – Sie sehen also, was passiert ist, aber erst nachträglich.

Dieser Modus besitzt drei Eigenschaften, die erklären, warum er der Standard ist. Er ist einfach, da Sie keine Steuerlogik auf Ihrer Seite schreiben müssen. Er ist schnell, weil die gesamte Kette bei Mistral ausgeführt wird, ohne Netzwerkrundgänge bei jedem Relay. Er ist zuverlässig, da Fehlerbehandlung und Timeouts zwischen Agenten für Sie gehandhabt werden.

Seine Einschränkungen sind das genaue Gegenstück. Sie haben keine Zwischenkontrolle: Es ist unmöglich, eine Übergabe während des Vorgangs zu validieren oder zu ändern. Die Kosten sind undurchsichtig, da alle Agenten in der Kette ausgeführt werden, ohne dass Sie den Fluss unterbrechen können, wenn eine Anfrage in eine unnötige Richtung läuft. Und Sie können keine benutzerdefinierte Logik zwischen den Schritten einfügen – keine feingranulare Protokollierung, keine Validierung, keine geschäftlichen Entscheidungen.

Client-Modus, wenn Sie Kontrolle wünschen

response = client.beta.conversations.start(
    agent_id=router_agent.id,
    inputs="Analyze the cloud market.",
    handoff_execution="client"
)

Der Router empfängt die Anfrage und entscheidet über die Übergabe, genau wie zuvor. Aber statt dass die Übergabe ausgeführt wird, erhalten Sie ein agent.handoff-Ereignis und die Kette stoppt dort. Es liegt an Ihnen, sie durch Aufruf des Zielagenten neu zu starten – was Ihnen die Freiheit lässt, zu validieren, zu protokollieren, den Kontext anzureichern oder einfach abzulehnen.

response = client.beta.conversations.start(
    agent_id=router_agent.id,
    inputs="Search for the latest tech news.",
    handoff_execution="client"
)

for entry in response.outputs:
    if entry.type == "agent.handoff":
        target_agent_id = entry.next_agent_id
        print(f"Handoff requested to: {target_agent_id}")

        # Validieren, dann an den Zielagenten übergeben, mit nützlichem Kontext
        next_response = client.beta.conversations.start(
            agent_id=target_agent_id,
            inputs="Search for the latest tech news.",
        )

        # Die Antwort des Zielagenten verarbeiten
        for next_entry in next_response.outputs:
            print(f"{next_entry.type}: {next_entry.content}")

Ein Punkt verdient Aufmerksamkeit: Die Dokumentation von Mistral beschreibt den client-Modus – die Kontrolle kehrt zum Zeitpunkt der Übergabe an Sie zurück – bietet aber keine Methode, damit der Zielagent dieselbe Konversation wieder aufnimmt, und conversations.append akzeptiert keinen agent_id-Parameter. Das Beispiel startet daher eine Konversation mit dem Zielagenten, dem Sie explizit übermitteln, was er benötigt: die ursprüngliche Anfrage und gegebenenfalls eine Zusammenfassung dessen, was bereits erledigt wurde. Dies ist auch eine Gelegenheit, nur das zu übermitteln, was er sehen muss.

Der obige Ausschnitt behandelt nur ein einzelnes Relay. Eine echte Kette verknüpft mehrere, was einen Loop erfordert.

def execute_with_control(router_id, query):
    """Führt einen Multi-Agenten-Workflow mit Kontrolle an jedem Schritt aus."""
    response = client.beta.conversations.start(
        agent_id=router_id,
        inputs=query,
        handoff_execution="client"
    )

    conversation_id = response.conversation_id
    results = []

    while True:
        handoff_found = False

        for entry in response.outputs:
            if entry.type == "agent.handoff":
                handoff_found = True
                target = entry.next_agent_id
                print(f"[LOG] Handoff to {target}")

                # Hier können Sie hinzufügen: Validierung, Protokollierung, Metriken
                response = client.beta.conversations.start(
                    agent_id=target,
                    inputs=query,  # die ursprüngliche Anfrage, ggf. angereichert
                    handoff_execution="client",
                )
                conversation_id = response.conversation_id
                break

            elif entry.type == "message.output":
                results.append(entry.content)

        if not handoff_found:
            break

    return results

Die Struktur ist die einer Pumpe: Solange ein Handoff in den Ausgaben erscheint, verarbeiten Sie es und starten neu; sobald eine Loop-Iteration keines findet, ist die Kette beendet und Sie verlassen mit den akkumulierten Nachrichten. Der Kommentar in der Mitte markiert den Ort, der diesen gesamten Modus rechtfertigt: Es ist dort, und nur dort, dass Ihr Code sich zwischen zwei Agenten einfügt.

Auswahl zwischen den beiden

Der Server-Modus deckt Standard-Produktion ab. Wenn Ihr Workflow vorhersehbar ist, wenn Sie den Agenten vertrauen, die Sie geschrieben haben, oder wenn Sie prototypisieren und Ergebnisse schnell sehen möchten, ist vollständige Automatisierung die richtige Wahl – und das Schreiben eines Kontrollloops wäre verschwendete Arbeit.

Der Client-Modus ist gerechtfertigt, sobald eine externe Anforderung in die Kette eintritt. Menschliche Validierung, wenn ein Operator eine Übergabe zu einem Agenten genehmigen muss, der sensible Aktionen auslöst. Der Bedarf an Protokollierung und Auditierung, wenn Compliance jede Stufe mit Ihren eigenen Identifikatoren und Zeitstempeln nachverfolgen erfordert. Konditionelle Routing, wenn die Entscheidung von Geschäftsregeln abhängt, die das Modell nicht kennen kann – Kundenstatus, Tageszeit, Kontingent. Eine Obergrenze oder Rate Limiting, wenn Sie die Anzahl der für eine Anfrage ausgeführten Agenten begrenzen möchten. Eine Fallback-Strategie, schließlich, wenn der Ausfall eines Agenten etwas anderes auslösen muss als einen Fehler, der dem Benutzer angezeigt wird.

Hier ist, wie die erste dieser Situationen in ihrem Skelett aussieht.

def workflow_with_validation(router_id, query):
    response = client.beta.conversations.start(
        agent_id=router_id,
        inputs=query,
        handoff_execution="client"
    )

    for entry in response.outputs:
        if entry.type == "agent.handoff":
            target = entry.next_agent_id
            approval = input(f"Authorize transfer to {target}? (y/n) ")

            if approval.lower() == "y":
                response = client.beta.conversations.start(
                    agent_id=target,
                    inputs=query,
                )
            else:
                print("Transfer refused.")
                break

Das Konsolen-input dient als Demonstration; in einer Anwendung wird es durch eine Benachrichtigung an einen Operator und durch die Wiederaufnahme des Workflows ersetzt, wenn die Antwort eingeht. Das Prinzip bleibt gleich: Die Übergabe erfolgt nur, wenn Ihr Code sie auslöst.

Der richtige Ansatz besteht darin, im Server-Modus zu beginnen und nur dann umzuschalten, wenn ein spezifisches Erfordernis dies verlangt. Der Wechsel in den Client-Modus „nur zur Sicherheit” lässt Sie sofort für die Komplexität eines Loops und Netzwerkrundgänge bezahlen, für eine Kontrolle, die Sie noch nicht nutzen.

Kernaussagen

  • Server-Modus = vollständig automatisch, einfach und schnell, keine Zwischenkontrolle
  • Client-Modus = Sie erhalten Handoff-Ereignisse und entscheiden, was Sie tun
  • Der Client-Modus ermöglicht Validierung, Protokollierung, konditionelles Routing und Fehlerbehandlung
  • Für die meisten Fälle ist der Server-Modus ausreichend – wechseln Sie in den Client-Modus, wenn Sie Kontrolle benötigen
  • Beide Modi unterstützen dieselben Agentenkette; nur die Kontrolle unterscheidet sich