Inicio / Artículos

Un mostrador de soporte con cinco agentes basado en Gemini 3.1 y ADK: triaje, investigación, acción, control de calidad y orquestador.

Construir un sistema de soporte al cliente con múltiples agentes utilizando Google ADK y Gemini 3.1: transferencias por escritura, bucles de corrección de calidad, Agent Engine o Cloud Run, sesiones y costos.

Editor: REACTAPP.TOP19 min de lectura4349 palabras

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

Imagínese un pedido que ha salido mal. Un cliente escribe que llegó el artículo incorrecto, pide un reembolso y también desea que se envíe el artículo correcto el mismo día. Detrás de esa sola oración hay tres tareas: verificar el pedido, procesar la devolución y enviar rápidamente un reemplazo. Cada una necesita sus propios datos, su propia política y su propia acción. Un bot de soporte solitario con una sola instrucción extensa puede manejar una pregunta sencilla, pero tiende a tropezar cuando varias tareas se entrelazan. Se vuelve lento, frágil y propenso a errores.

La solución es un diseño multiagente: varios especialistas, cada uno a cargo de una parte del flujo de trabajo, con un orquestador que dirige el tráfico. A continuación se explica cómo implementar esto en Google Cloud utilizando los modelos Gemini 3.1 y el Kit de Desarrollo de Agentes (ADK) de Google. Se aborda cómo definir roles para los agentes con límites claros, cómo el orquestador enruta tareas, delega responsabilidades y reúne resultados, cómo los agentes intercambian información entre sí, y, lo que es igualmente importante, cuándo seguir optando por un solo agente.

Qué sucede cuando se usa una sola instrucción extensa

Imagínese a un agente de soporte que comenzó con funciones básicas y fue adquiriendo más capacidades: recuperación de información desde una base de conocimientos, un tono más amable con los clientes molestos, y la posibilidad de autoevaluarse. Su instrucción de sistema llega a superar los 3,000 tokens, y cada adición interfiere con algo ya existente. Aparecen cuatro síntomas:

  • Fuga de recursos por restricciones. Las reglas de reembolso comienzan a aplicarse a preguntas que no tienen nada que ver con ellos, por lo que una simple consulta sobre un producto recibe respuesta mediante la lógica de devoluciones.
  • Atención diluida. La capacidad de atención de un modelo es limitada. Al distribuirla entre docenas de instrucciones, la mayoría de las cuales son irrelevantes para la consulta en cuestión, se le da menos importancia a cada una.
  • Debugaje imposible. Cuando la respuesta es incorrecta, no queda claro cuál de las muchas instrucciones la causó.
  • Solo un camino para todo. Cada consulta pasa por el mismo proceso, independientemente de su dificultad.

Al dividir el trabajo, cada modelo dispone de todo su presupuesto de atención para la tarea que tiene entre manos. Solo piensa en la política de reembolso al procesarlos y solo en el tono al revisar un borrador.

ADK está diseñado en torno a esta idea. Su mecanismo AutoFlow gestiona las transferencias entre especialistas: cuando un orquestador cuenta con subagentes, ADK agrega una herramienta transfer_to_agent() y escribe descripciones de cada especialista disponible en su contexto. De este modo, el orquestador sabe quién forma parte de su equipo y para qué es bueno cada miembro.

Forma del sistema

En lugar de un único comando, existe un orquestador central que dirige a un conjunto de subagentes especializados. No es necesario que los modelos sean idénticos. El razonador más capaz se encarga de las tareas que requieren juicio (orquestación y revisión de calidad), mientras que el más rápido y económico se ocupa de aquellas donde la velocidad es clave (triage):

  • Orquestador: planifica y delega tareas. Gemini 3.1 Pro. Sus herramientas son los agentes especialistas.
  • Agente de triage: analiza el sentimiento y la intención para redirigir las solicitudes. Gemini 3.1 Flash-Lite, respaldado por clasificadores de NLP.
  • Agente de investigación: recopila hechos y contexto. Gemini 3.1 Flash, con búsqueda Vertex y una API de CRM.
  • Agente de acción: realiza transacciones como reembolsos y actualizaciones. Gemini 3.1 Flash, con APIs de pedidos y pagos.
  • Agente de control de calidad: verifica los hechos y el cumplimiento de las políticas. Gemini 3.1 Pro, con una base de conocimientos sobre políticas.
  • Gemini 2.5 Flash sigue siendo una opción sólida para flujos con un solo agente. Sin embargo, cuando la calidad del razonamiento determina las decisiones de enrutamiento, la línea Gemini 3.1 (disponible generalmente desde principios de 2026) es más adecuada, especialmente en los roles de orquestador y control de calidad.

    Los componentes de Google Cloud involucrados:

    • Modelos Gemini 3.1 como núcleo de razonamiento, ajustados para el uso de herramientas.
    • Agent Development Kit como marco que gestiona las transferencias mediante AutoFlow.
    • Vertex AI Agent Engine como entorno de ejecución gestionado para desplegar y escalar agentes.
    • Firestore como estado de sesión compartido donde los agentes leen y escriben la memoria de las conversaciones.
    • Vertex AI Vector Search para realizar búsquedas en la base de conocimientos.

    Configuración de ADK

    ADK proporciona la estructura necesaria, incluido el patrón de transferencia mediante el cual un agente puede pasar eficazmente la llamada a otro. La instalación se realiza en una sola línea:

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

    Pydantic se menciona explícitamente porque ADK depende de él para los esquemas de entrada y salida de los agentes, y nombrarlo así mantiene compatibles las versiones.

    El diseño del proyecto merece ser planificado desde el principio. Los sistemas multiagente suelen fallar en las conexiones entre componentes: un agente envía un refund_id como número entero mientras que el siguiente espera una cadena de texto. Un diseño estructurado con esquemas compartidos evita ese tipo de errores:

    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
    

    Un hospital es una analogía adecuada. El orquestador es la enfermera de triaje, el agente de investigación es el técnico de laboratorio y el agente que realiza la acción es el cirujano. Ninguno de ellos habla con el paciente al mismo tiempo. Leen y actualizan la historia clínica del paciente, que en este caso es Firestore, y schemas.py es el formato de la historia clínica con el que todos están de acuerdo.

    El agente de triaje

    El triaje funciona como el control de tráfico aéreo. No resuelve nada por sí mismo, sino que se asegura simplemente de que cada solicitud llegue al especialista adecuado con la prioridad correcta.

    Transferir cadenas de texto sin procesar entre los agentes puede causar errores. Un esquema estricto de Pydantic garantiza que el orquestador reciba un objeto de Python validado y nunca tenga que analizar texto libre. El esquema viene primero:

    # 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.)"
        )
    

    Luego, el agente que lo produce:

    # 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"
    )
    

    Hay cuatro opciones de diseño importantes en esa definición:

    • Una sola tarea. El agente nunca responde preguntas ni toma acciones, solo clasifica. Esto mantiene el prompt breve y la precisión alta.
    • Salida estructurada. output_schema obliga a que se genere JSON válido que coincida con TriageResult, y ADK lo valida automáticamente mediante Pydantic.
    • Varias intenciones a la vez. Dado que intents es una lista de cadenas, un mensaje que solicita actualizar una dirección y también verificar la última factura funciona, algo que un clasificador de una sola etiqueta no lograría.
    • Transferencia de estado. output_key="triage_data" guarda el resultado en el estado de la sesión, de modo que el orquestador lo lee desde session.state['triage_data'].

    El agente de investigación

    El agente de investigación es el investigador. Extrae datos brutos de Firestore y del pipeline de recuperación, y luego los condensa en un resumen estructurado para el agente de acción. El esquema de dicho resumen constituye el contrato entre estas dos funciones:

    # 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")
    

    A continuación vienen sus herramientas y la definición del agente:

    # 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"
    )
    

    El estado se transmite sin código adicional. Cuando el agente de investigación se inicia, ADK inyecta triage_data del paso anterior en su contexto, de modo que ya sabe que debe buscar el pedido 12345 porque la clasificación identificó esa intención. Cada agente se basa en el trabajo del anterior y nada se realiza dos veces. Un pequeño consejo de producción: ADK envuelve automáticamente las funciones simples en objetos FunctionTool, pero envolverlas explícitamente con from google.adk.tools import FunctionTool permite un mejor seguimiento de la latencia y registro del uso de tokens en Vertex AI Agent Engine.

    El agente de acciones

    Solo este especialista tiene acceso de escritura a las APIs empresariales. Dado que realiza operaciones de alto riesgo, cuenta con esquemas estrictos y restricciones claras. El esquema de salida primero:

    # 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)
    

    Luego está el propio agente, que solicita confirmación humana para operaciones de alto valor:

    # 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"
    )
    

    Dos configuraciones son las que garantizan la mayor parte de la seguridad. require_confirmation existe porque un sistema en producción rara vez permite que un agente realice un reembolso basándose únicamente en instrucciones inmediatas. El flujo de confirmación de la herramienta de ADK pausa la ejecución hasta que una persona da su aprobación, y el orquestador ve un estado “pendiente” que puede redirigir a un panel de control del personal. input_schema es importante porque, sin él, el agente ve toda la conversación, incluidas las interacciones obsoletas. Al restringir la entrada a ResearchBrief, se evita que entre contexto antiguo y las decisiones se basan en los datos más recientes.

    También hay que tener en cuenta que escalate_to_human es una regla de negocio deliberada y no un estado de fallo. El orquestador puede ver con precisión por qué el agente se detuvo y enviar la solicitud a una persona junto con el resumen completo de la investigación.

    El agente de control de calidad

    La verificación de calidad es la última etapa. Además de comprobar el redactado, compara lo que hizo el agente en acción con lo indicado en el resumen de la investigación, para asegurarse de que las acciones realizadas coincidan con lo conocido.

    Esta función opera en Gemini 3.1 Pro, ya que debe mantener en mente todo el estado de la conversación y detectar contradicciones sutiles, tareas en las que Pro supera consistentemente a Flash. ADK también le permite utilizar el modo de reflexión para una autoevaluación más profunda antes de aprobar una respuesta. El esquema de revisión:

    # 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")
    

    Y la configuración del agente:

    # 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")
        )
    )
    

    El rechazo no pone fin al proceso. Cuando qa_review.is_approved es falso, el orquestador lee el campo feedback y redirige la tarea al agente correspondiente con correcciones concretas. Este ciclo de correcciones es lo que diferencia a un agente en producción de un script de demostración. Está limitado a dos ciclos de revisión; después de eso, el caso pasa a ser manejado por una persona.

    El orquestador

    El orquestador ni investiga ni actúa. Se encarga de gestionar el estado y asegurarse de que los especialistas trabajen en un orden lógico. Dado sub_agents, AutoFlow de ADK incluye la herramienta transfer_to_agent(), y el LLM del orquestador selecciona al siguiente especialista según sus instrucciones y el estado actual de la sesión:

    # 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]
    )
    

    Ejecutarlo

    ADK ejecuta a los agentes a través de un Runner, el cual suspende la ejecución cada vez que un agente invoca una herramienta y vuelve a iniciar al agente una vez que se obtiene el resultado:

    # 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
        }
    

    ¿Por qué no llamar directamente a los agentes? El Runner controla todo el proceso: mantiene activas las sesiones, rastrea al agente en uso, procesa las llamadas a herramientas y registra cada paso. Dado que cada agente escribe su salida bajo una output_key, el Runner garantiza que la información necesaria para la investigación esté disponible cuando el agente de acción la requiera, sin necesidad de escribir código adicional a mano. La trazabilidad también se incluye de forma automática: cada llamada a un agente, uso de herramienta o transferencia de tareas se registra como un evento, lo que resuelve los problemas de depuración mencionados anteriormente. Cuando surge algún problema, el historial muestra qué agente tomó qué decisión y por qué.

    Rutas de despliegue

    Existen dos formas de implementarlo. Vertex AI Agent Engine ofrece un entorno gestionado con casi cero mantenimiento, mientras que Cloud Run brinda control total sobre el contenedor.

    Agent Engine

    Esta es la opción de bajo mantenimiento, recomendada para la mayoría de las configuraciones nativas de ADK. Se deben definir dos variables:

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

    Luego, implemente con una sola orden:

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

    Agent Engine se encarga del escalado, de la persistencia de sesiones y del registro de trazas con conocimiento del agente. No hay Dockerfile, ni código de sesiones, ni infraestructura que mantener.

    Cloud Run

    Elija esta opción cuando se necesitan bibliotecas de sistema personalizadas, redes específicas como VPC Service Controls, o componentes que no formen parte de ADK. El ejemplo utiliza Quart en lugar de Flask. La sintaxis es casi idéntica, pero Quart maneja async/await de forma nativa, lo que evita el antipatrón de asyncio.run() de crear un bucle de eventos nuevo para cada solicitud:

    # 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)
    

    La definición del contenedor:

    # 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"]
    

    Y la orden de despliegue:

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

    En resumen, Cloud Run requiere un esfuerzo de configuración moderado (un Dockerfile y una API), necesita gestión manual del estado con Firestore o Redis, registra los datos en Cloud Logging estándar y es compatible con tiempos de ejecución y frameworks personalizados. Agent Engine solo necesita un comando, incluye sesiones integradas, genera trazas específicas del agente y es adecuado para agentes nativos de ADK que necesitan escalar rápidamente.

    Hacer que las conversaciones persistan

    El ejemplo de orquestador utilizó InMemorySessionService, lo cual es adecuado para pruebas pero pierde toda la información cuando se reinicia el proceso. En entornos de producción se necesita un servicio duradero. ADK ofrece dos opciones.

    Con Agent Engine, las sesiones se gestionan automáticamente a través del servicio de sesiones de Vertex AI:

    # 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 también resume historiales largos y se encarga de limpiar todo por sí mismo, por lo que no se necesita código de Firestore.

    En Cloud Run, DatabaseSessionService funciona con un backend de PostgreSQL o SQLite:

    # 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"
    )
    

    Crea sus tablas la primera vez que se inicia. Al colocarlo en el Runner, el estado de sesión sobrevive a los reinicios.

    Cómo se transfiere el estado entre agentes

    No son necesarias llamadas manuales a get() y set(). El output_key de cada agente escribe automáticamente en el estado de sesión, y los agentes posteriores lo leen desde allí:

    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")
    

    El Runner mantiene todo ese estado en el backend configurado, ya sea Firestore, PostgreSQL o Agent Engine.

    Tres hábitos mantienen la memoria saludable:

    • Resumir. Almacenar resultados condensados en lugar de respuestas API sin procesar, para evitar que la ventana de contexto se llene de datos innecesarios.
    • Vencer sesiones. Las sesiones de soporte deben tener una duración de 24 a 48 horas, lo que mantiene la base de datos más pequeña y segura.
    • Proteger los datos personales. La información personal sensible como números de identificación nacional o contraseñas no debe estar en el estado compartido, por lo que debe ser enmascarada antes de escribirse en la sesión.

    Cuando un agente sigue siendo la mejor opción

    El enfoque multiagente no es automáticamente superior. Una forma práctica de decidirlo es:

    • Preguntas frecuentes simples o verificación de estado: un solo agente. Menor latencia y costo, no se necesita razonamiento complejo.
    • Enriquecimiento de datos con tres a cinco búsquedas: un solo agente. Una sola llamada al LLM es suficiente para utilizar herramientas básicas.
    • Flujos de trabajo regulados: múltiples agentes. El aislamiento mantiene la lógica de las acciones separada de la entrada del usuario, lo que limita la inyección de instrucciones no deseadas.
    • Enrutamiento ambiguo: múltiples agentes. Un agente especializado en triaje se encarga de asignar las intenciones, reduciendo los problemas derivados de ambigüedades.
    • Acciones de alto riesgo por encima de los $500: múltiples agentes. Permite una segunda verificación por parte de un agente de control de calidad antes de acceder a cualquier API.
    • Requisitos de auditoría: múltiples agentes. Las entradas y salidas de cada agente se registran por separado.

    Una regla práctica: cuando una instrucción para un único agente alcanza los 3,000 tokens, es decir, en el punto en que aparecen problemas de limitaciones y dilución de la atención, o cuando diferentes partes del flujo de trabajo requieren herramientas distintas, es momento de dividirlo.

    Trampas comunes

    • El agente que lo hace todo. El rendimiento disminuye cuando un solo agente maneja diez o más herramientas, ya que los modelos comienzan a dedicar esfuerzos a elegir la herramienta en lugar de comprender la solicitud. Divídalo por capacidades: un agente que necesita herramientas para reembolsos, envíos y asuntos legales se convierte en tres especialistas.
    • Contexto desbordante. Si cada agente ve toda la conversación de diez turnos, los costos en tokens se disparan. Compacta el estado para que la triaje solo transmita la intención detectada y no toda la conversación.
  • Transferencias interminables. El agente A envía la tarea al B, que a su vez la devuelve al A, perdiéndose tokens en un círculo continuo. Se debe establecer un contador máximo de transferencias; dos ciclos suelen ser suficientes antes de necesitar intervención humana.
  • Límites poco definidos. Dos agentes pueden encargarse de la misma tarea, o bien una tarea puede quedar dividida entre ellos. Es necesario definir contratos explícitos input_schema y output_schema sin responsabilidades superpuestas.
  • Ignorar la latencia. Un flujo secuencial añade entre 4 y 6 segundos, mientras que un solo agente tarda de 1 a 2 segundos. El ParallelAgent de ADK distribuye el trabajo de forma independiente, y realizar verificaciones de investigación y cumplimiento en paralelo puede reducir entre un 30% y un 40% la latencia total.
  • Qué esperar de ellos

    Los sistemas multiagente sacrifican la latencia en favor de la fiabilidad en tareas complejas. Los benchmarks publicados y la experiencia del sector destacan estas ventajas:

    • Precisión en tareas complejas. Dividir problemas de múltiples pasos en subtareas específicas generalmente da mejores resultados que los prompts monolíticos, y la documentación de ADK indica tasas de finalización más altas cuando los agentes tienen funciones limitadas.
    • Fallas contenidas. Cuando un componente falla, el daño se queda dentro de ese agente y no arruina toda la respuesta.
    • Auditable. Los registros separados por agente facilitan la depuración y el cumplimiento de normas.

    Los costos también son reales:

    • Latencia. Un pipeline con cinco agentes tarda aproximadamente de 3 a 8 segundos, frente a 1 a 2 segundos para un solo agente. Las llamadas secuenciales son el principal cuello de botella.
  • Gasto en API. Cinco agentes (un orquestador y cuatro especialistas) cuestan entre cuatro y cinco veces más que un agente por consulta, aunque la mezcla de modelos ayuda a controlar los costos. La triaje en Flash-Lite cuesta 0,25 dólares por millón de tokens de entrada, mientras que la versión Pro, a 2 dólares por millón, está reservada para la orquestación y las pruebas de calidad, manteniendo el costo total por interacción por debajo de un centavo.
  • Tokens de procesamiento. El modo de procesamiento extendido de Pro (thinking_level="HIGH") puede añadir unos 20.000 tokens, con una tarifa de 12 dólares por millón de tokens de salida. Por lo tanto, una revisión profunda de calidad cuesta aproximadamente 0,24 dólares solo en tokens de procesamiento. Use el nivel HIGH de forma selectiva, ya que la mayoría de las revisiones de calidad funcionan bien con el nivel MEDIUM.
  • Complejidad. Hay más elementos que monitorear. Resulta útil para flujos de trabajo complejos, pero es excesivo para los sencillos.
  • Para una estimación aproximada del costo mensual con 100.000 consultas complejas:

    • Ruteo del orquestador en Gemini 3.1 Pro: unos $80
    • Triaje en Flash-Lite: unos $20
    • Investigación con Flash: unos $40
    • Acción con Flash: unos $40
    • Control de calidad con nivel de razonamiento MEDIUM en Pro: unos $100
    • Cloud Run con 2 vCPU y 2 GiB: unos $120
    • Sesiones de PostgreSQL: unos $30
    • Búsqueda vectorial, compartida con una configuración de un solo agente: unos $100
    • Total: unos $530 por mes

    La mezcla de modelos es el verdadero factor que influye en los costos. Solo alrededor del 30% de las llamadas (orquestador y control de calidad) aplican la tarifa de Pro, mientras que el resto se ejecutan en Flash o Flash-Lite a una octava o una quincuagésima parte del precio por token. El costo unitario por interacción compleja es de aproximadamente medio centavo. Estas cifras provienen de las tarifas publicadas por Google Cloud, y las facturas reales varían según la complejidad de la consulta, el nivel de razonamiento y la profundidad de las llamadas del agente.

    Orden de adopción

    La secuencia lógica consiste en comenzar con un único agente, ajustar su lógica, fundamentarlo mediante la recuperación de información, y dividirlo en especialistas solo cuando el prompt del sistema se vuelva demasiado largo o las tareas sean demasiado variadas como para que un modelo las maneje de manera fiable. Cada capa se basa en la anterior.

    El momento de los microservicios para los agentes

    El diseño multiagente no complica más a la IA; hace que los flujos de trabajo complejos sean predecibles, al igual que los microservicios reemplazaron a los sistemas monolíticos: un prompt se convierte en un conjunto distribuido de componentes, cada uno encargado de una tarea específica. Pedirle a un único agente que realice tareas como triage, investigación, acción y auditoría al mismo tiempo es como pedirle a una sola persona que sea recepcionista, analista principal, técnico y auditor al mismo tiempo. Eso funciona en una empresa con un solo empleado, pero falla en una organización grande.

    Al asignar a cada agente una tarea específica, herramientas especializadas y una capa de memoria compartida, el resultado es preciso, ya que las instrucciones bien definidas reducen la desviación en tareas no relacionadas; es fácil de depurar, porque se puede identificar al especialista que falla; y resulta económico, ya que ejecutar cinco agentes en Gemini 3.1 cuesta aproximadamente medio centavo por interacción compleja, muy menos que un minuto del tiempo de un agente humano.

    El diseño también tiene espacio para evolucionar. Con el protocolo Agent-to-Agent (A2A), un estándar abierto gestionado por la Linux Foundation, un sistema como este podría llegar a negociar con agentes operados por proveedores o socios, por ejemplo, un agente de soporte que hable directamente con el agente de un proveedor de envíos para resolver un paquete perdido sin intervención humana.

    Por ahora, el consejo es sencillo: construya primero un solo agente y descomóntelo cuando la instrucción sea demasiado larga o las tareas demasiado diversas.

    Lecturas relacionadas

  • Tres personajes Gemini debaten una estrategia fallida para superar la volatilidad — Un backtest de una estrategia para superar la volatilidad en acciones de alto beta, ajustada por un especialista en quantitativos, un gerente de riesgos y un responsable de ejecución; se analiza qué mejoró y qué aún quedó atrás en comparación con SPY.
  • Asistente de soporte con doble motor en Google Cloud: documentos públicos y guías privadas — Creación de un asistente de soporte que consulta simultáneamente Vertex AI Search y la API Developer Knowledge, permitiendo además a Gemini armonizar los consejos con las reglas propias del cliente.
  • Construye con IA gratis: Gemini y Groq cuando se agotan tus créditos de API — Una guía para principiantes sobre la diferencia entre tokens y créditos, planes de API gratuitos que no requieren tarjeta, y cuánto cambia el código al cambiar de proveedor.