* docs: Add Go language quickstart * updates based on review comments * fix tab stops * update based on review comments * sync with main * update to tested version * Added google_search snippet * Fix: Address Go style guide issues in google_search.go * Migrated to new API * Fixed tool info in md file * Added partial check * Added function-tools sample * Migrated to new API * Added partial check * Ran linter * feat: add go fmt check * Run go fmt only on changed files * Added google_search snippet * Fix: Address Go style guide issues in google_search.go * Migrated to new API * Added partial check * Added function-tools sample * Migrated to new API * Added partial check * Ran linter * feat: add go fmt check * Run go fmt only on changed files * Feat: Add Golang example for LLM agents * Added schema agent * Added session support * Migrated to new API * Added back OutputKey * Added missing snippets * Moved snipped to its own package * Minor cleanup * Reverted llm-agents.md * Added back correct changes to llm-agents.md * Updated to newest API * Ran linter * WIP * WIP: Added the rest of the agents * Added sequential agent * Migrated agents to new API * Fixed snippet tags * Updated parallel and sequential with OutputKey * Updated loop agent * Cleanup * Fixed and ran linter * Removed comment * Ran linter * Added custom agent snippets * Migrated to new API * Fixed incorrect info about channels since run returns an Iterator, not Channel * Cleanup and renaming * Ran linter * Fixed md * Added multi-agent docs * Updated to use AgentTool * Split snippets * Added missing file * Ran linter and fixed API * Added Models snippets * Migrated to new API * Embedded imports * Ran linter * Added long running tool * Ran linter and fixed API * Switched to two-turn style * Ran linter * Added callback snippets * Added back imports * Added types of callbacks snippets * feat(go): align callback snippets with other languages * Ran linter and updated API * Added tool callbacks * Added artifact snippets * Use story.pdf instead of random bytes * Fixed issue with artifact loading * Cleanup unneeded fixes * Added back inadvertently removed GCS section * Addressed PR comments * Ran linter * feat: Added context snippets * Fixed callback signature * Fixed additional callbacks * Added remaining snippets * Added conceptual runner example * Removed duplicate code * Clean up tags and imports * Updated API * Twaked text * Ran linter * Fixed broken API issues * Updated to latest Go ADK API * Added func param info * Interleaved Py and Go * Revert mistakes * Removed extra newline * Added example cloud run code and update md with Go (#41) * Added example cloud run code and update md with Go * Added a2a_agent_url and fixed future tense * Moved Go before Java --------- Co-authored-by: ivanmkc <ivanmkc@google.com> * adding go snippets to runconfig docs * realigning runconfig go examples with current state of adk-go. * adding language support tags to individual runtime config fields * removing unsupported supportcfc go examples * removing unsupported streamingmode.bidi go snippets * Added AgentTool examples (#31) * Added AgentTool example * Ran formatter --------- Co-authored-by: ivanmkc <ivanmkc@google.com> * adding initial go sessions.sessions snippets * updating go session docs + session examples * update go session snippets * updating DatabaseSessionService language support tag * cleaning up go vertex ai comments * removing go.mod for session_management_example * docs: add language support tags for Go * initial go runtime sample updates * fixing runtime go snippet formatting * formatting updates to runtime go snippets * updating runtime go examples to streamline to newer go features * adding go snippets for events * updating go snippets for events * adding artifactdelta snippet for go * minor java fixes, cleaning up go event.content * Custom tools: Merging again (#44) * Added missing custom-tools snippets * Split user_preference runner code * Split more files * Tweaks * Split session into 1 and 2 and added artifact saving * Fixed conflict --------- Co-authored-by: ivanmkc <ivanmkc@google.com> * Fixed tab issue with cloud-run md (#45) Co-authored-by: ivanmkc <ivanmkc@google.com> * adding initial go snippets for memory services * updating go memory sample, adding python formatting in docs to clarify current support. * removing go replace for memory example * removing go.sum from memory_example * fixing go formatting for memory example * fixing go memory snippets to streamline examples in docs * removing unnecessary go.mod for memory_example.go and snippet cleanup * adding go session state snippets." * adding additional go state examples for state injection * fixing go formatting * fixing language ordering on session/state.md; removing unnecessary go.mod files * reworking error functions in go session state samples * fixing go formatting on session state samples * initial go snippets for safety tools * fixing go snippet formatting in safety/index.md * temp storing safety example * cleaning up go snippets in safety docs; deferring safety go full example * cleaning up go safety snippets * Added link to Go API docs (#47) Co-authored-by: ivanmkc <ivanmkc@google.com> * Added a2a_basic sample (#46) * Added a2a_basic sample * Removed dummy LLMs * Added md Fix inaccuracies in md Ran formatter * Cleaned up index --------- Co-authored-by: ivanmkc <ivanmkc@google.com> * Reverted to proper ToC and added missing links (#48) Co-authored-by: ivanmkc <ivanmkc@google.com> * Added missing get-started/go.md (#50) Co-authored-by: ivanmkc <ivanmkc@google.com> * Added missing JSON tags for Go structs (#51) * Added json tags * Added jsonschema and json tags --------- Co-authored-by: ivanmkc <ivanmkc@google.com> * Renamed Golang to Go (#52) Co-authored-by: ivanmkc <ivanmkc@google.com> --------- Co-authored-by: Joe Fernandez <joefernandez@google.com> Co-authored-by: ivanmkc <ivanmkc@google.com> Co-authored-by: Toni Klopfenstein <tklopfenstein@google.com>
8.3 KiB
Callbacks: Observe, Customize, and Control Agent Behavior
Callbacks are a cornerstone feature of ADK, providing a powerful mechanism to hook into an agent's execution process. They allow you to observe, customize, and even control the agent's behavior at specific, predefined points without modifying the core ADK framework code.
What are they? In essence, callbacks are standard functions that you define. You then associate these functions with an agent when you create it. The ADK framework automatically calls your functions at key stages, letting you observe or intervene. Think of it like checkpoints during the agent's process:
- Before the agent starts its main work on a request, and after it finishes: When you ask an agent to do something (e.g., answer a question), it runs its internal logic to figure out the response.
- The
Before Agentcallback executes right before this main work begins for that specific request. - The
After Agentcallback executes right after the agent has finished all its steps for that request and has prepared the final result, but just before the result is returned. - This "main work" encompasses the agent's entire process for handling that single request. This might involve deciding to call an LLM, actually calling the LLM, deciding to use a tool, using the tool, processing the results, and finally putting together the answer. These callbacks essentially wrap the whole sequence from receiving the input to producing the final output for that one interaction.
- The
- Before sending a request to, or after receiving a response from, the Large Language Model (LLM): These callbacks (
Before Model,After Model) allow you to inspect or modify the data going to and coming from the LLM specifically. - Before executing a tool (like a Python function or another agent) or after it finishes: Similarly,
Before ToolandAfter Toolcallbacks give you control points specifically around the execution of tools invoked by the agent.
Why use them? Callbacks unlock significant flexibility and enable advanced agent capabilities:
- Observe & Debug: Log detailed information at critical steps for monitoring and troubleshooting.
- Customize & Control: Modify data flowing through the agent (like LLM requests or tool results) or even bypass certain steps entirely based on your logic.
- Implement Guardrails: Enforce safety rules, validate inputs/outputs, or prevent disallowed operations.
- Manage State: Read or dynamically update the agent's session state during execution.
- Integrate & Enhance: Trigger external actions (API calls, notifications) or add features like caching.
!!! tip When implementing security guardrails and policies, use ADK Plugins for better modularity and flexibility than Callbacks. For more details, see Callbacks and Plugins for Security Guardrails.
How are they added:
??? "Code" === "Python"
```python
--8<-- "examples/python/snippets/callbacks/callback_basic.py:callback_basic"
```
=== "Java"
```java
--8<-- "examples/java/snippets/src/main/java/callbacks/AgentWithBeforeModelCallback.java:init"
```
=== "Go"
```go
--8<-- "examples/go/snippets/callbacks/main.go:imports"
--8<-- "examples/go/snippets/callbacks/main.go:callback_basic"
```
The Callback Mechanism: Interception and Control
When the ADK framework encounters a point where a callback can run (e.g., just before calling the LLM), it checks if you provided a corresponding callback function for that agent. If you did, the framework executes your function.
Context is Key: Your callback function isn't called in isolation. The framework provides special context objects (CallbackContext or ToolContext) as arguments. These objects contain vital information about the current state of the agent's execution, including the invocation details, session state, and potentially references to services like artifacts or memory. You use these context objects to understand the situation and interact with the framework. (See the dedicated "Context Objects" section for full details).
Controlling the Flow (The Core Mechanism): The most powerful aspect of callbacks lies in how their return value influences the agent's subsequent actions. This is how you intercept and control the execution flow:
-
return None(Allow Default Behavior):- The specific return type can vary depending on the language. In Java, the equivalent return type is
Optional.empty(). Refer to the API documentation for language specific guidance. - This is the standard way to signal that your callback has finished its work (e.g., logging, inspection, minor modifications to mutable input arguments like
llm_request) and that the ADK agent should proceed with its normal operation. - For
before_*callbacks (before_agent,before_model,before_tool), returningNonemeans the next step in the sequence (running the agent logic, calling the LLM, executing the tool) will occur. - For
after_*callbacks (after_agent,after_model,after_tool), returningNonemeans the result just produced by the preceding step (the agent's output, the LLM's response, the tool's result) will be used as is.
- The specific return type can vary depending on the language. In Java, the equivalent return type is
-
return <Specific Object>(Override Default Behavior):- Returning a specific type of object (instead of
None) is how you override the ADK agent's default behavior. The framework will use the object you return and skip the step that would normally follow or replace the result that was just generated. before_agent_callback→types.Content: Skips the agent's main execution logic (_run_async_impl/_run_live_impl). The returnedContentobject is immediately treated as the agent's final output for this turn. Useful for handling simple requests directly or enforcing access control.before_model_callback→LlmResponse: Skips the call to the external Large Language Model. The returnedLlmResponseobject is processed as if it were the actual response from the LLM. Ideal for implementing input guardrails, prompt validation, or serving cached responses.before_tool_callback→dictorMap: Skips the execution of the actual tool function (or sub-agent). The returneddictis used as the result of the tool call, which is then typically passed back to the LLM. Perfect for validating tool arguments, applying policy restrictions, or returning mocked/cached tool results.after_agent_callback→types.Content: Replaces theContentthat the agent's run logic just produced.after_model_callback→LlmResponse: Replaces theLlmResponsereceived from the LLM. Useful for sanitizing outputs, adding standard disclaimers, or modifying the LLM's response structure.after_tool_callback→dictorMap: Replaces thedictresult returned by the tool. Allows for post-processing or standardization of tool outputs before they are sent back to the LLM.
- Returning a specific type of object (instead of
Conceptual Code Example (Guardrail):
This example demonstrates the common pattern for a guardrail using before_model_callback.
??? "Code" === "Python"
```python
--8<-- "examples/python/snippets/callbacks/before_model_callback.py"
```
=== "Java"
```java
--8<-- "examples/java/snippets/src/main/java/callbacks/BeforeModelGuardrailExample.java:init"
```
=== "Go"
```go
--8<-- "examples/go/snippets/callbacks/main.go:imports"
--8<-- "examples/go/snippets/callbacks/main.go:guardrail_init"
```
By understanding this mechanism of returning None versus returning specific objects, you can precisely control the agent's execution path, making callbacks an essential tool for building sophisticated and reliable agents with ADK.
