Startseite / Artikel

Ein Fünf-Agenten-Support-Desk auf Gemini 3.1 und ADK: Triage, Recherche, Handlung, QA und Orchestrator

Erstellen Sie ein mehragentenbasiertes Kundensupport-System mit Google ADK und Gemini 3.1: typbasierte Weiterleitungen, QA-Korrekturläufe, Agent Engine oder Cloud Run, Sitzungen und Kosten.

Verlag: REACTAPP.TOP19 Min. Lesezeit4349 Wörter

Quellen: Building a Multi-Agent AI System with Gemini 3 and Google Cloud: From Single Agent to Orchestrated Intelligence

Stellen Sie sich eine fehlerhafte Bestellung vor. Ein Kunde schreibt, dass das falsche Produkt angekommen ist, bittet um Rückerstattung und möchte außerdem das richtige Produkt noch am selben Tag versandt bekommen. Hinter diesem einen Satz stecken drei Aufgaben: Die Bestellung überprüfen, die Rückgabe bearbeiten und einen Ersatz schnell versenden. Jede Aufgabe benötigt eigene Daten, eigene Richtlinien und eigene Handlungen. Ein einzelner Support-Bot mit einer einzigen umfangreichen Anweisung kann nur eine einfache Frage bewältigen und stolpert oft, wenn mehrere Aufgaben miteinander verknüpft sind. Er wird langsam, anfällig und fehleranfällig.

Die Lösung besteht in einem mehragentigen Design: mehrere Spezialisten, von denen jeder für einen Teil des Workflows verantwortlich ist, wobei ein Orchesterator den Ablauf steuert. Im Folgenden wird gezeigt, wie man dies auf Google Cloud mit den Gemini 3.1-Modellen sowie dem Google Agent Development Kit (ADK) umsetzt. Es wird erläutert, wie man Agentenrollen mit klaren Grenzen festlegt, wie ein Orchesterator Aufgaben verteilt, Delegierungen vornimmt und Ergebnisse zusammenführt, wie Agenten den Zustand untereinander weitergeben – sowie, was genauso wichtig ist, wann ein einzelner Agent immer noch die bessere Wahl ist.

Was schiefgeht bei einem großen Prompt

Stellen Sie sich einen Support-Agenten vor, der mit einfachen Aufgaben begann und stetig neue Fähigkeiten erwarb: das Abrufen von Informationen aus einer Wissensdatenbank, ein sanfterer Tonfall bei verärgerten Kunden sowie die Möglichkeit zur Selbstüberprüfung. Sein Systemprompt wächst auf über 3.000 Token an, und jede Ergänzung stört etwas, das bereits vorhanden ist. Daraus ergeben sich vier Symptome:

  • Begrenzungen durch Mehrfachanwendung. Die Rückerstattungsregeln gelten plötzlich auch für Fragen, die nichts mit Rückerstattungen zu tun haben, wodurch auf einfache Produktanfragen ebenfalls Logik zur Rückgabe angewandt wird.
  • Geringere Aufmerksamkeitsspanne. Die Aufmerksamkeit eines Modells ist begrenzt. Wenn sie auf Dutzende von Anweisungen verteilt wird, von denen die meisten für die jeweilige Anfrage irrelevant sind, erhält jede weniger Gewicht.
  • Unmögliche Fehlersuche. Wenn die Antwort falsch ist, ist unklar, welche der vielen Anweisungen dazu geführt hat.
  • Nur ein Prozessweg für alles. Jede Anfrage durchläuft unabhängig von ihrer Schwierigkeit denselben Ablauf.

Durch Aufteilung der Arbeit erhält jedes Modell sein gesamtes Aufmerksamkeitsbudget für die vorliegende Aufgabe. Es denkt nur während der Verarbeitung von Rückerstattungen an die Rückerstattungsrichtlinien und nur beim Überprüfen eines Entwurfs an den Ton.

ADK ist nach diesem Konzept entworfen. Sein AutoFlow-Mechanismus steuert die Abstimmung zwischen Spezialisten: Wenn ein Orchesterer Sub-Agenten hat, fügt ADK ein transfer_to_agent()-Tool hinzu und schreibt Beschreibungen aller verfügbaren Spezialisten in seinen Kontext. Der Orchesterer weiß somit, wer zu seinem Team gehört und wofür jedes Mitglied geeignet ist.

Struktur des Systems

Anstelle einer einzigen Anfrage steht ein zentraler Orchesterer über einer Reihe von spezialisierten Sub-Agenten. Die Modelle müssen nicht identisch sein. Der stärkste Denker übernimmt Aufgaben, bei denen Urteilsvermögen wichtig ist (Orchestrierung und Qualitätsprüfung), während der schnellste und günstigste für Aufgaben eingesetzt wird, bei denen Geschwindigkeit entscheidend ist (Triage):

  • Orchesterer: plant und delegiert. Gemini 3.1 Pro. Seine Tools sind die Spezialisten-Agenten.
  • Triage-Agent: liest Stimmung und Absicht ein und leitet weiter. Gemini 3.1 Flash-Lite, unterstützt durch NLP-Klassifikatoren.
  • Forschungsagent: sammelt Fakten und Kontexte. Gemini 3.1 Flash mit Vertex-Suche sowie einer CRM-API.
  • Aktionsagent: führt Transaktionen wie Rückerstattungen und Aktualisierungen durch. Gemini 3.1 Flash mit Bestell- und Zahlungs-APIs.
  • QA-Agent: überprüft Fakten sowie die Einhaltung von Richtlinien. Gemini 3.1 Pro mit einer Richtlinien-Wissensdatenbank.
  • Gemini 2.5 Flash bleibt ein guter Allrounder für Prozesse mit einem einzigen Agenten. Wenn jedoch die Qualität der Argumentation Entscheidungen über den Ablauf bestimmt, eignet sich die Gemini 3.1-Serie (grundsätzlich seit Anfang 2026 verfügbar) besser, insbesondere für die Rollen des Orchestriers und der Qualitätskontrolle.

    Die beteiligten Google Cloud-Produkte sind:

    • Gemini 3.1-Modelle als Kern für die Argumentation, angepasst für den Einsatz von Tools.
    • Agent Development Kit als Framework, das Übertragungen über AutoFlow abwickelt.
    • Vertex AI Agent Engine als verwalteter Laufzeitumgebung zur Bereitstellung und Skalierung von Agenten.
    • Firestore als gemeinsamer Sitzungszustand, in dem Agenten Gesprächsdaten lesen und schreiben können.
    • Vertex AI Vector Search zur Suche in der Wissensdatenbank.

    Einrichtung von ADK

    ADK stellt die notwendige Infrastruktur bereit, einschließlich des Übergabemusters, mit dem ein Agent den Anruf effektiv an einen anderen übertragen kann. Die Installation erfolgt in nur einer Zeile:

    pip install google-adk google-generativeai google-cloud-firestore pydantic
    

    Pydantic wird ausdrücklich aufgelistet, weil ADK darauf angewiesen ist, um Schemata für Eingaben und Ausgaben der Agenten zu erstellen, und seine Angabe sorgt für kompatible Versionen.

    Über die Struktur des Projekts sollte man frühzeitig nachdenken. Mehr-Agentensysteme versagen am häufigsten an den Schnittstellen: Ein Agent sendet einen refund_id als Integer, während ein anderer einen String erwartet. Eine einfache Struktur mit gemeinsamen Schemata verhindert solche Fehler:

    support_agents/
    ├── main.py              # Entry point for Cloud Run
    ├── common/
    │   ├── __init__.py
    │   └── schemas.py       # Shared Pydantic models (the "handshake")
    ├── agents/
    │   ├── __init__.py
    │   ├── orchestrator.py
    │   ├── triage.py
    │   ├── research.py
    │   ├── action.py
    │   └── qa.py
    └── config.py            # Environment & project IDs
    

    Ein Krankenhaus ist eine passende Analogie. Der Orchesterleiter ist das Triage-Pflegepersonal, der Forschungsagent ist der Labortechniker und der Handlungsagent ist der Chirurg. Keiner von ihnen spricht gleichzeitig mit dem Patienten. Sie lesen und aktualisieren die Krankenakte des Patienten, die hier Firestore ist, und schemas.py ist das Format der Akte, auf dem sich alle einigen.

    Der Triage-Agent

    Triage fungiert wie die Flugverkehrsleitstelle. Sie löst nichts selbst, sondern sorgt lediglich dafür, dass jede Anfrage mit der richtigen Priorität zum richtigen Spezialisten gelangt.

    Das Übergeben von Rohstrings zwischen den Agenten führt zu Fehlern. Ein strenges Pydantic-Schema bedeutet, dass der Orchesterleiter ein validiertes Python-Objekt erhält und niemals freien Text analysieren muss. Zuerst kommt das Schema:

    # common/schemas.py
    from pydantic import BaseModel, Field
    
    class TriageResult(BaseModel):
        intents: list[str] = Field(description="List of detected customer goals")
        urgency: str = Field(pattern="^(low|medium|high|critical)quot;)
        sentiment: str = Field(description="Current emotional state of the user")
        required_agents: list[str] = Field(
            description="List of sub-agents needed (research, action, etc.)"
        )
    

    Dann der Agent, der es erzeugt:

    # agents/triage.py
    from google.adk.agents import LlmAgent
    from common.schemas import TriageResult
    
    triage_agent = LlmAgent(
        name="triage_agent",
        model="gemini-3.1-flash-lite",  # Fast and cheap for classification
        instruction="""You are a triage specialist. Analyze the customer's
        message and categorize it accurately.
    
        Urgency rules:
        - critical: Active outages or safety threats
        - high: Frustrated users or financial issues > $100
        - medium: Standard requests needing action
        - low: General info/feedback
    
        You must NOT attempt to solve the problem. Only classify it.""",
        output_schema=TriageResult,  # Force structured JSON output
        output_key="triage_data"
    )
    

    Vier Gestaltungsentscheidungen sind in dieser Definition wichtig:

    • Eine Aufgabe. Der Agent beantwortet niemals Fragen oder führt Aktionen aus, sondern klassifiziert nur. Dadurch bleibt die Anfrage kurz und die Genauigkeit hoch.
    • Gestrukturierte Ausgabe. output_schema erzwingt gültiges JSON, das TriageResult entspricht, und ADK überprüft es automatisch mithilfe von Pydantic.
    • Mehrere Absichten gleichzeitig. Da intents eine Liste von Zeichenketten ist, funktioniert eine Nachricht, die darum bittet, eine Adresse zu aktualisieren und gleichzeitig die neueste Rechnung zu prüfen, während ein Einzel-Label-Klassifikator versagen würde.
    • Übertragung des Zustands. output_key="triage_data" speichert das Ergebnis im Sitzungszustand, sodass der Orchestrierer es über session.state['triage_data'] abruft.

    Der Forschungsagent

    Der Forschungsagent ist der Ermittler. Er holt Rohdaten aus Firestore und dem Abrufprozess ab und fasst sie anschließend zu einem strukturierten Bericht für den Handlungsagenten zusammen. Das Schema dieses Berichts stellt den Vertrag zwischen diesen beiden Rollen dar:

    # common/schemas.py (add to existing file)
    
    class ResearchBrief(BaseModel):
        order_status: str = Field(description="Current order state")
        customer_tier: str = Field(description="e.g. Gold, Standard")
        applicable_policy: str = Field(description="Relevant policy text")
        can_refund: bool = Field(description="Whether a refund is allowed")
        reasoning: str = Field(description="Why this conclusion was reached")
    

    Danach folgen seine Tools und die Definition des Agents:

    # agents/research.py
    from google.adk.agents import LlmAgent
    from google.cloud import firestore
    from common.schemas import ResearchBrief
    
    db = firestore.Client()
    
    def lookup_order(order_id: str) -> dict:
        """Fetch real-time shipping status and line items for an order ID."""
        doc = db.collection('orders').document(order_id).get()
        if doc.exists:
            return doc.to_dict()
        return {"error": f"Order {order_id} not found"}
    
    def lookup_customer(customer_id: str) -> dict:
        """Retrieve customer profile, tier, and interaction history."""
        doc = db.collection('customers').document(customer_id).get()
        if doc.exists:
            return doc.to_dict()
        return {"error": f"Customer {customer_id} not found"}
    
    def search_knowledge_base(query: str) -> list:
        """Search product docs and company policies via RAG pipeline."""
        # Uses the RAG pipeline from our previous article
        from rag_pipeline import pipeline
        result = pipeline.query(query, top_k=5)
        return result['sources']
    
    research_agent = LlmAgent(
        name="research_agent",
        model="gemini-3.1-flash",
        instruction="""You are a research specialist.
        1. Extract identifiers (Order ID, Customer ID) from the triage data.
        2. Use tools to gather order history and relevant company policies.
        3. If policy info is missing, use search_knowledge_base.
    
        CRITICAL: Do not answer the customer. Output a formal ResearchBrief.""",
        tools=[lookup_order, lookup_customer, search_knowledge_base],
        output_schema=ResearchBrief,
        output_key="research_brief"
    )
    

    Der State wird ohne zusätzlichen Code übertragen. Wenn der Forschungsagent gestartet wird, injiziert ADK triage_data aus dem vorherigen Schritt in seinen Kontext, sodass er bereits weiß, dass er nach der Bestellung mit der Nummer 12345 suchen muss, da die Triage diese Absicht erkannt hat. Jeder Agent baut auf der Arbeit des vorherigen auf, und nichts wird zweimal erledigt. Ein kleiner Produktions-Tipp: ADK umhüllt einfache Funktionen automatisch als FunctionTool-Objekte, doch ihre explizite Umhüllung mit from google.adk.tools import FunctionTool führt zu einer besseren Latenzverfolgung sowie zum Protokollieren der Tokennutzung im Vertex AI Agent Engine.

    Der Aktion-Agent

    Nur dieser Spezialist hat Schreibzugriff auf die Geschäfts-APIs. Da er hochriskante Operationen durchführt, gelten für ihn strenge Schemata sowie klare Richtlinien. Zunächst das Ausgabeschema:

    # common/schemas.py (add to existing file)
    
    class ActionSummary(BaseModel):
        actions_taken: list[str] = Field(description="List of actions executed")
        refund_id: str | None = Field(default=None, description="Refund ID if issued")
        escalated: bool = Field(default=False)
        escalation_reason: str | None = Field(default=None)
    

    Dann das Agent selbst, das bei wertvollen Transaktionen eine menschliche Bestätigung anfordert:

    # agents/action.py
    from google.adk.agents import LlmAgent
    from google.adk.tools import FunctionTool
    from common.schemas import ResearchBrief, ActionSummary
    
    def process_refund(order_id: str, amount: float, reason: str) -> dict:
        """Process a financial refund. Required: valid order_id and amount."""
        # In production: call your payment API
        return {
            "status": "processed",
            "refund_id": f"REF-{order_id}",
            "amount": amount
        }
    
    def create_replacement_order(
        order_id: str,
        item_id: str,
        shipping_speed: str
    ) -> dict:
        """Create a replacement order with specified shipping speed."""
        # In production: call your order management API
        return {
            "status": "created",
            "new_order_id": f"REPL-{order_id}",
            "estimated_delivery": "2 business days"
        }
    
    def escalate_to_human(reason: str, priority: str) -> dict:
        """Escalate to a human agent with full context."""
        return {
            "status": "escalated",
            "queue": "priority" if priority == "high" else "standard"
        }
    
    # Wrap refund tool with human confirmation for high-value transactions
    refund_tool = FunctionTool(
        func=process_refund,
        require_confirmation=True  # Pauses for human approval before executing
    )
    
    action_agent = LlmAgent(
        name="action_agent",
        model="gemini-3.1-flash",
        instruction="""You are an action specialist.
        Review the 'research_brief' in the session state.
    
        CRITICAL RULES:
        1. Only refund if 'can_refund' is True in the research brief
        2. If amount > $500, you MUST use escalate_to_human
        3. You must call tools for every action — do not just tell the user
           it happened
        4. If information is missing from the brief, escalate""",
        tools=[refund_tool, create_replacement_order, escalate_to_human],
        input_schema=ResearchBrief,   # Only sees research data, not raw chat
        output_schema=ActionSummary,
        output_key="action_result"
    )
    

    Zwei Einstellungen tragen den größten Teil zur Sicherheit bei. require_confirmation existiert, weil ein Produktivsystem selten einem Agenten erlaubt, allein aufgrund von Anweisungen im Prompt einen Rückerstattungsvorgang durchzuführen. ADKs Tool zur Bestätigung hält die Ausführung bis zu einer menschlichen Genehmigung an und zeigt dem Orchestrierer einen „pending“-Status, den er auf ein Mitarbeiter-Dashboard weiterleiten kann. input_schema ist wichtig, da der Agent ohne es den gesamten Dialog inklusive veralteter Nachrichten sehen würde. Die Einschränkung der Eingaben auf ResearchBrief verhindert, dass veralteter Kontext eindringt, und stellt sicher, dass Entscheidungen auf den aktuellsten Daten beruhen.

    Bemerken Sie außerdem, dass escalate_to_human eine bewusste Geschäftsregel und kein Fehlerzustand ist. Der Orchestrierer kann genau erkennen, warum der Agent aufgehört hat, und das Ticket zusammen mit dem vollständigen Research Brief an eine Person weiterleiten.

    Der QA-Agent

    QA ist die letzte Kontrollstufe. Neben der Überprüfung der Formulierungen vergleicht sie das, was der Handlungsagent getan hat, mit dem Inhalt des Forschungsauftrags, damit Handeln mit Wissen übereinstimmt.

    Diese Funktion läuft auf Gemini 3.1 Pro, da sie den gesamten Gesprächsverlauf im Gedächtnis behalten und feine Widersprüche erkennen muss – Aufgaben, bei denen Pro konsequent besser abschneidet als Flash. ADK ermöglicht es außerdem, den Denkmodus zur tieferen Selbstreflexion vor der Freigabe einer Antwort zu nutzen. Das Überprüfungs Schema:

    # common/schemas.py (add to existing file)
    
    class QAReview(BaseModel):
        is_approved: bool = Field(description="True if the response meets all criteria")
        feedback: str = Field(description="Specific corrections if not approved")
        final_text: str = Field(description="The customer-facing message")
    

    Und die Agent-Konfiguration:

    # agents/qa.py
    from google.adk.agents import LlmAgent
    from google.adk.planners import BuiltInPlanner
    from google.genai.types import ThinkingConfig
    from common.schemas import QAReview
    
    qa_agent = LlmAgent(
        name="qa_agent",
        model="gemini-3.1-pro",
        instruction="""You are a senior QA auditor. Compare the 'action_result'
        against the 'research_brief' in the session state.
    
        CRITICAL CHECKS:
        1. Did the Action Agent refund the EXACT amount listed in the brief?
        2. Does the response cite the policy found during research?
        3. Is the tone empathetic but professional?
        4. Are ALL intents from the triage classification addressed?
        5. No unauthorized promises, discounts, or policy exceptions
    
        If any check fails, set is_approved to False with specific feedback.""",
        output_schema=QAReview,
        output_key="qa_review",
        # MEDIUM for routine QA; switch to HIGH for edge cases or audits
        planner=BuiltInPlanner(
            thinking_config=ThinkingConfig(thinking_level="MEDIUM")
        )
    )
    

    Die Ablehnung beendet den Prozess nicht. Wenn qa_review.is_approved falsch ist, liest der Orchesterer das feedback-Feld und leitet die Anfrage mit konkreten Korrekturen zurück an den jeweiligen Agenten oder Forschungsagenten. Dieser Korrekturzyklus ist es, der einen Produktionsagenten von einem Demo-Skript unterscheidet. Er ist auf zwei Überarbeitungsrunden beschränkt, danach wird der Fall an einen Menschen weitergeleitet.

    Der Orchesterer

    Der Orchesterer führt weder Forschungen durch noch handelt er selbst. Er verwaltet den Zustand und sorgt dafür, dass die Spezialisten in einer sinnvollen Reihenfolge arbeiten. Unter Verwendung von sub_agents fügt ADKs AutoFlow das Tool transfer_to_agent() hinzu, und der LLM des Orchesterers wählt den nächsten Spezialisten anhand seiner Anweisungen sowie des aktuellen Sitzungszustands aus:

    # agents/orchestrator.py
    from google.adk.agents import LlmAgent
    from agents.triage import triage_agent
    from agents.research import research_agent
    from agents.action import action_agent
    from agents.qa import qa_agent
    
    orchestrator = LlmAgent(
        name="support_orchestrator",
        model="gemini-3.1-pro",  # Best reasoning for delegation decisions
        instruction="""You are the lead coordinator of a customer support team.
        Use the following specialists in order:
        1. triage_agent: to classify the intent and urgency
        2. research_agent: to gather order data and relevant policies
        3. action_agent: to execute the required operations
        4. qa_agent: to verify the final response
    
        Special cases:
        - If triage classifies as 'critical': bypass the chain and escalate
        - If QA returns is_approved=False: re-route to the responsible agent
          with the feedback (maximum 2 revision cycles, then escalate)
        - If any agent fails: escalate to human with full context
    
        You must never respond to the customer directly.
        Always route through the specialist pipeline.""",
        sub_agents=[triage_agent, research_agent, action_agent, qa_agent]
    )
    

    Ausführen

    ADK führt Agenten über einen Runner aus, der die Ausführung pausiert, sobald ein Agent ein Tool aufruft, und den Agenten anschließend wieder startet, sobald das Ergebnis zurückgekehrt ist:

    # main.py
    from google.adk.runners import Runner
    from google.adk.sessions import InMemorySessionService
    from agents.orchestrator import orchestrator
    
    APP_NAME = "customer_support"
    USER_ID = "system"
    
    # For production, replace with a Firestore-backed session service
    session_service = InMemorySessionService()
    
    runner = Runner(
        agent=orchestrator,
        app_name=APP_NAME,
        session_service=session_service
    )
    
    async def handle_customer_message(customer_id: str, message: str):
        """
        Entry point for customer messages.
        """
        session_id = f"support-{customer_id}"
    
        # Ensure session exists
        session = await session_service.get_session(
            app_name=APP_NAME, user_id=USER_ID, session_id=session_id
        )
        if not session:
            session = await session_service.create_session(
                app_name=APP_NAME, user_id=USER_ID, session_id=session_id
            )
    
        # run_async yields events as agents execute
        final_response = None
        async for event in runner.run_async(
            user_id=USER_ID,
            session_id=session_id,
            new_message=message
        ):
            if event.is_final_response():
                final_response = event
    
        return {
            "response": final_response.content.parts[0].text if final_response else None,
            "session_id": session_id
        }
    

    Warum nicht die Agenten direkt anrufen? Der Runner übernimmt den gesamten Ablauf. Er speichert Sessions, verfolgt den aktiven Agenten, verarbeitet Toolaufrufe und protokolliert jeden Schritt. Da jeder Agent seine Ausgabe unter einem output_key speichert, garantiert der Runner, dass das Forschungsprofil bereitsteht, wenn es vom Handlungsagenten benötigt wird – ohne manuelle Anpassungen. Die Nachvollziehbarkeit ist außerdem inklusive: Jeder Agentenaufruf, jede Toolnutzung sowie jeder Übergabeprozess wird als Ereignis protokolliert, was die zuvor geäußerte Problematik bei der Fehlersuche löst. Wenn etwas schiefgeht, zeigt die Spur an, welcher Agent was und warum entschieden hat.

    Implementierungswege

    Es gibt zwei Möglichkeiten, es einzusetzen. Vertex AI Agent Engine bietet eine verwaltete Laufzeitumgebung, bei der fast nichts bedient werden muss, während Cloud Run volle Kontrolle über den Container bietet.

    Agent Engine

    Das ist der wartungsarme Ansatz, der für die meisten ADK-eigenen Konfigurationen empfohlen wird. Legen Sie zwei Variablen fest:

    PROJECT_ID=your-project-id
    LOCATION_ID=us-central1
    

    Dann führen Sie mit einem Befehl den Deploy durch:

    adk deploy agent_engine \
      --project=$PROJECT_ID \
      --region=$LOCATION_ID \
      --display_name="Customer Support Team" \
      support_agents
    

    Agent Engine kümmert sich um Skalierung, Session-Persistenz sowie tracebasiertes Logging, das die Eigenschaften der Agenten berücksichtigt. Es gibt keinen Dockerfile, keinen Session-Code und keine Infrastruktur, die betreut werden muss.

    Cloud Run

    Wählen Sie diese Option, wenn benutzerdefinierte Systembibliotheken, spezielle Netzwerklösungen wie VPC Service Controls oder Komponenten außerhalb des ADK erforderlich sind. Im Beispiel wird statt Flask Quart verwendet. Die Syntax ist nahezu identisch, doch Quart handhabt async/await nativ, wodurch das Anti-Muster asyncio.run() vermieden wird – bei dem für jede Anfrage ein neuer Event-Loop gestartet wird:

    # server.py
    from quart import Quart, request, jsonify
    from main import handle_customer_message
    
    app = Quart(__name__)
    
    @app.route("/support", methods=["POST"])
    async def support():
        data = await request.get_json()
        # No asyncio.run needed — Quart handles the event loop
        result = await handle_customer_message(
            data["customer_id"],
            data["message"]
        )
        return jsonify(result)
    
    @app.route("/health", methods=["GET"])
    async def health():
        return jsonify({"status": "healthy"})
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8080)
    

    Die Container-Definition:

    # Dockerfile
    FROM python:3.11-slim
    
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY . .
    EXPOSE 8080
    
    CMD ["python", "server.py"]
    

    Und der Deploy-Befehl:

    gcloud run deploy support-agents \
      --source . \
      --region us-central1 \
      --memory 4Gi \
      --cpu 2 \
      --allow-unauthenticated
    

    Kurz gesagt erfordert Cloud Run eine mittlere Menge an Einrichtungsaufwand (einen Dockerfile und eine API), benötigt eine manuelle Zustandsverwaltung mit Firestore oder Redis, protokolliert in das Standard-Cloud Logging und eignet sich für benutzerdefinierte Laufzeiten sowie Frameworks. Agent Engine benötigt nur einen Befehl, verfügt über integrierte Sessions, erzeugt agentenspezifische Spuren und eignet sich für ADK-native Agenten, die schnell skaliert werden müssen.

    Aufrechterhaltung von Konversationen

    Das Orchestrator-Beispiel nutzte InMemorySessionService, was für Tests in Ordnung ist, aber alles verliert, wenn der Prozess neu gestartet wird. In der Produktion ist ein dauerhafter Service erforderlich. ADK bietet zwei solcher Dienste.

    Mit Agent Engine werden Sessions über den Vertex AI Session Service für Sie verwaltet:

    # config.py
    from google.adk.sessions import VertexAiSessionService
    
    session_service = VertexAiSessionService(
        project="your-project-id",
        location="us-central1",
        agent_engine_id="your-agent-engine-id"  # From adk deploy output
    )
    

    Agent Engine fasst außerdem lange Historien zusammen und kümmert sich selbst um die Aufbereitung, sodass kein Firestore-Code erforderlich ist.

    Für Cloud Run funktioniert DatabaseSessionService mit einem PostgreSQL- oder SQLite-Backend:

    # config.py
    from google.adk.sessions import DatabaseSessionService
    
    # PostgreSQL for production
    session_service = DatabaseSessionService(
        db_url="postgresql+asyncpg://user:pass@host:5432/agents"
    )
    
    # Or SQLite for development
    session_service = DatabaseSessionService(
        db_url="sqlite+aiosqlite:///sessions.db"
    )
    

    Es erstellt seine Tabellen beim ersten Start. Wenn es in den Runner eingebettet wird, bleibt der Sitzungszustand auch nach Neustarts erhalten.

    Wie der Zustand zwischen Agenten übertragen wird

    Es sind keine manuellen get()- und set()-Aufrufe erforderlich. Jeder Agent schreibt automatisch mit seinem output_key in den Sitzungszustand, und späteren Agenten steht dieser dort zur Verfügung:

    triage_agent (output_key="triage_data")
        ↓ writes to session.state["triage_data"]
    research_agent (reads triage_data, output_key="research_brief")
        ↓ writes to session.state["research_brief"]
    action_agent (input_schema=ResearchBrief, output_key="action_result")
        ↓ writes to session.state["action_result"]
    qa_agent (reads action_result + research_brief, output_key="qa_review")
    

    Der Runner speichert diesen gesamten Zustand bei dem konfigurierten Backend – egal ob Firestore, PostgreSQL oder Agent Engine.

    Drei Gewohnheiten halten den Speicher gesund:

    • Zusammenfassen. Speichern Sie gekürzte Ergebnisse anstelle von rohen API-Antworten, sonst füllt sich das Kontextfenster mit Überflussdaten.
    • Sessions ablaufen lassen. Support-Sessions sollten eine Gültigkeitsdauer von 24 bis 48 Stunden haben, damit die Datenbank kleiner und sicherer bleibt.
    • Persönliche Daten schützen. Rohdaten wie Personalausweisnummern oder Passwörter gehören nicht in den gemeinsamen Zustand; sie sollten daher maskiert werden, bevor etwas in die Session geschrieben wird.

    Wann ein einzelner Agent immer noch die bessere Lösung ist

    Mehr-Agenten-Systeme sind nicht automatisch überlegen. Eine praktische Entscheidungshilfe:

    • Einfache FAQ oder Statusüberprüfung: Einzelagent. Geringste Latenz und Kosten, kein komplexes Denken erforderlich.
    • Datenerweiterung durch drei bis fünf Abfragen: Einzelagent. Ein einziger Aufruf des LLM reicht aus, um die grundlegende Nutzung der Tools zu bewältigen.
    • Geregelte Arbeitsabläufe: Mehrere Agenten. Die Isolierung hält die Ablauflogik von den Benutzereingaben getrennt, was eine Eingabe von Manipulationsbefehlen erschwert.
    • Unklare Routen: Mehrere Agenten. Ein spezieller Triage-Agent, der sich auf die Zuordnung von Absichten spezialisiert hat, verringert die Auswirkungen von Einschränkungen.
    • Wichtige Aktionen im Wert von über 500 Dollar: Mehrere Agenten. Es wird eine doppelte Überprüfung durch einen QA-Agenten vor jedem API-Aufruf ermöglicht.
    • Auditspezifikationen: Mehrere Agenten. Die Eingaben und Ausgaben jedes Agenten werden getrennt protokolliert.

    Eine Faustregel: Wenn ein Prompt für einen einzelnen Agenten bei etwa 3.000 Tokens ankommt – dem Punkt, an dem Einschränkungen zu Problemen führen und die Aufmerksamkeit des Modells nachlässt – oder wenn verschiedene Teile des Arbeitsablaufs unterschiedliche Tools erfordern, ist es an der Zeit, den Agenten aufzuteilen.

    Häufige Fallstricke

    • Der „Alleskönner-Agent“. Die Leistung sinkt, sobald ein Agent zehn oder mehr Tools besitzt, da die Modelle ihre Energie stattdessen darauf verwenden, ein Tool auszuwählen, anstatt die Anfrage zu verstehen. Teilen Sie den Agenten nach Funktionen auf: Ein Agent, der Rückzahlungen, Versand und rechtliche Aspekte handhaben muss, wird in drei Spezialisten aufgeteilt.
    • Ausufernder Kontext. Wenn jeder Agent die gesamte zehn-Schritte umfassende Konversation sieht, steigen die Tokenkosten enorm an. Komprimieren Sie den Zustand, sodass nur die erkannte Absicht weitergeleitet wird und nicht die gesamte Konversation.
  • Endlose Weiterleitungen. Agent A sendet an B, der es wieder an A zurücksendet – wodurch Token im Kreis verbraucht werden. Geben Sie dem Orchesterer einen maximalen Weiterleitungs-Zähler; zwei Zyklen vor der Eskalation durch einen Menschen funktioniert das gut.
  • Unklare Grenzen. Zwei Agenten übernehmen dieselbe Aufgabe oder eine Aufgabe fällt zwischen ihnen. Definieren Sie explizite input_schema- und output_schema-Verträge ohne überschneidende Aufgaben.
  • Ignorieren der Latenz. Ein sequenzieller Ablauf fügt 4 bis 6 Sekunden hinzu, während ein einzelner Agent nur 1 bis 2 Sekunden benötigt. ADKs ParallelAgent verteilt die Arbeit unabhängig voneinander, und das Parallelausführen von Forschungs- sowie Konformitätsprüfungen kann 30 bis 40 Prozent der Gesamtlatenz reduzieren.
  • Was man davon erwarten kann

    Mehr-Agenten-Systeme tauschen Latenz gegen Zuverlässigkeit bei komplexen Aufgaben ein. Veröffentlichte Benchmarks sowie Branchenerfahrungen weisen auf diese Stärken hin:

    • Genauigkeit bei komplexen Aufgaben. Das Zerlegen mehrschrittiger Probleme in fokussierte Unteraufgaben bringt in der Regel bessere Ergebnisse als monolithische Anfragen, und die Dokumentation von ADK weist auf höhere Abschlussraten hin, wenn Agenten spezifische Aufgaben haben.
    • Eingegrenzte Fehler. Wenn ein Komponente versagt, bleibt der Schaden auf diesem Agent beschränkt und zerstört nicht die gesamte Antwort.
    • Auditorierbarkeit. Getrennte Protokolle pro Agent erleichtern das Debuggen sowie die Einhaltung von Vorgaben.

    Auch die Kosten sind real:

    • Verzögerung. Ein vollständiger Prozess mit fünf Agenten dauert in der Regel 3 bis 8 Sekunden, während ein einzelner Agent nur 1 bis 2 Sekunden benötigt. Sequenzielle Aufrufe stellen das Hauptengpass dar.
  • API-Kosten. Fünf Agenten (ein Orchestrierer und vier Spezialisten) kosten etwa vier bis fünfmal so viel wie ein Agent pro Abfrage, wobei die Modellkombination dies in Schach hält. Die Triage mit Flash-Lite kostet 0,25 US-Dollar pro Million Eingabetoken, während Pro bei 2 US-Dollar pro Million für Orchestrierung und QA reserviert ist, wodurch die Gesamtkosten pro Interaktion unter einem Cent bleiben.
  • Denk-Token. Das erweiterte Denken in Pro (thinking_level="HIGH") kann etwa 20.000 Token hinzufügen, wofür ein Entgelt von 12 US-Dollar pro Million Ausgabe-Token anfällt. Eine umfassende QA-Überprüfung kostet daher allein für das Denken etwa 0,24 US-Dollar. Verwenden Sie „HIGH“ selektiv, da die meisten QA-Prüfungen mit „MEDIUM“ ausreichen.
  • Komplexität. Es gibt mehr zu überwachende Komponenten. Dies lohnt sich bei komplexen Workflows, ist aber für einfache Fälle übertrieben.
  • Für eine ungefähre monatliche Rechnung bei 100.000 komplexen Abfragen:

    • Orchestrator-Routing auf Gemini 3.1 Pro: etwa 80 Dollar
    • Triage mit Flash-Lite: etwa 20 Dollar
    • Forschung zu Flash: etwa 40 Dollar
    • Aktionen mit Flash: etwa 40 Dollar
    • QA mit MEDIUM-Thinking auf Pro: etwa 100 Dollar
    • Cloud Run mit 2 vCPU und 2 GiB: etwa 120 Dollar
    • PostgreSQL-Sessions: etwa 30 Dollar
    • Vector Search in Kombination mit einer Ein-Agenten-Einrichtung: etwa 100 Dollar
    • Gesamt: etwa 530 Dollar pro Monat

    Die Kombination von Modellen ist der eigentliche Kostenfaktor. Nur etwa 30 Prozent der Anfragen (Orchestrator und QA) fallen unter die Pro-Preise, während der Rest auf Flash oder Flash-Lite läuft – zu einem Achtel bis Fünfzigstel des Preises pro Token. Die Einheitskosten für eine komplexe Interaktion betragen etwa einen halben Cent. Diese Zahlen stammen aus den veröffentlichten Preisen von Google Cloud; tatsächliche Rechnungen variieren je nach Komplexität der Abfragen, dem Denklevel sowie der Tiefe der Agentenanrufe.

    Reihenfolge der Einführung

    Die sinnvolle Reihenfolge besteht darin, mit einem einzelnen Agenten zu beginnen, seine Logik anzupassen, ihn durch Informationsabruf zu stützen und erst dann in Spezialisten aufzuteilen, wenn der Systemprompt zu lang wird oder die Aufgaben zu vielfältig sind, um von einem einzigen Modell zuverlässig bewältigt zu werden. Jede Schicht baut auf der darunterliegenden auf.

    Der Zeitpunkt für Microservices bei Agenten

    Das Mehr-Agenten-Design macht KI nicht komplizierter. Es macht komplexe Arbeitsabläufe vorhersehbar – genauso wie Microservices den Monolithen ersetzt haben: Ein Prompt wird zu einer verteilten Ansammlung von Komponenten, von denen jede eine bestimmte Aufgabe erledigt. Von einem einzelnen Agenten zu verlangen, gleichzeitig zu sortieren, zu recherchieren, zu handeln und zu prüfen, ist wie von einer Person zu verlangen, gleichzeitig Empfangsdame, leitende Analystin, Technikerin und Prüferin zu sein. Das funktioniert in einem Ein-Mann-Unternehmen, scheitert aber in einem großen Unternehmen.

    Geben Sie jedem Agenten eine fokussierte Aufgabe, spezialisierte Tools sowie eine gemeinsame Speicherschicht – das Ergebnis ist präzise, denn fokussierte Anweisungen verursachen weniger Abweichungen bei unzusammenhängenden Aufgaben; es lässt sich debuggen, da der fehlerhafte Spezialist sichtbar ist; und es ist kostengünstig, denn ein Einsatz von fünf Agenten auf Gemini 3.1 kostet etwa einen halben Cent pro komplexer Interaktion, was weit unter einer Minute der Arbeitszeit eines menschlichen Agenten liegt.

    Das Design bietet außerdem Raum für weitere Entwicklungen. Mit dem Agent-to-Agent (A2A)-Protokoll, einem offenen Standard unter der Verwaltung der Linux Foundation, könnte ein solches System letztendlich mit von Anbietern oder Partnern betriebenen Agenten verhandeln – beispielsweise könnte ein Support-Agent direkt mit dem Agenten eines Versanddienstleisters kommunizieren, um ein verlorenes Paket ohne menschliche Beteiligung zu lösen.

    Für den Moment lautet der Rat einfach: Bauen Sie zunächst einen Agenten und zerlegen Sie das System, wenn die Anweisungen zu lang oder die Aufgaben zu vielfältig werden.