Devoluciones de llamada

Las devoluciones de llamada son una función avanzada que proporciona un mecanismo potente para conectarse al proceso de ejecución de un agente específico con código de Python. Te permiten observar, personalizar y hasta controlar el comportamiento del agente en puntos específicos predefinidos.

Existen varios tipos de devoluciones de llamada que puedes utilizar, y cada tipo se ejecuta en un punto específico del turno de conversación. Estos tipos se describen en las siguientes secciones.

Clases y entorno de ejecución de Python

En el código de devolución de llamada de Python, tienes acceso a ciertas clases y funciones que te ayudan a escribir el código. Para obtener más información, consulta la referencia del entorno de ejecución de Python.

Tipos de devolución de llamada

Según el tipo de devolución de llamada, tu función de devolución de llamada principal debe tener un nombre específico. Esto te permite definir funciones auxiliares con cualquier nombre dentro del código de devolución de llamada.

Cada tipo de devolución de llamada se ejecuta en un punto específico del turno de conversación:

Flujo de devolución de llamada

Si defines varias devoluciones de llamada de un tipo específico, se ejecutarán en el orden en que las definas.

En las siguientes secciones, se describe cada tipo de devolución de llamada, y se incluye la siguiente información para cada tipo:

X X
Nombre Nombre de la función de devolución de llamada obligatoria
Ejecución Es el punto de ejecución dentro del turno de conversación.
Objetivo Situaciones útiles para usar la devolución de llamada.
Argumentos Son los argumentos de entrada para la función.
Volver Es el valor de retorno de la función.
Devolución de llamada del ADK Vínculo a la documentación de devolución de llamada del ADK correspondiente.

Antes de que se inicie el agente (before_agent_callback)

X X
Nombre before_agent_callback
Ejecución Se llama antes de invocar al agente.
Objetivo Es útil para configurar el estado o los recursos necesarios para el agente, realizar verificaciones de validación en el estado de la sesión o evitar la invocación del agente.
Argumentos CallbackContext
Volver Content(opcional): Si se configura, no se invoca al agente y se usa la respuesta proporcionada.
Devolución de llamada del ADK before agent callback

Muestra de código:

import random

def before_agent_callback(
  callback_context: CallbackContext
) -> Optional[Content]:
  username = callback_context.variables.get("username", None)
  if not username:
    # default user
    final_name = "Default Name"
  else:
    # add a random integer to the username
    final_name = f"{username} {random.randint(1,10)}"
  # update the username variable
  callback_context.variables["username"] = final_name

Después de que el agente finaliza (after_agent_callback)

X X
Nombre after_agent_callback
Ejecución Se llama después de que el agente completa su tarea.
Objetivo Es útil para realizar tareas de limpieza, validar datos después de la ejecución, modificar el estado final o actualizar la respuesta del agente.
Argumentos CallbackContext
Volver Content(opcional): Si se configura, reemplaza el resultado del agente por el resultado proporcionado.
Devolución de llamada del ADK after agent callback

Muestra de código:

def after_agent_callback(
  callback_context: CallbackContext
) -> Optional[Content]:
  if callback_context.agent_name == "Routing Agent":
    counter = callback_context.variables.get("counter", 0)
    counter += 1
    # increment the invoked counter for this agent
    callback_context.variables["counter"] = int(counter)

Antes de la llamada al LLM (before_model_callback)

X X
Nombre before_model_callback
Ejecución Se llama antes de la solicitud del modelo.
Objetivo Es útil para inspeccionar o modificar la solicitud del modelo, o para evitar el uso del modelo.
Argumentos CallbackContext, LlmRequest
Volver LlmResponse: Si se configura, se omite la llamada al modelo y se usa la respuesta como si proviniera del modelo.
Devolución de llamada del ADK before model callback

Muestra de código:

def before_model_callback(
  callback_context: CallbackContext,
  llm_request: LlmRequest
) -> Optional[LlmResponse]:
  """
  This callback executes *before* a request is sent to the LLM.

  By returning an `LlmResponse` object, we are intercepting the call to the
  LLM. The LLM will *not* be called, and the framework will instead use the
  `LlmResponse` we provide as if it came from the model.

  This is the core mechanism for implementing input guardrails, prompt
  validation, or serving responses from a cache. Here, we force the agent to
  call a function instead of thinking with the LLM.
  """
  # Modify the shared session state.
  callback_context.variables['foo'] = 'baz'

  # Skip the LLM call and return a custom response telling the agent to
  # execute a specific function.
  return LlmResponse(
    content=Content(parts=[Part(
      function_call=FunctionCall(
        name="function_name", args={"arg_name": "arg_value"}))],
      role="model"))

Después de la llamada al LLM (after_model_callback)

X X
Nombre after_model_callback
Ejecución Se llama después de que se recibe una respuesta del modelo.
Objetivo Es útil para cambiar el formato de las respuestas del modelo, censurar la información sensible generada por el modelo, analizar los datos estructurados del modelo para usarlos en variables y manejo de errores del modelo.
Argumentos CallbackContext, LlmResponse
Volver LlmResponse: Si se configura, reemplaza la respuesta del modelo por la respuesta proporcionada.
Devolución de llamada del ADK Devolución de llamada posterior al modelo

Muestra de código:

def after_model_callback(
  callback_context: CallbackContext,
  llm_response: LlmResponse
) -> Optional[LlmResponse]:
  """
  This callback executes *after* a response has been received from the LLM,
  but before the agent processes it.

  The `llm_response` parameter contains the actual data from the LLM.
  By returning `None`, we are approving this response and allowing the agent
  to use it as-is.

  If we returned a new `LlmResponse` object, it would *replace* the original,
  which is useful for redacting sensitive information, enforcing output
  formatting, or adding disclaimers.
  """
  # Returning None allows the LLM's actual response to be used.
  return None

Antes de la llamada a la herramienta (before_tool_callback)

X X
Nombre before_tool_callback
Ejecución Se llama antes de las llamadas a herramientas.
Objetivo Es útil para inspeccionar y modificar los argumentos de las herramientas, realizar verificaciones de autorización antes de la ejecución de las herramientas o implementar el almacenamiento en caché a nivel de las herramientas.
Argumentos Tool, Dict[str,Any]: Entradas de la herramienta, CallbackContext
Volver Dict[str,Any] : Si se configura, se omite la ejecución de la herramienta y se proporciona este resultado al modelo.
Devolución de llamada del ADK before tool callback

Muestra de código:

def before_tool_callback(
  tool: Tool,
  input: dict[str, Any],
  callback_context: CallbackContext
) -> Optional[dict[str, Any]]:
  """
  This callback executes *before* a specific tool is called by the agent.

  Here, we modify the input arguments intended for the tool and then return
  a dictionary. By returning a dictionary instead of `None`, we are
  overriding the default behavior. The actual tool function will *not* be
  executed. Instead, the dictionary we return will be treated as the
  llm.tool's result and passed back to the LLM for the next step.

  This is ideal for validating tool inputs, applying policies, or returning
  mocked/cached data for testing.
  """
  # Modify the shared session state.
  callback_context.variables['foo'] = 'baz'

  # Modify the arguments for the tool call in-place.
  input['input_arg'] = 'updated_val1'
  input['additional_arg'] = 'updated_val2'

  # Override the tool call and return a mocked result.
  return {"result": "ok"}

Después de la llamada a la herramienta (after_tool_callback)

X X
Nombre after_tool_callback
Ejecución Se llama después de que se completa la herramienta.
Objetivo Es útil para inspeccionar y modificar la respuesta de la herramienta antes de enviarla al modelo, procesar los resultados de la herramienta de forma posterior o guardar partes específicas de una respuesta de la herramienta en variables.
Argumentos Tool, Dict[str,Any]: Entradas de la herramienta, CallbackContext, Dict[str,Any]: Respuesta de la herramienta
Volver Dict[str,Any]: Si se configura, anula la respuesta de la herramienta que se proporciona al modelo.
Devolución de llamada del ADK después de la devolución de llamada de la herramienta

Muestra de código:

# Previous tool was named `get_user_info`
# Previous tool returned the payload:
# {"username": "Patrick", "fave_food": ["pizza"]}

def after_tool_callback(
  tool: Tool,
  input: dict[str, Any],
  callback_context: CallbackContext,
  tool_response: dict
) -> Optional[dict]:

  if tool.name == "get_user_info":
    tool_response["username"] = "Gary"
    tool_response["pet"] = "dog"

    # Override tool response
    return tool_response

Crea una devolución de llamada

Para crear una devolución de llamada, haz lo siguiente:

  1. Abre la configuración del agente.
  2. Haz clic en Agregar código.
  3. Selecciona un tipo de devolución de llamada.
  4. Proporciona código de Python.
  5. Haz clic en Guardar.

Cargas útiles personalizadas (custom_payloads)

Las cargas útiles personalizadas facilitan la inclusión de datos estructurados complementarios y no textuales (por lo general, con formato JSON) en la respuesta de un agente. Esta carga útil es fundamental para dirigir o aumentar la interacción del agente con sistemas externos o aplicaciones cliente.

El modelo de lenguaje grande (LLM) no puede ver el valor de la carga útil, ya que solo se usa para generar la respuesta final. Las cargas útiles personalizadas se generan y configuran con devoluciones de llamada, específicamente before_model_callback o after_model_callback.

La carga útil personalizada se puede usar para varios propósitos, generalmente centrados en habilitar interacciones enriquecidas y estructuradas:

  • Transferencia o derivación al agente: Se usa con frecuencia para transferir una interacción a un agente humano proporcionando instrucciones de enrutamiento (por ejemplo, la cola específica a la que se debe enrutar).
  • Contenido enriquecido y acciones del cliente: Permite incorporar widgets enriquecidos y otro contenido enriquecido directamente en las experiencias de chat, lo que resulta especialmente útil para las integraciones de chat personalizadas.
    • Por ejemplo, mostrar URLs de imágenes o chips y opciones de respuesta rápida para un cliente que usa una interfaz como Call Companion.
  • Composición de la respuesta: Las cargas útiles personalizadas se pueden configurar para que se muestren de varias maneras:
    • Devuelve solo la carga útil explícita de forma determinística.
    • Devuelve la carga útil junto con una respuesta de texto generada por un LLM.
    • Devuelve la carga útil con una respuesta de texto estático

Configuración del agente

Las cargas útiles personalizadas solo se pueden generar y establecer con devoluciones de llamada. La carga útil se establece como un Blob con un mime_type de application/json.

Part.from_json(data=payload_string)

Ejemplo de after_model_callback

Este es un ejemplo de after_model_callback que devuelve la respuesta del modelo junto con una respuesta de carga útil personalizada adicional.

import json

def after_model_callback(callback_context: CallbackContext, llm_response: LlmResponse) -> Optional[LlmResponse]:
 """
 Adds a custom payload to every model response which is a text
 """
 if (llm_response.content.parts[0].text is not None):
   # construct payload
   payload_dict = { "custom_payload_key": "custom_payload_value"}
   payload_json_string = json.dumps(payload_dict)

   new_parts = []
   # Keep the origial agent response part, as model only sees text in the historical context.
   new_parts.append(Part(text=llm_response.content.parts[0].text))

   # Append custom payload
   new_parts.append(Part.from_json(data=payload_string))

   return LlmResponse(content=Content(parts=new_parts))

Ejemplo de before_model_callback

Este es un ejemplo de before_model_callback que devuelve una carga útil personalizada adicional después de que se activa una herramienta determinada.

import json

def has_escalate(llm_request: LlmRequest) -> bool:
  for content in llm_request.contents:
    for part in content.parts:
      if part.function_call and part.function_call.name == 'escalate':
        return True
  return False

def before_model_callback(callback_context: CallbackContext, llm_request: LlmRequest) -> Optional[LlmResponse]:
  # checks if `escalate` tool is being called
  if not has_escalate(llm_request):
    return None
  payload_dict = { "escalate": "user ask for escalation"}
  payload_json_string = json.dumps(payload_dict)

  return LlmResponse(content=Content(parts=[Part(text="ESCALATE!!!"), Part.from_json(data=payload_json_string)]))

Verifica la carga útil en la respuesta durante el tiempo de ejecución

La carga útil se completa como un Struct en el campo payload para RunSession y BidiRunSession.

El LLM no puede ver el valor de la carga útil.