Skip to content

Types of Callbacks

The framework provides different types of callbacks that trigger at various stages of an agent's execution. Understanding when each callback fires and what context it receives is key to using them effectively.

Agent Lifecycle Callbacks

These callbacks are available on any agent that inherits from BaseAgent (including LlmAgent, SequentialAgent, ParallelAgent, LoopAgent, etc).

Before Agent Callback

When: Called immediately before the agent's _run_async_impl (or _run_live_impl) method is executed. It runs after the agent's InvocationContext is created but before its core logic begins.

Purpose: Ideal for setting up resources or state needed only for this specific agent's run, performing validation checks on the session state (callback_context.state) before execution starts, logging the entry point of the agent's activity, or potentially modifying the invocation context before the core logic uses it.

Code

Note on the before_agent_callback Example:

  • What it Shows: This example demonstrates the before_agent_callback. This callback runs right before the agent's main processing logic starts for a given request.
  • How it Works: The callback function (check_if_agent_should_run) looks at a flag (skip_llm_agent) in the session's state.
    • If the flag is True, the callback returns a types.Content object. This tells the ADK framework to skip the agent's main execution entirely and use the callback's returned content as the final response.
    • If the flag is False (or not set), the callback returns None. This tells the ADK framework to proceed with the agent's normal execution (calling the LLM in this case).
  • Expected Outcome: You'll see two scenarios:
    1. In the session with the skip_llm_agent: True state, the agent's LLM call is bypassed, and the output comes directly from the callback ("Agent... skipped...").
    2. In the session without that state flag, the callback allows the agent to run, and you see the actual response from the LLM (e.g., "Hello!").
  • Understanding Callbacks: This highlights how before_ callbacks act as gatekeepers, allowing you to intercept execution before a major step and potentially prevent it based on checks (like state, input validation, permissions).

After Agent Callback

When: Called immediately after the agent's _run_async_impl (or _run_live_impl) method successfully completes. It does not run if the agent was skipped due to before_agent_callback returning content or if end_invocation was set during the agent's run.

Purpose: Useful for cleanup tasks, post-execution validation, logging the completion of an agent's activity, modifying final state, or augmenting/replacing the agent's final output.

Code

Note on the after_agent_callback Example:

  • What it Shows: This example demonstrates the after_agent_callback. This callback runs right after the agent's main processing logic has finished and produced its result, but before that result is finalized and returned.
  • How it Works: The callback function (modify_output_after_agent) checks a flag (add_concluding_note) in the session's state.
    • If the flag is True, the callback returns a new types.Content object. This tells the ADK framework to replace the agent's original output with the content returned by the callback.
    • If the flag is False (or not set), the callback returns None. This tells the ADK framework to use the original output generated by the agent.
  • Expected Outcome: You'll see two scenarios:
    1. In the session without the add_concluding_note: True state, the callback allows the agent's original output ("Processing complete!") to be used.
    2. In the session with that state flag, the callback intercepts the agent's original output and replaces it with its own message ("Concluding note added...").
  • Understanding Callbacks: This highlights how after_ callbacks allow post-processing or modification. You can inspect the result of a step (the agent's run) and decide whether to let it pass through, change it, or completely replace it based on your logic.

LLM Interaction Callbacks

These callbacks are specific to LlmAgent and provide hooks around the interaction with the Large Language Model.

Before Model Callback

When: Called just before the generate_content_async (or equivalent) request is sent to the LLM within an LlmAgent's flow.

Purpose: Allows inspection and modification of the request going to the LLM. Use cases include adding dynamic instructions, injecting few-shot examples based on state, modifying model config, implementing guardrails (like profanity filters), or implementing request-level caching.

Return Value Effect:
If the callback returns None, the LLM continues its normal workflow. If the callback returns an LlmResponse object, then the call to the LLM is skipped. The returned LlmResponse is used directly as if it came from the model. This is powerful for implementing guardrails or caching.

Code

After Model Callback

When: Called just after a response (LlmResponse) is received from the LLM, before it's processed further by the invoking agent.

Purpose: Allows inspection or modification of the raw LLM response. Use cases include

  • logging model outputs,
  • reformatting responses,
  • censoring sensitive information generated by the model,
  • parsing structured data from the LLM response and storing it in callback_context.state
  • or handling specific error codes.
Code

Tool Execution Callbacks

These callbacks are also specific to LlmAgent and trigger around the execution of tools (including FunctionTool, AgentTool, etc.) that the LLM might request.

Before Tool Callback

When: Called just before a specific tool's run_async method is invoked, after the LLM has generated a function call for it.

Purpose: Allows inspection and modification of tool arguments, performing authorization checks before execution, logging tool usage attempts, or implementing tool-level caching.

Return Value Effect:

  1. If the callback returns None, the tool's run_async method is executed with the (potentially modified) args.
  2. If a dictionary is returned, the tool's run_async method is skipped. The returned dictionary is used directly as the result of the tool call. This is useful for caching or overriding tool behavior.
Code

After Tool Callback

When: Called just after the tool's run_async method completes successfully.

Purpose: Allows inspection and modification of the tool's result before it's sent back to the LLM (potentially after summarization). Useful for logging tool results, post-processing or formatting results, or saving specific parts of the result to the session state.

Return Value Effect:

  1. If the callback returns None, the original tool_response is used.
  2. If a new dictionary is returned, it replaces the original tool_response. This allows modifying or filtering the result seen by the LLM.
Code