Rappels

Les rappels sont une fonctionnalité avancée qui fournit un mécanisme puissant pour s'intégrer au processus d'exécution d'un agent spécifique à l'aide de code Python. Ils vous permettent d'observer, de personnaliser et même de contrôler le comportement de l'agent à des points spécifiques prédéfinis.

Vous pouvez utiliser différents types de rappels, chacun étant exécuté à un moment précis du tour de conversation. Ces types sont décrits dans les sections ci-dessous.

Environnement d'exécution et classes Python

Dans votre code de rappel Python, vous avez accès à certaines classes et fonctions qui vous aident à écrire le code. Pour en savoir plus, consultez la documentation de référence sur l'environnement d'exécution Python.

Types de rappel

En fonction du type de rappel, votre fonction de rappel principale doit porter un nom spécifique. Cela vous permet de définir des fonctions d'assistance de n'importe quel nom dans votre code de rappel.

Chaque type de rappel est exécuté à un moment précis du tour de conversation :

flux de rappel

Si vous définissez plusieurs rappels d'un type spécifique, ils seront exécutés dans l'ordre dans lequel vous les définissez.

Les sections ci-dessous décrivent chaque type de rappel, en fournissant les informations suivantes pour chacun d'eux :

X X
Nom Nom de la fonction de rappel requise
Exécution Point d'exécution dans le tour de conversation.
Objectif Scénarios utiles pour utiliser le rappel.
Arguments Arguments d'entrée pour la fonction.
Renvoyer Valeur de retour de la fonction.
Rappel ADK Lien vers la documentation du rappel ADK correspondant.

Avant le début de l'agent (before_agent_callback)

X X
Nom before_agent_callback
Exécution Appelé avant l'invocation de l'agent.
Objectif Utile pour configurer les ressources ou l'état nécessaires à l'agent, effectuer des contrôles de validation sur l'état de la session ou éviter l'appel de l'agent.
Arguments CallbackContext
Renvoyer Content(facultatif) : si cette option est définie, l'agent n'est pas appelé et la réponse fournie est utilisée.
Rappel ADK before_agent_callback

Exemple de code :

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

Une fois l'agent terminé (after_agent_callback)

X X
Nom after_agent_callback
Exécution Appelé une fois l'agent terminé.
Objectif Utile pour les tâches de nettoyage, la validation post-exécution, la modification de l'état final ou la mise à jour de la réponse de l'agent.
Arguments CallbackContext
Renvoyer Contenu(facultatif) : si cette option est définie, remplacez la sortie de l'agent par la sortie fournie.
Rappel ADK after agent callback

Exemple de code :

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)

Avant l'appel LLM (before_model_callback)

X X
Nom before_model_callback
Exécution Appelé avant la requête de modèle.
Objectif Utile pour inspecter/modifier la requête du modèle ou pour éviter l'utilisation du modèle.
Arguments CallbackContext, LlmRequest
Renvoyer LlmResponse : si cette valeur est définie, l'appel de modèle est ignoré et la réponse est utilisée comme si elle provenait du modèle.
Rappel ADK before_model_callback

Exemple de code :

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

Après l'appel LLM (after_model_callback)

X X
Nom after_model_callback
Exécution Appelé après la réception d'une réponse du modèle.
Objectif Utile pour reformater les réponses du modèle, censurer les informations sensibles générées par le modèle, analyser les données structurées du modèle pour les utiliser dans des variables et gestion des exceptions du modèle.
Arguments CallbackContext, LlmResponse
Renvoyer LlmResponse : si cette valeur est définie, remplacez la réponse du modèle par la réponse fournie.
Rappel ADK après le rappel du modèle

Exemple de code :

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

Avant l'appel d'outil (before_tool_callback)

X X
Nom before_tool_callback
Exécution Appelé avant les appels d'outil.
Objectif Utile pour inspecter et modifier les arguments des outils, vérifier les autorisations avant l'exécution des outils ou implémenter une mise en cache au niveau de l'outil.
Arguments Tool, Dict[str,Any]: tool inputs, CallbackContext
Renvoyer Dict[str,Any] : si cette valeur est définie, l'exécution de l'outil est ignorée et cette sortie est fournie au modèle.
Rappel ADK before tool callback

Exemple de code :

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

Après l'appel d'outil (after_tool_callback)

X X
Nom after_tool_callback
Exécution Appelé après l'exécution de l'outil.
Objectif Utile pour inspecter et modifier la réponse de l'outil avant de la renvoyer au modèle, post-traiter les résultats de l'outil ou enregistrer des parties spécifiques d'une réponse d'outil dans des variables.
Arguments Tool, Dict[str,Any]: tool inputs, CallbackContext, Dict[str,Any]: tool response
Renvoyer Dict[str,Any]: si cette valeur est définie, elle remplace la réponse de l'outil fournie au modèle.
Rappel ADK after tool callback

Exemple de code :

# 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

Créer un rappel

Pour créer un rappel :

  1. Ouvrez les paramètres de l'agent.
  2. Cliquez sur Ajouter un code.
  3. Sélectionnez un type de rappel.
  4. Fournis du code Python.
  5. Cliquez sur Enregistrer.

Charges utiles personnalisées (custom_payloads)

Les charges utiles personnalisées permettent d'inclure des données structurées supplémentaires et non textuelles (généralement au format JSON) dans la réponse d'un agent. Cette charge utile est essentielle pour orienter ou augmenter l'interaction de l'agent avec des systèmes externes ou des applications clientes.

La valeur de la charge utile n'est pas visible par le grand modèle de langage (LLM). Elle n'est utilisée que pour générer la réponse finale. Les charges utiles personnalisées sont générées et définies à l'aide de rappels, en particulier before_model_callback ou after_model_callback.

La charge utile personnalisée peut être utilisée à plusieurs fins, généralement axées sur l'activation d'interactions riches et structurées :

  • Escalade/Transfert d'agent : cette fonctionnalité est fréquemment utilisée pour transférer une interaction à un agent humain en fournissant des instructions de routage (par exemple, la file d'attente spécifique vers laquelle transférer l'interaction).
  • Contenu enrichi et actions côté client : il permet d'intégrer des widgets et d'autres contenus enrichis directement dans les expériences de chat, ce qui est particulièrement utile pour les intégrations de chat personnalisées.
    • Par exemple, vous pouvez afficher des URL d'images ou des options et des chips de réponse rapide pour un client qui utilise une interface comme Call Companion.
  • Composition de la réponse : Les charges utiles personnalisées peuvent être configurées pour être renvoyées de différentes manières :
    • Renvoie uniquement la charge utile explicite de manière déterministe.
    • Renvoyez la charge utile avec une réponse textuelle générée par le LLM.
    • Renvoyer la charge utile avec une réponse texte statique

Configurer l'agent

Les charges utiles personnalisées ne peuvent être générées et définies qu'à l'aide de rappels. La charge utile est définie en tant que Blob avec un mime_type de application/json.

Part.from_json(data=payload_string)

Exemple d'after_model_callback

Il s'agit d'un exemple de after_model_callback qui renvoie la réponse du modèle ainsi qu'une réponse de charge utile personnalisée supplémentaire.

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

Exemple de before_model_callback

Il s'agit d'un exemple de before_model_callback qui renvoie une charge utile personnalisée supplémentaire après le déclenchement d'un certain outil.

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

Valider la charge utile dans la réponse au moment de l'exécution

La charge utile est renseignée sous forme de structure dans le champ payload pour RunSession et BidiRunSession.

La valeur de la charge utile n'est pas visible par le LLM.