Callbacks

As callbacks são um recurso avançado que oferece um mecanismo eficiente para se conectar ao processo de execução de um agente específico usando código Python. Elas permitem observar, personalizar e até mesmo controlar o comportamento do agente em pontos específicos e predefinidos.

Há vários tipos de callbacks que você pode usar, e cada um é executado em um ponto específico do turno da conversa. Esses tipos são descritos nas seções abaixo.

Ambiente de execução e classes do Python

No seu código de callback em Python, você tem acesso a determinadas classes e funções que ajudam a escrever o código. Para mais informações, consulte a referência do ambiente de execução do Python.

Tipos de callback

Dependendo do tipo de callback, sua função de callback principal precisa ter um nome específico. Isso permite definir funções auxiliares de qualquer nome no código de callback.

Cada tipo de callback é executado em um ponto específico da conversa:

fluxo de callback

Se você definir vários callbacks de um tipo específico, eles serão executados na ordem em que foram definidos.

As seções abaixo descrevem cada tipo de callback, com as seguintes informações:

X X
Nome Nome da função de callback obrigatória
Execução Ponto de execução na rodada de conversa.
Finalidade Cenários úteis para usar o callback.
Argumentos Argumentos de entrada para a função.
Retornar Valor de retorno da função.
Retorno de chamada do ADK Link para a documentação de callback do ADK correspondente.

Antes de o agente começar (before_agent_callback)

X X
Nome before_agent_callback
Execução Chamado antes de o agente ser invocado.
Finalidade Útil para configurar recursos ou estados necessários para o agente, realizar verificações de validação no estado da sessão ou evitar a invocação do agente.
Argumentos CallbackContext
Retornar Conteúdo(opcional): se definido, o agente não será invocado, e a resposta fornecida será usada.
Retorno de chamada do ADK before agent callback

Exemplo 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

Depois que o agente termina (after_agent_callback)

X X
Nome after_agent_callback
Execução Chamado depois que o agente é concluído.
Finalidade Útil para tarefas de limpeza, validação pós-execução, modificação do estado final ou atualização da resposta do agente.
Argumentos CallbackContext
Retornar Conteúdo(opcional): se definido, substitui a saída do agente pela saída fornecida.
Retorno de chamada do ADK após o retorno de chamada do agente

Exemplo 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 da chamada de LLM (before_model_callback)

X X
Nome before_model_callback
Execução Chamado antes da solicitação de modelo.
Finalidade Útil para inspeção/modificação da solicitação de modelo ou para evitar o uso do modelo.
Argumentos CallbackContext, LlmRequest
Retornar LlmResponse: se definido, a chamada do modelo será ignorada e a resposta será usada como se tivesse vindo do modelo.
Retorno de chamada do ADK before model callback

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

Após a chamada de LLM (after_model_callback)

X X
Nome after_model_callback
Execução Chamado depois que uma resposta do modelo é recebida.
Finalidade Útil para reformatar respostas do modelo, censurar informações sensíveis geradas pelo modelo, analisar dados estruturados do modelo para uso em variáveis e tratamento de erros do modelo.
Argumentos CallbackContext, LlmResponse
Retornar LlmResponse: se definido, substitua a resposta do modelo pela resposta fornecida.
Retorno de chamada do ADK após o callback do modelo

Exemplo 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 da chamada de função (before_tool_callback)

X X
Nome before_tool_callback
Execução Chamado antes das chamadas de função.
Finalidade Útil para inspeção e modificação de argumentos de ferramentas, verificações de autorização antes da execução de ferramentas ou implementação de armazenamento em cache no nível da ferramenta.
Argumentos Tool, Dict[str,Any]: entradas de ferramentas, CallbackContext
Retornar Dict[str,Any] : se definido, a execução da ferramenta será ignorada e essa saída será fornecida ao modelo.
Retorno de chamada do ADK antes do callback da ferramenta

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

Após a chamada de ferramenta (after_tool_callback)

X X
Nome after_tool_callback
Execução Chamado após a conclusão da ferramenta.
Finalidade Útil para inspeção e modificação da resposta da ferramenta antes de enviar de volta ao modelo, pós-processamento dos resultados da ferramenta ou salvamento de partes específicas de uma resposta da ferramenta em variáveis.
Argumentos Tool, Dict[str,Any]: entradas da ferramenta, CallbackContext, Dict[str,Any]: resposta da ferramenta
Retornar Dict[str,Any]: se definido, substitui a resposta da ferramenta fornecida ao modelo.
Retorno de chamada do ADK após o callback da ferramenta

Exemplo 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

Criar um callback

Para criar um callback:

  1. Abra as configurações do agente.
  2. Clique em Adicionar código.
  3. Selecione um tipo de retorno de chamada.
  4. Forneça código Python.
  5. Clique em Salvar.

Payloads personalizados (custom_payloads)

Os payloads personalizados facilitam a inclusão de dados complementares, não textuais e estruturados (normalmente formatados como JSON) na resposta de um agente. Esse payload é fundamental para direcionar ou aumentar a interação do agente com sistemas externos ou aplicativos cliente.

O valor da carga útil não fica visível para o modelo de linguagem grande (LLM). Ele é usado apenas para gerar a resposta final. Os payloads personalizados são gerados e definidos usando callbacks, especificamente before_model_callback ou after_model_callback.

O payload personalizado pode ser usado para várias finalidades, geralmente centradas em permitir interações estruturadas e avançadas:

  • Transferência/escalonamento de agente: é usado com frequência para transferir uma interação a um agente humano fornecendo instruções de encaminhamento (por exemplo, a fila específica para encaminhar).
  • Conteúdo avançado e ações do lado do cliente: permite incorporar widgets avançados e outros conteúdos avançados diretamente nas experiências de chat, o que é especialmente útil para integrações de chat personalizadas.
    • Por exemplo, mostrar URLs de imagens ou opções e chips de resposta rápida para um cliente usando uma interface como o acompanhante de chamadas.
  • Composição da resposta: os payloads personalizados podem ser configurados para serem retornados de várias maneiras:
    • Retorne apenas o payload explícito de forma determinística.
    • Retorne o payload com uma resposta de texto gerada por LLM.
    • Retornar o payload com uma resposta de texto estático

Configuração do agente

Os payloads personalizados só podem ser gerados e definidos usando callbacks. O payload é definido como um Blob com um mime_type de application/json.

Part.from_json(data=payload_string)

Exemplo de after_model_callback

Este é um exemplo de after_model_callback que retorna a resposta do modelo junto com outra resposta de payload personalizada.

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

Exemplo de before_model_callback

Este é um exemplo de before_model_callback que retorna uma carga útil personalizada adicional depois que uma determinada ferramenta é acionada.

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

Verificar o payload no tempo de execução na resposta

O payload é preenchido como uma struct no campo payload para RunSession e BidiRunSession.

O valor do payload não fica visível para o LLM.