I callback sono una funzionalità avanzata che fornisce un meccanismo potente per collegarsi al processo di esecuzione di un agente specifico utilizzando il codice Python. Ti consentono di osservare, personalizzare e persino controllare il comportamento dell'agente in punti specifici e predefiniti.
Esistono diversi tipi di callback che puoi utilizzare, ognuno dei quali viene eseguito in un punto specifico del turno di conversazione. Questi tipi sono descritti nelle sezioni seguenti.
Runtime e classi Python
Nel codice di callback Python, hai accesso a determinate classi e funzioni che ti aiutano a scrivere il codice. Per saperne di più, consulta il riferimento del runtime Python.
Limitazioni di sandbox e rete
Il codice di callback Python viene eseguito in un ambiente sandbox. Questo ambiente presenta le seguenti limitazioni:
- Nessun accesso alla rete privata (PNA): i callback non possono accedere direttamente agli indirizzi IP privati o risolvere i domini DNS privati, anche se è configurato Service Directory. Se devi accedere alle risorse all'interno di una rete privata, devi utilizzare un tipo di strumento che supporti l'accesso alla rete privata (ad esempio gli strumenti OpenAPI o MCP).
- Accesso a internet pubblico: i callback possono accedere solo agli endpoint disponibili pubblicamente su internet.
Tipi di callback
A seconda del tipo di callback, la funzione di callback principale deve avere un nome specifico. In questo modo puoi definire funzioni di assistenza con qualsiasi nome all'interno del codice di callback.
Ogni tipo di callback viene eseguito in un punto specifico del turno di conversazione:

Se definisci più callback di un tipo specifico, verranno eseguiti nell'ordine in cui li definisci.
Le sezioni seguenti descrivono ogni tipo di callback, con le seguenti informazioni per ogni tipo:
| X | X |
|---|---|
| Nome | Nome della funzione di callback obbligatoria |
| Esecuzione | Punto di esecuzione all'interno del turno di conversazione. |
| Finalità | Scenari utili per utilizzare il callback. |
| Argomenti | Argomenti di input per la funzione. |
| Restituisci il dispositivo | Valore restituito per la funzione. |
| Callback ADK | Link alla documentazione di callback ADK corrispondente. |
Prima dell'avvio dell'agente (before_agent_callback)
| X | X |
|---|---|
| Nome | before_agent_callback |
| Esecuzione | Chiamato prima dell'invocazione dell'agente. |
| Finalità | Utile per configurare le risorse o lo stato necessari per l'agente, eseguire controlli di convalida sullo stato della sessione o evitare l'invocazione dell'agente. |
| Argomenti | CallbackContext |
| Restituisci il dispositivo | Contenuto(facoltativo): se impostato, l'agente non viene invocato e viene utilizzata la risposta fornita. |
| Callback ADK | callback prima dell'agente |
Esempio di codice:
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
Al termine dell'agente (after_agent_callback)
| X | X |
|---|---|
| Nome | after_agent_callback |
| Esecuzione | Chiamato al termine dell'agente. |
| Finalità | Utile per le attività di pulizia, la convalida post-esecuzione, la modifica dello stato finale o l'aggiornamento della risposta dell'agente. |
| Argomenti | CallbackContext |
| Restituisci il dispositivo | Contenuto(facoltativo): se impostato, sostituisce l'output dell'agente con l'output fornito. |
| Callback ADK | callback dopo l'agente |
Esempio di codice:
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)
Prima della chiamata LLM (before_model_callback)
| X | X |
|---|---|
| Nome | before_model_callback |
| Esecuzione | Chiamato prima della richiesta del modello. |
| Finalità | Utile per l'ispezione/modifica della richiesta del modello o per evitare l'utilizzo del modello. |
| Argomenti | CallbackContext, LlmRequest |
| Restituisci il dispositivo | LlmResponse: se impostato, la chiamata del modello viene ignorata e la risposta viene utilizzata come se provenisse dal modello. |
| Callback ADK | callback prima del modello |
Esempio di codice:
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"))
Dopo la chiamata LLM (after_model_callback)
| X | X |
|---|---|
| Nome | after_model_callback |
| Esecuzione | Chiamato dopo aver ricevuto una risposta del modello. |
| Finalità | Utile per riformattare le risposte del modello, censurare le informazioni sensibili generate dal modello, analizzare i dati strutturati del modello per l'utilizzo nelle variabili e gestione degli errori del modello. |
| Argomenti | CallbackContext, LlmResponse |
| Restituisci il dispositivo | LlmResponse: se impostato, sostituisce la risposta del modello con la risposta fornita. |
| Callback ADK | callback dopo il modello |
Esempio di codice:
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
Prima della chiamata dello strumento (before_tool_callback)
| X | X |
|---|---|
| Nome | before_tool_callback |
| Esecuzione | Chiamato prima delle chiamate dello strumento. |
| Finalità | Utile per l'ispezione e la modifica degli argomenti dello strumento, i controlli di autorizzazione prima dell'esecuzione dello strumento o l'implementazione della memorizzazione nella cache a livello di strumento. |
| Argomenti | Strumento, Dict[str,Any]: input dello strumento, CallbackContext |
| Restituisci il dispositivo | Dict[str,Any] : se impostato, l'esecuzione dello strumento viene ignorata e questo output viene fornito al modello. |
| Callback ADK | callback prima dello strumento |
Esempio di codice:
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"}
Dopo la chiamata dello strumento (after_tool_callback)
| X | X |
|---|---|
| Nome | after_tool_callback |
| Esecuzione | Chiamato al termine dello strumento. |
| Finalità | Utile per l'ispezione e la modifica della risposta dello strumento prima di inviarla al modello, l'elaborazione post-elaborazione dei risultati dello strumento o il salvataggio di parti specifiche di una risposta dello strumento nelle variabili. |
| Argomenti | Strumento, Dict[str,Any]: input dello strumento, CallbackContext, Dict[str,Any]: risposta dello strumento |
| Restituisci il dispositivo | Dict[str,Any]: se impostato, sostituisce la risposta dello strumento fornita al modello. |
| Callback ADK | callback dopo lo strumento |
Esempio di codice:
# 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
Creare un callback
Per creare un callback:
- Apri le impostazioni dell'agente.
- Fai clic su Aggiungi codice.
- Seleziona un tipo di callback.
- Fornisci il codice Python.
- Fai clic su Salva.
Payload personalizzati (custom_payloads)
I payload personalizzati facilitano l'inclusione di dati strutturati supplementari non testuali (in genere formattati come JSON) nella risposta di un agente. Questo payload è fondamentale per indirizzare o aumentare l'interazione dell'agente con sistemi esterni o applicazioni client.
Il valore del payload non è visibile al modello linguistico di grandi dimensioni (LLM); viene utilizzato solo per generare la risposta finale.
I payload personalizzati vengono generati e impostati utilizzando i callback, in particolare before_model_callback o after_model_callback.
Il payload personalizzato può essere utilizzato per diversi scopi, in genere incentrati sull'abilitazione di interazioni strutturate e avanzate:
- Escalation/trasferimento dell'agente: viene spesso utilizzato per trasferire un'interazione a un agente umano fornendo istruzioni di routing (ad esempio, la coda specifica a cui eseguire il routing).
- Contenuti avanzati e azioni lato client:
supporta l'incorporamento di widget avanzati e altri contenuti avanzati
direttamente nelle esperienze di chat,
il che è particolarmente utile per le integrazioni di chat personalizzate.
- Ad esempio, la visualizzazione di URL di immagini o chip e opzioni di risposta rapida per un cliente che utilizza un'interfaccia come Call Companion.
- Composizione della risposta:
i payload personalizzati possono essere configurati per essere restituiti in vari modi:
- Restituisci solo il payload esplicito in modo deterministico.
- Restituisci il payload insieme a una risposta di testo generata da LLM.
- Restituisci il payload con una risposta di testo statica
Configurazione dell'agente
I payload personalizzati possono essere generati e impostati solo utilizzando i callback.
Il payload viene impostato come
Blob
con un mime_type di application/json.
Part.from_json(data=payload_string)
Esempio di after_model_callback
Questo è un esempio di after_model_callback che restituisce la risposta del modello insieme a una risposta di payload personalizzata aggiuntiva.
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_json_string))
return LlmResponse(content=Content(parts=new_parts))
Esempio di before_model_callback
Questo è un esempio di before_model_callback che restituisce un payload personalizzato aggiuntivo dopo l'attivazione di un determinato strumento.
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)]))
Verificare il payload in fase di runtime nella risposta
Il payload viene compilato come Struct nel campo payload sia per
RunSession
che per
BidiRunSession.
Il valore del payload non è visibile a LLM.