Llamada a función asíncrona con la API de Gemini Live

Cuando se crean agentes de voz en tiempo real, algunas llamadas a funciones pueden bloquear la ejecución del modelo, lo que hace que la transmisión de audio se silencie y el usuario quede esperando en silencio. Con la API de Gemini Live, todas las llamadas a funciones no son de bloqueo de forma predeterminada, lo que te permite ejecutar funciones en paralelo con el flujo de conversación principal. Este proceso se denomina llamada a función asíncrona. Tu backend puede procesar tareas pesadas, como buscar precios de vuelos en vivo o consultar APIs externas complejas en segundo plano, mientras el modelo sigue escuchando, hablando y conversando con naturalidad con el usuario. La API de Gemini Live permite que las llamadas a funciones se procesen en segundo plano sin interrumpir la interacción del usuario con el modelo, lo que permite interacciones más fluidas y en tiempo real.

La llamada a funciones asíncrona te permite completar tareas como reservar citas, establecer recordatorios o recuperar datos sin pausar la conversación. Por ejemplo, un usuario puede solicitar reservar un vuelo y, de inmediato, pedir información sobre el clima mientras se procesa la reserva en segundo plano.

Ejemplo de llamada a función asíncrona

En este ejemplo, se muestra a un usuario que reserva un vuelo y pregunta la hora en Nueva York mientras la función book_ticket se ejecuta de forma asíncrona en segundo plano:

User: Please book the 2:00 PM flight to New York for me.

Model: function_call: {name: "book_ticket"}
//(The "book_ticket" function call is sent to the client.)
//(Right after the "book_ticket" function call is received, the client sends a text message to the model: "repeat this sentence 'I'm booking your ticket now, please wait.'")
//(The client runs the function call asynchronously in the background.)
Model: I'm booking your ticket now, please wait.

User: What is the current time in New York?

Model: The current time in New York is 12:00pm.

//(Once the book_ticket function finishes, the client sends the result.)
Function_response: {name: "book_ticket", response: {booking_status: "booked"}}

Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.

Implementa la llamada a funciones asíncrona

En esta sección, se proporcionan varios ejemplos en los que se usa la versión para Python del SDK de Agent Platform para compilar una arquitectura simultánea y con alta capacidad de respuesta que usa la capacidad de llamada a funciones asíncrona de la API de Gemini Live. Los ejemplos se desglosan en las siguientes tareas:

Define tus herramientas

Para controlar cómo se ejecuta cada herramienta, configura el campo behavior de su FunctionDeclaration:

  • NON_BLOCKING (predeterminado cuando no se establece behavior): El modelo sigue conversando mientras se ejecuta la herramienta. Usa este parámetro de configuración para búsquedas de solo lectura o tareas en segundo plano cuyos resultados se puedan entregar más tarde.
  • BLOCKING: El modelo se detiene y espera tu FunctionResponse antes de generar más resultados. Usa este parámetro de configuración para operaciones irreversibles o que cambian de estado (como pagos, reservas o actualizaciones de cuentas) en las que el modelo no debe confirmar un resultado antes de conocerlo. Si llega una entrada de usuario nueva mientras se ejecuta una llamada de bloqueo, el servidor cancela la llamada, lo que requiere idempotencia del backend.

Si usas un framework sobre la API de Gemini Live, verifica que el framework transmita behavior en el mensaje de configuración de la sesión. Si se omite, las herramientas se ejecutan como NON_BLOCKING de forma predeterminada.

En el siguiente ejemplo de Python, se muestra cómo declarar herramientas de bloqueo y no bloqueo:

from google import genai
from google.genai import types

client = genai.Client()

# 1. A read-only lookup: safe to run in the background
search_live_flights = types.FunctionDeclaration(
    name="search_live_flights",
    description="Searches airlines for current flight prices. Can take up to 10 seconds.",
    behavior=types.Behavior.NON_BLOCKING,
)

# 2. A state-changing operation: the model waits for the result before continuing
book_flight = types.FunctionDeclaration(
    name="book_flight",
    description="Books a flight ticket. Irreversible.",
    behavior=types.Behavior.BLOCKING,
    parameters=types.Schema(
        type=types.Type.OBJECT,
        properties={
            "flight_id": types.Schema(type=types.Type.STRING),
        },
        required=["flight_id"],
    ),
)

tools = [types.Tool(function_declarations=[search_live_flights, book_flight])]

Controla las llamadas a función desde el flujo de mensajes

Cuando el modelo debe llamar a una o más funciones, la API de Gemini Live envía un evento tool_call a través del flujo de mensajes en tiempo real.

Tu backend no debe bloquear la transmisión porque el modelo espera seguir ejecutándose. Cuando recibes una llamada para una función lenta (como search_live_flights), debes pasarla a un trabajador en segundo plano. Si usas un await directamente en tu bucle de mensajes principal para una tarea de 10 segundos, se congelará la conexión. Las tareas rápidas (como get_current_weather) se pueden esperar de forma segura.

import asyncio

async def handle_stream(session):
    async for response in session.receive():
        # Check if the model is asking to use a tool
        if response.tool_call is not None:
            for fc in response.tool_call.function_calls:

                if fc.name == "search_live_flights":
                    # Pass to a background task so we don't block the receive loop!
                    asyncio.create_task(background_flight_search(fc.id, fc.args, session))

                elif fc.name == "get_current_weather":
                    # Instant lookups can be safely awaited directly
                    await instant_weather_lookup(fc.id, fc.args, session)

Controlar las expectativas de los usuarios

Para administrar las expectativas durante las llamadas a funciones asíncronas de larga duración, envía un mensaje de texto desde el cliente que le indique al sistema que informe al usuario que se está procesando la solicitud y que tenga paciencia. Por ejemplo, después de que el cliente recibe una llamada a función, puede enviar un mensaje de texto al modelo, como: "repite esta oración: 'Estoy reservando tu boleto ahora, espera'".

En el siguiente diálogo de ejemplo, se muestra este intercambio:

User: Please book the 2:00 PM flight to New York for me.
Model: function_call: {name: "book_ticket"}
//(The "book_ticket" function call is sent to the client.)
//(Right after the "book_ticket" function call is received, the client sends a text message to the model: "repeat this sentence 'I'm booking your ticket now, please wait.'")
//(The client runs the function call asynchronously in the background.)
Model: I'm booking your ticket now, please wait.
User: What is the current time in New York?
Model: The current time in New York is 12:00pm.
//(Once the "book_ticket" function call finishes, the client sends in the response.)
Function_response: {name: "book_ticket", response: {booking_status: "booked"}}
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.

Esta estrategia de mensajería proactiva tiene los siguientes beneficios:

  • Informa al usuario sobre las operaciones actuales del sistema, lo que administra las expectativas durante las llamadas a funciones de larga duración.
  • Reduce la frecuencia de instrucciones breves y redundantes de los usuarios, como "¿hola?" o "¿estás ahí?". Suelen ocurrir durante períodos prolongados de silencio del sistema mientras se procesan las llamadas a funciones asíncronas. Esto puede minimizar el riesgo de llamadas a funciones duplicadas que se activan por estas consultas repetidas de los usuarios.
  • Proporcionar una instrucción del sistema adicional puede reducir la probabilidad de crear llamadas duplicadas en interacciones posteriores.

Controla las llamadas a funciones duplicadas

Existe una pequeña posibilidad de que el modelo genere llamadas a funciones duplicadas antes de recibir una respuesta para la primera llamada. Si tu caso de uso lo permite, tu aplicación puede ignorar las llamadas a funciones duplicadas si aún está pendiente una respuesta para la misma llamada a función.

En el siguiente ejemplo, se muestra cómo un cliente puede ignorar una llamada a función duplicada:

User: Please book the 2:00 PM flight to New York for me.

Model: function_call: {name: "book_ticket"}
//(The "book_ticket" function call is sent to the client. It is running asynchronously in the background.)

User: What is the current time in New York?
Model: The current time in New York is 12:00pm. + function_call: {name: "book_ticket"}
//(The duplicated "book_ticket" can be ignored by the client since the response for the first "book_ticket" has not been sent to the model yet.)

//(The first "book_ticket" function call finishes, and client sends in the response.)
Function_response: {name: "book_ticket", response: {booking_status: "booked"}}

Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.

Controla las respuestas de funciones asíncronas

Cuando se completa una llamada a función asíncrona, tu aplicación envía el resultado al modelo en un function_response. Mientras tu backend procesa una llamada a función, como buscar vuelos, el usuario puede hacerle al modelo una pregunta completamente diferente, como "¿Cómo está el clima en Londres?". El modelo responde a la solicitud en tiempo real, en paralelo con la ejecución de la llamada a función. Como el usuario podría estar en una interacción en curso con el modelo cuando se complete la ejecución de la función, puedes especificar una política que defina cómo debe controlar el modelo esta respuesta entrante. Puedes especificar una de las siguientes políticas:

Para especificar una política, incluye el campo scheduling en la carga útil de function_response:

{
  "name": "book_ticket",
  "scheduling": "WHEN_IDLE",
  "response": {
    "booking_status": "booked"
  }
}

La compatibilidad de modelos para FunctionResponse.scheduling varía según el modelo:

  • Gemini 3.8 Live: Admite scheduling (SILENT, WHEN_IDLE y INTERRUPT).
  • gemini-3.8-live-extended-thinking-preview: No admite parámetros de configuración de programación explícitos. El envío de scheduling hace que la sesión se cierre con el error 1007 de WebSocket. Para este modelo, omite el campo scheduling.

Cuando se omite scheduling en los modelos compatibles, la API de Gemini Live usa de forma predeterminada WHEN_IDLE. Cada respuesta de función entrante activa un nuevo turno del modelo después de que el usuario termina de hablar.

En el siguiente ejemplo de Python, se muestra cómo dar formato y enviar un function_response con scheduling="WHEN_IDLE" para esperar una pausa natural en la conversación antes de anunciar los resultados:

async def background_flight_search(call_id, args, session):
    # 1. Simulate a slow API call taking 5 seconds
    await asyncio.sleep(5)
    flight_data = ["Air Canada AC758: $350", "WestJet WS12: $290"]

    # 2. Format the response
    function_response = types.FunctionResponse(
        id=call_id,
        name="search_live_flights",
        response={ "status": "success", "flights": flight_data },
        scheduling="WHEN_IDLE" # Wait for a moment to tell the user
    )

    # 3. Send it back into the live session
    await session.send_tool_response(function_responses=[function_response])

Las siguientes políticas se pueden especificar en el campo scheduling para administrar las respuestas de las funciones:

Política de respuesta SILENT

Con la política SILENT, la respuesta de la función se agrega al contexto del modelo, pero el modelo no genera una respuesta para ella, y no se interrumpe ninguna interacción en curso del usuario.

User: Please book the 2:00 PM flight to New York for me.

Model: function_call: {name: "book_ticket"}
//(The book_ticket function call is sent to the client and starts running asynchronously in the background.)

User: What is the current time in New York?
Model: The current time in New York is 12:00pm.

//(The book_ticket function finishes, and client sends the result with scheduling: "SILENT".)
Function_response: {name: "book_ticket", scheduling: "SILENT", response: {booking_status: "booked"}}
//(The model doesn't generate a response for the function response.)

User: Is my flight ticket booked?
Model: Yes. Your flight has been booked.

Política de respuesta WHEN_IDLE

Con la política WHEN_IDLE, el modelo genera una respuesta a la respuesta de la función solo cuando no hay interacción activa del usuario. Si hay una interacción del usuario en curso, el modelo espera a que se complete antes de generar una respuesta para evitar interrupciones.

User: Please book the 2:00 PM flight to New York for me.

Model: function_call: {name: "book_ticket"}
//(The book_ticket function call is sent to the client and starts running asynchronously in the background.)

User: What is the current time in New York?

//(The book_ticket function finishes, and client sends the result with scheduling: "WHEN_IDLE".)
Function_response: {name: "book_ticket", scheduling: "WHEN_IDLE", response: {booking_status: "booked"}}
//(The ongoing interaction about the time is not interrupted.)

Model: The current time in New York is 12:00pm.
//(After responding to the user's time query, the model issues the response for the book_ticket function.)
Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.

Política de respuesta INTERRUPT

Con la política INTERRUPT, el modelo genera una respuesta a la función de inmediato, lo que interrumpe cualquier interacción del usuario en curso.

User: Please book the 2:00 PM flight to New York for me.

Model: function_call: {name: "book_ticket"}
//(The book_ticket function call is sent to the client and starts running asynchronously in the background.)

User: What is the current time in New York?

//(The book_ticket function finishes, and client sends the result with scheduling: "INTERRUPT".)
Function_response: {name: "book_ticket", scheduling: "INTERRUPT", response: {booking_status: "booked"}}
//(The ongoing interaction about the time is interrupted, and model skips responding to it.)

Model: Your flight has been booked. Expect a confirmation text on your phone within 5 minutes.

Agrega varias respuestas no bloqueantes

Cuando el modelo llama a varias herramientas no bloqueantes de forma simultánea (como búsquedas de datos paralelas), enviar cada resultado de forma individual con WHEN_IDLE hace que el modelo genere varios turnos de voz independientes. Para entregar una sola respuesta consolidada, aplica uno de los siguientes patrones:

  • Usa SILENT para los resultados intermedios: Envía todas las respuestas intermedias de la herramienta con scheduling="SILENT". Envía la respuesta final con scheduling="WHEN_IDLE" para que el modelo resuma todos los datos recopilados en un turno.
  • Respuestas por lotes: Espera a que se completen todas las tareas de herramientas simultáneas y entrégalas juntas en una sola llamada a send_tool_response con function_responses=[...].

Prácticas recomendadas

  • Declara el comportamiento de la herramienta de forma explícita: Configura las herramientas irreversibles o que cambian de estado en BLOCKING y las búsquedas en segundo plano o de solo lectura en NON_BLOCKING.
  • Diseña para la simultaneidad: Siempre descarga las herramientas lentas (como consultar APIs externas o ejecutar canalizaciones de RAG) en tareas en segundo plano en tu backend. Permite que el modelo siga controlando la transmisión de audio activa.
  • Programa respuestas sin bloqueo de forma deliberada: Usa SILENT para las respuestas intermedias, WHEN_IDLE para el resultado final que debería activar la salida de voz y INTERRUPT solo para las alertas críticas. Si dejas scheduling sin configurar, se establece de forma predeterminada en WHEN_IDLE y se inicia un turno del modelo para cada respuesta.
  • Turnos de chat independientes: En la API de Gemini Live, la ejecución de herramientas es completamente independiente de los turnos de chat. La conversación puede ramificarse, continuar y fluir de forma natural mientras tu herramienta se procesa en segundo plano.
  • La advertencia "Silencioso": Es posible que el modelo aún intente narrar verbalmente la ejecución de una herramienta, incluso si está programada como SILENT. Para aplicar el silencio verdadero, agrega instrucciones de seguridad explícitas a tus instrucciones del sistema (por ejemplo, "Cuando uses [nombre de la herramienta], realiza una EJECUCIÓN SILENCIOSA y no digas nada") o usa un patrón de backend de "disparar y olvidar" en el que no envíes un FunctionResponse de vuelta al modelo.

¿Qué sigue?

Descripción general

Obtén una descripción general de la API de Live.

Referencia

Guía de referencia de la API de Live.

Guía

Aprende a iniciar y administrar sesiones en vivo con la API de Live.

Guía

Aprende a configurar las funciones de Gemini para la API de Live.